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(i::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 EmptyInterceptorGetter(Local<String> name,
2025 const v8::PropertyCallbackInfo<v8::Value>& info) {
2028 void EmptyInterceptorSetter(Local<String> name,
2030 const v8::PropertyCallbackInfo<v8::Value>& info) {
2033 void InterceptorGetter(Local<String> name,
2034 const v8::PropertyCallbackInfo<v8::Value>& info) {
2035 // Intercept names that start with 'interceptor_'.
2036 String::Utf8Value utf8(name);
2037 char* name_str = *utf8;
2038 char prefix[] = "interceptor_";
2040 for (i = 0; name_str[i] && prefix[i]; ++i) {
2041 if (name_str[i] != prefix[i]) return;
2043 Handle<Object> self = Handle<Object>::Cast(info.This());
2044 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2047 void InterceptorSetter(Local<String> name,
2049 const v8::PropertyCallbackInfo<v8::Value>& info) {
2050 // Intercept accesses that set certain integer values, for which the name does
2051 // not start with 'accessor_'.
2052 String::Utf8Value utf8(name);
2053 char* name_str = *utf8;
2054 char prefix[] = "accessor_";
2056 for (i = 0; name_str[i] && prefix[i]; ++i) {
2057 if (name_str[i] != prefix[i]) break;
2059 if (!prefix[i]) return;
2061 if (value->IsInt32() && value->Int32Value() < 10000) {
2062 Handle<Object> self = Handle<Object>::Cast(info.This());
2063 self->SetHiddenValue(name, value);
2064 info.GetReturnValue().Set(value);
2068 void AddAccessor(Handle<FunctionTemplate> templ,
2069 Handle<String> name,
2070 v8::AccessorGetterCallback getter,
2071 v8::AccessorSetterCallback setter) {
2072 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2075 void AddInterceptor(Handle<FunctionTemplate> templ,
2076 v8::NamedPropertyGetterCallback getter,
2077 v8::NamedPropertySetterCallback setter) {
2078 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2082 void AddAccessor(Handle<FunctionTemplate> templ,
2084 v8::AccessorNameGetterCallback getter,
2085 v8::AccessorNameSetterCallback setter) {
2086 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2090 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2091 v8::HandleScope scope(CcTest::isolate());
2092 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2093 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2094 child->Inherit(parent);
2095 AddAccessor(parent, v8_str("age"),
2096 SimpleAccessorGetter, SimpleAccessorSetter);
2097 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2099 env->Global()->Set(v8_str("Child"), child->GetFunction());
2100 CompileRun("var child = new Child;"
2102 ExpectBoolean("child.hasOwnProperty('age')", false);
2103 ExpectInt32("child.age", 10);
2104 ExpectInt32("child.accessor_age", 10);
2108 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2109 v8::Isolate* isolate = CcTest::isolate();
2110 v8::HandleScope scope(isolate);
2112 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2113 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2114 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2115 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2116 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2117 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2118 // But we should still have an ExecutableAccessorInfo.
2119 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2120 i::LookupResult lookup(i_isolate);
2121 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2122 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2123 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2124 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2128 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2129 v8::HandleScope scope(CcTest::isolate());
2130 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2131 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2133 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2134 CompileRun("var o1 = new Constructor;"
2135 "o1.a = 1;" // Ensure a and x share the descriptor array.
2136 "Object.defineProperty(o1, 'x', {value: 10});");
2137 CompileRun("var o2 = new Constructor;"
2139 "Object.defineProperty(o2, 'x', {value: 10});");
2143 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2144 v8::Isolate* isolate = CcTest::isolate();
2145 v8::HandleScope scope(isolate);
2146 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2147 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2148 child->Inherit(parent);
2149 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2151 env->Global()->Set(v8_str("Child"), child->GetFunction());
2152 CompileRun("var child = new Child;"
2153 "var parent = child.__proto__;"
2154 "Object.defineProperty(parent, 'age', "
2155 " {get: function(){ return this.accessor_age; }, "
2156 " set: function(v){ this.accessor_age = v; }, "
2157 " enumerable: true, configurable: true});"
2159 ExpectBoolean("child.hasOwnProperty('age')", false);
2160 ExpectInt32("child.age", 10);
2161 ExpectInt32("child.accessor_age", 10);
2165 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2166 v8::Isolate* isolate = CcTest::isolate();
2167 v8::HandleScope scope(isolate);
2168 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2169 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2170 child->Inherit(parent);
2171 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2173 env->Global()->Set(v8_str("Child"), child->GetFunction());
2174 CompileRun("var child = new Child;"
2175 "var parent = child.__proto__;"
2176 "parent.name = 'Alice';");
2177 ExpectBoolean("child.hasOwnProperty('name')", false);
2178 ExpectString("child.name", "Alice");
2179 CompileRun("child.name = 'Bob';");
2180 ExpectString("child.name", "Bob");
2181 ExpectBoolean("child.hasOwnProperty('name')", true);
2182 ExpectString("parent.name", "Alice");
2186 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2187 v8::HandleScope scope(CcTest::isolate());
2188 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2189 AddAccessor(templ, v8_str("age"),
2190 SimpleAccessorGetter, SimpleAccessorSetter);
2191 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2193 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2194 CompileRun("var obj = new Obj;"
2195 "function setAge(i){ obj.age = i; };"
2196 "for(var i = 0; i <= 10000; i++) setAge(i);");
2197 // All i < 10000 go to the interceptor.
2198 ExpectInt32("obj.interceptor_age", 9999);
2199 // The last i goes to the accessor.
2200 ExpectInt32("obj.accessor_age", 10000);
2204 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2205 v8::HandleScope scope(CcTest::isolate());
2206 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2207 AddAccessor(templ, v8_str("age"),
2208 SimpleAccessorGetter, SimpleAccessorSetter);
2209 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2211 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2212 CompileRun("var obj = new Obj;"
2213 "function setAge(i){ obj.age = i; };"
2214 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2215 // All i >= 10000 go to the accessor.
2216 ExpectInt32("obj.accessor_age", 10000);
2217 // The last i goes to the interceptor.
2218 ExpectInt32("obj.interceptor_age", 9999);
2222 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2223 v8::HandleScope scope(CcTest::isolate());
2224 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2225 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2226 child->Inherit(parent);
2227 AddAccessor(parent, v8_str("age"),
2228 SimpleAccessorGetter, SimpleAccessorSetter);
2229 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2231 env->Global()->Set(v8_str("Child"), child->GetFunction());
2232 CompileRun("var child = new Child;"
2233 "function setAge(i){ child.age = i; };"
2234 "for(var i = 0; i <= 10000; i++) setAge(i);");
2235 // All i < 10000 go to the interceptor.
2236 ExpectInt32("child.interceptor_age", 9999);
2237 // The last i goes to the accessor.
2238 ExpectInt32("child.accessor_age", 10000);
2242 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2243 v8::HandleScope scope(CcTest::isolate());
2244 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2245 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2246 child->Inherit(parent);
2247 AddAccessor(parent, v8_str("age"),
2248 SimpleAccessorGetter, SimpleAccessorSetter);
2249 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2251 env->Global()->Set(v8_str("Child"), child->GetFunction());
2252 CompileRun("var child = new Child;"
2253 "function setAge(i){ child.age = i; };"
2254 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2255 // All i >= 10000 go to the accessor.
2256 ExpectInt32("child.accessor_age", 10000);
2257 // The last i goes to the interceptor.
2258 ExpectInt32("child.interceptor_age", 9999);
2262 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2263 v8::HandleScope scope(CcTest::isolate());
2264 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2265 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2267 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2268 CompileRun("var obj = new Obj;"
2269 "function setter(i) { this.accessor_age = i; };"
2270 "function getter() { return this.accessor_age; };"
2271 "function setAge(i) { obj.age = i; };"
2272 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2273 "for(var i = 0; i <= 10000; i++) setAge(i);");
2274 // All i < 10000 go to the interceptor.
2275 ExpectInt32("obj.interceptor_age", 9999);
2276 // The last i goes to the JavaScript accessor.
2277 ExpectInt32("obj.accessor_age", 10000);
2278 // The installed JavaScript getter is still intact.
2279 // This last part is a regression test for issue 1651 and relies on the fact
2280 // that both interceptor and accessor are being installed on the same object.
2281 ExpectInt32("obj.age", 10000);
2282 ExpectBoolean("obj.hasOwnProperty('age')", true);
2283 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2287 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2288 v8::HandleScope scope(CcTest::isolate());
2289 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2290 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2292 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2293 CompileRun("var obj = new Obj;"
2294 "function setter(i) { this.accessor_age = i; };"
2295 "function getter() { return this.accessor_age; };"
2296 "function setAge(i) { obj.age = i; };"
2297 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2298 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2299 // All i >= 10000 go to the accessor.
2300 ExpectInt32("obj.accessor_age", 10000);
2301 // The last i goes to the interceptor.
2302 ExpectInt32("obj.interceptor_age", 9999);
2303 // The installed JavaScript getter is still intact.
2304 // This last part is a regression test for issue 1651 and relies on the fact
2305 // that both interceptor and accessor are being installed on the same object.
2306 ExpectInt32("obj.age", 10000);
2307 ExpectBoolean("obj.hasOwnProperty('age')", true);
2308 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2312 THREADED_TEST(SwitchFromInterceptorToProperty) {
2313 v8::HandleScope scope(CcTest::isolate());
2314 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2315 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2316 child->Inherit(parent);
2317 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2319 env->Global()->Set(v8_str("Child"), child->GetFunction());
2320 CompileRun("var child = new Child;"
2321 "function setAge(i){ child.age = i; };"
2322 "for(var i = 0; i <= 10000; i++) setAge(i);");
2323 // All i < 10000 go to the interceptor.
2324 ExpectInt32("child.interceptor_age", 9999);
2325 // The last i goes to child's own property.
2326 ExpectInt32("child.age", 10000);
2330 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2331 v8::HandleScope scope(CcTest::isolate());
2332 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2333 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2334 child->Inherit(parent);
2335 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2337 env->Global()->Set(v8_str("Child"), child->GetFunction());
2338 CompileRun("var child = new Child;"
2339 "function setAge(i){ child.age = i; };"
2340 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2341 // All i >= 10000 go to child's own property.
2342 ExpectInt32("child.age", 10000);
2343 // The last i goes to the interceptor.
2344 ExpectInt32("child.interceptor_age", 9999);
2348 THREADED_TEST(NamedPropertyHandlerGetter) {
2349 echo_named_call_count = 0;
2350 v8::HandleScope scope(CcTest::isolate());
2351 v8::Handle<v8::FunctionTemplate> templ =
2352 v8::FunctionTemplate::New(CcTest::isolate());
2353 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2357 env->Global()->Set(v8_str("obj"),
2358 templ->GetFunction()->NewInstance());
2359 CHECK_EQ(echo_named_call_count, 0);
2360 v8_compile("obj.x")->Run();
2361 CHECK_EQ(echo_named_call_count, 1);
2362 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2363 v8::Handle<Value> str = CompileRun(code);
2364 String::Utf8Value value(str);
2365 CHECK_EQ(*value, "oddlepoddle");
2366 // Check default behavior
2367 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2368 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2369 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2373 int echo_indexed_call_count = 0;
2376 static void EchoIndexedProperty(
2378 const v8::PropertyCallbackInfo<v8::Value>& info) {
2379 ApiTestFuzzer::Fuzz();
2380 CHECK_EQ(v8_num(637), info.Data());
2381 echo_indexed_call_count++;
2382 info.GetReturnValue().Set(v8_num(index));
2386 THREADED_TEST(IndexedPropertyHandlerGetter) {
2387 v8::Isolate* isolate = CcTest::isolate();
2388 v8::HandleScope scope(isolate);
2389 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2390 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2394 env->Global()->Set(v8_str("obj"),
2395 templ->GetFunction()->NewInstance());
2396 Local<Script> script = v8_compile("obj[900]");
2397 CHECK_EQ(script->Run()->Int32Value(), 900);
2401 v8::Handle<v8::Object> bottom;
2403 static void CheckThisIndexedPropertyHandler(
2405 const v8::PropertyCallbackInfo<v8::Value>& info) {
2406 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2407 ApiTestFuzzer::Fuzz();
2408 CHECK(info.This()->Equals(bottom));
2411 static void CheckThisNamedPropertyHandler(
2413 const v8::PropertyCallbackInfo<v8::Value>& info) {
2414 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2415 ApiTestFuzzer::Fuzz();
2416 CHECK(info.This()->Equals(bottom));
2419 void CheckThisIndexedPropertySetter(
2422 const v8::PropertyCallbackInfo<v8::Value>& info) {
2423 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2424 ApiTestFuzzer::Fuzz();
2425 CHECK(info.This()->Equals(bottom));
2429 void CheckThisNamedPropertySetter(
2430 Local<String> property,
2432 const v8::PropertyCallbackInfo<v8::Value>& info) {
2433 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2434 ApiTestFuzzer::Fuzz();
2435 CHECK(info.This()->Equals(bottom));
2438 void CheckThisIndexedPropertyQuery(
2440 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2441 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2442 ApiTestFuzzer::Fuzz();
2443 CHECK(info.This()->Equals(bottom));
2447 void CheckThisNamedPropertyQuery(
2448 Local<String> property,
2449 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2450 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2451 ApiTestFuzzer::Fuzz();
2452 CHECK(info.This()->Equals(bottom));
2456 void CheckThisIndexedPropertyDeleter(
2458 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2459 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2460 ApiTestFuzzer::Fuzz();
2461 CHECK(info.This()->Equals(bottom));
2465 void CheckThisNamedPropertyDeleter(
2466 Local<String> property,
2467 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2468 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2469 ApiTestFuzzer::Fuzz();
2470 CHECK(info.This()->Equals(bottom));
2474 void CheckThisIndexedPropertyEnumerator(
2475 const v8::PropertyCallbackInfo<v8::Array>& info) {
2476 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2477 ApiTestFuzzer::Fuzz();
2478 CHECK(info.This()->Equals(bottom));
2482 void CheckThisNamedPropertyEnumerator(
2483 const v8::PropertyCallbackInfo<v8::Array>& info) {
2484 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2485 ApiTestFuzzer::Fuzz();
2486 CHECK(info.This()->Equals(bottom));
2490 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2492 v8::Isolate* isolate = env->GetIsolate();
2493 v8::HandleScope scope(isolate);
2495 // Set up a prototype chain with three interceptors.
2496 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2497 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2498 CheckThisIndexedPropertyHandler,
2499 CheckThisIndexedPropertySetter,
2500 CheckThisIndexedPropertyQuery,
2501 CheckThisIndexedPropertyDeleter,
2502 CheckThisIndexedPropertyEnumerator);
2504 templ->InstanceTemplate()->SetNamedPropertyHandler(
2505 CheckThisNamedPropertyHandler,
2506 CheckThisNamedPropertySetter,
2507 CheckThisNamedPropertyQuery,
2508 CheckThisNamedPropertyDeleter,
2509 CheckThisNamedPropertyEnumerator);
2511 bottom = templ->GetFunction()->NewInstance();
2512 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2513 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2515 bottom->SetPrototype(middle);
2516 middle->SetPrototype(top);
2517 env->Global()->Set(v8_str("obj"), bottom);
2519 // Indexed and named get.
2520 CompileRun("obj[0]");
2521 CompileRun("obj.x");
2523 // Indexed and named set.
2524 CompileRun("obj[1] = 42");
2525 CompileRun("obj.y = 42");
2527 // Indexed and named query.
2528 CompileRun("0 in obj");
2529 CompileRun("'x' in obj");
2531 // Indexed and named deleter.
2532 CompileRun("delete obj[0]");
2533 CompileRun("delete obj.x");
2536 CompileRun("for (var p in obj) ;");
2540 static void PrePropertyHandlerGet(
2542 const v8::PropertyCallbackInfo<v8::Value>& info) {
2543 ApiTestFuzzer::Fuzz();
2544 if (v8_str("pre")->Equals(key)) {
2545 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2550 static void PrePropertyHandlerQuery(
2552 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2553 if (v8_str("pre")->Equals(key)) {
2554 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2559 THREADED_TEST(PrePropertyHandler) {
2560 v8::Isolate* isolate = CcTest::isolate();
2561 v8::HandleScope scope(isolate);
2562 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2563 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2565 PrePropertyHandlerQuery);
2566 LocalContext env(NULL, desc->InstanceTemplate());
2567 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2568 v8::Handle<Value> result_pre = CompileRun("pre");
2569 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2570 v8::Handle<Value> result_on = CompileRun("on");
2571 CHECK_EQ(v8_str("Object: on"), result_on);
2572 v8::Handle<Value> result_post = CompileRun("post");
2573 CHECK(result_post.IsEmpty());
2577 THREADED_TEST(UndefinedIsNotEnumerable) {
2579 v8::HandleScope scope(env->GetIsolate());
2580 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2581 CHECK(result->IsFalse());
2585 v8::Handle<Script> call_recursively_script;
2586 static const int kTargetRecursionDepth = 200; // near maximum
2589 static void CallScriptRecursivelyCall(
2590 const v8::FunctionCallbackInfo<v8::Value>& args) {
2591 ApiTestFuzzer::Fuzz();
2592 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2593 if (depth == kTargetRecursionDepth) return;
2594 args.This()->Set(v8_str("depth"),
2595 v8::Integer::New(args.GetIsolate(), depth + 1));
2596 args.GetReturnValue().Set(call_recursively_script->Run());
2600 static void CallFunctionRecursivelyCall(
2601 const v8::FunctionCallbackInfo<v8::Value>& args) {
2602 ApiTestFuzzer::Fuzz();
2603 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2604 if (depth == kTargetRecursionDepth) {
2605 printf("[depth = %d]\n", depth);
2608 args.This()->Set(v8_str("depth"),
2609 v8::Integer::New(args.GetIsolate(), depth + 1));
2610 v8::Handle<Value> function =
2611 args.This()->Get(v8_str("callFunctionRecursively"));
2612 args.GetReturnValue().Set(
2613 function.As<Function>()->Call(args.This(), 0, NULL));
2617 THREADED_TEST(DeepCrossLanguageRecursion) {
2618 v8::Isolate* isolate = CcTest::isolate();
2619 v8::HandleScope scope(isolate);
2620 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2621 global->Set(v8_str("callScriptRecursively"),
2622 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2623 global->Set(v8_str("callFunctionRecursively"),
2624 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2625 LocalContext env(NULL, global);
2627 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2628 call_recursively_script = v8_compile("callScriptRecursively()");
2629 call_recursively_script->Run();
2630 call_recursively_script = v8::Handle<Script>();
2632 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2633 CompileRun("callFunctionRecursively()");
2637 static void ThrowingPropertyHandlerGet(
2639 const v8::PropertyCallbackInfo<v8::Value>& info) {
2640 ApiTestFuzzer::Fuzz();
2641 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2645 static void ThrowingPropertyHandlerSet(
2648 const v8::PropertyCallbackInfo<v8::Value>& info) {
2649 info.GetIsolate()->ThrowException(key);
2650 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2654 THREADED_TEST(CallbackExceptionRegression) {
2655 v8::Isolate* isolate = CcTest::isolate();
2656 v8::HandleScope scope(isolate);
2657 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2658 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2659 ThrowingPropertyHandlerSet);
2661 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2662 v8::Handle<Value> otto = CompileRun(
2663 "try { with (obj) { otto; } } catch (e) { e; }");
2664 CHECK_EQ(v8_str("otto"), otto);
2665 v8::Handle<Value> netto = CompileRun(
2666 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2667 CHECK_EQ(v8_str("netto"), netto);
2671 THREADED_TEST(FunctionPrototype) {
2672 v8::Isolate* isolate = CcTest::isolate();
2673 v8::HandleScope scope(isolate);
2674 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2675 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2677 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2678 Local<Script> script = v8_compile("Foo.prototype.plak");
2679 CHECK_EQ(script->Run()->Int32Value(), 321);
2683 THREADED_TEST(InternalFields) {
2685 v8::Isolate* isolate = env->GetIsolate();
2686 v8::HandleScope scope(isolate);
2688 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2689 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2690 instance_templ->SetInternalFieldCount(1);
2691 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2692 CHECK_EQ(1, obj->InternalFieldCount());
2693 CHECK(obj->GetInternalField(0)->IsUndefined());
2694 obj->SetInternalField(0, v8_num(17));
2695 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2699 THREADED_TEST(GlobalObjectInternalFields) {
2700 v8::Isolate* isolate = CcTest::isolate();
2701 v8::HandleScope scope(isolate);
2702 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2703 global_template->SetInternalFieldCount(1);
2704 LocalContext env(NULL, global_template);
2705 v8::Handle<v8::Object> global_proxy = env->Global();
2706 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2707 CHECK_EQ(1, global->InternalFieldCount());
2708 CHECK(global->GetInternalField(0)->IsUndefined());
2709 global->SetInternalField(0, v8_num(17));
2710 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2714 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2716 v8::HandleScope scope(CcTest::isolate());
2718 v8::Local<v8::Object> global = env->Global();
2719 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2720 CHECK(global->HasRealIndexedProperty(0));
2724 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2726 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2727 obj->SetAlignedPointerInInternalField(0, value);
2728 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2729 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2733 THREADED_TEST(InternalFieldsAlignedPointers) {
2735 v8::Isolate* isolate = env->GetIsolate();
2736 v8::HandleScope scope(isolate);
2738 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2739 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2740 instance_templ->SetInternalFieldCount(1);
2741 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2742 CHECK_EQ(1, obj->InternalFieldCount());
2744 CheckAlignedPointerInInternalField(obj, NULL);
2746 int* heap_allocated = new int[100];
2747 CheckAlignedPointerInInternalField(obj, heap_allocated);
2748 delete[] heap_allocated;
2750 int stack_allocated[100];
2751 CheckAlignedPointerInInternalField(obj, stack_allocated);
2753 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2754 CheckAlignedPointerInInternalField(obj, huge);
2756 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2757 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2758 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2762 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2765 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2766 (*env)->SetAlignedPointerInEmbedderData(index, value);
2767 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2768 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2772 static void* AlignedTestPointer(int i) {
2773 return reinterpret_cast<void*>(i * 1234);
2777 THREADED_TEST(EmbedderDataAlignedPointers) {
2779 v8::HandleScope scope(env->GetIsolate());
2781 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2783 int* heap_allocated = new int[100];
2784 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2785 delete[] heap_allocated;
2787 int stack_allocated[100];
2788 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2790 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2791 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2793 // Test growing of the embedder data's backing store.
2794 for (int i = 0; i < 100; i++) {
2795 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2797 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2798 for (int i = 0; i < 100; i++) {
2799 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2804 static void CheckEmbedderData(LocalContext* env,
2806 v8::Handle<Value> data) {
2807 (*env)->SetEmbedderData(index, data);
2808 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2812 THREADED_TEST(EmbedderData) {
2814 v8::Isolate* isolate = env->GetIsolate();
2815 v8::HandleScope scope(isolate);
2819 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2820 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2821 "over the lazy dog."));
2822 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2823 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2827 THREADED_TEST(IdentityHash) {
2829 v8::Isolate* isolate = env->GetIsolate();
2830 v8::HandleScope scope(isolate);
2832 // Ensure that the test starts with an fresh heap to test whether the hash
2833 // code is based on the address.
2834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2835 Local<v8::Object> obj = v8::Object::New(isolate);
2836 int hash = obj->GetIdentityHash();
2837 int hash1 = obj->GetIdentityHash();
2838 CHECK_EQ(hash, hash1);
2839 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2840 // Since the identity hash is essentially a random number two consecutive
2841 // objects should not be assigned the same hash code. If the test below fails
2842 // the random number generator should be evaluated.
2843 CHECK_NE(hash, hash2);
2844 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2845 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2846 // Make sure that the identity hash is not based on the initial address of
2847 // the object alone. If the test below fails the random number generator
2848 // should be evaluated.
2849 CHECK_NE(hash, hash3);
2850 int hash4 = obj->GetIdentityHash();
2851 CHECK_EQ(hash, hash4);
2853 // Check identity hashes behaviour in the presence of JS accessors.
2854 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2856 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2857 Local<v8::Object> o1 = v8::Object::New(isolate);
2858 Local<v8::Object> o2 = v8::Object::New(isolate);
2859 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2863 "function cnst() { return 42; };\n"
2864 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2865 Local<v8::Object> o1 = v8::Object::New(isolate);
2866 Local<v8::Object> o2 = v8::Object::New(isolate);
2867 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2872 THREADED_TEST(GlobalProxyIdentityHash) {
2874 v8::Isolate* isolate = env->GetIsolate();
2875 v8::HandleScope scope(isolate);
2876 Handle<Object> global_proxy = env->Global();
2877 int hash1 = global_proxy->GetIdentityHash();
2878 // Hash should be retained after being detached.
2879 env->DetachGlobal();
2880 int hash2 = global_proxy->GetIdentityHash();
2881 CHECK_EQ(hash1, hash2);
2883 // Re-attach global proxy to a new context, hash should stay the same.
2884 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2885 int hash3 = global_proxy->GetIdentityHash();
2886 CHECK_EQ(hash1, hash3);
2891 THREADED_TEST(SymbolProperties) {
2893 v8::Isolate* isolate = env->GetIsolate();
2894 v8::HandleScope scope(isolate);
2896 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2897 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2898 v8::Local<v8::Symbol> sym2 =
2899 v8::Symbol::New(isolate, v8_str("my-symbol"));
2900 v8::Local<v8::Symbol> sym3 =
2901 v8::Symbol::New(isolate, v8_str("sym3"));
2903 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2905 // Check basic symbol functionality.
2906 CHECK(sym1->IsSymbol());
2907 CHECK(sym2->IsSymbol());
2908 CHECK(!obj->IsSymbol());
2910 CHECK(sym1->Equals(sym1));
2911 CHECK(sym2->Equals(sym2));
2912 CHECK(!sym1->Equals(sym2));
2913 CHECK(!sym2->Equals(sym1));
2914 CHECK(sym1->StrictEquals(sym1));
2915 CHECK(sym2->StrictEquals(sym2));
2916 CHECK(!sym1->StrictEquals(sym2));
2917 CHECK(!sym2->StrictEquals(sym1));
2919 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2921 v8::Local<v8::Value> sym_val = sym2;
2922 CHECK(sym_val->IsSymbol());
2923 CHECK(sym_val->Equals(sym2));
2924 CHECK(sym_val->StrictEquals(sym2));
2925 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2927 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2928 CHECK(sym_obj->IsSymbolObject());
2929 CHECK(!sym2->IsSymbolObject());
2930 CHECK(!obj->IsSymbolObject());
2931 CHECK(!sym_obj->Equals(sym2));
2932 CHECK(!sym_obj->StrictEquals(sym2));
2933 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2934 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2936 // Make sure delete of a non-existent symbol property works.
2937 CHECK(obj->Delete(sym1));
2938 CHECK(!obj->Has(sym1));
2940 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2941 CHECK(obj->Has(sym1));
2942 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2943 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2944 CHECK(obj->Has(sym1));
2945 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2946 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2948 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2949 int num_props = obj->GetPropertyNames()->Length();
2950 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2951 v8::Integer::New(isolate, 20)));
2952 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2953 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2955 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2957 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2958 CHECK(obj->Get(sym3)->IsUndefined());
2959 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2960 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2961 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2962 v8::Integer::New(isolate, 42)));
2964 // Add another property and delete it afterwards to force the object in
2966 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2967 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2968 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2969 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2970 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2972 CHECK(obj->Has(sym1));
2973 CHECK(obj->Has(sym2));
2974 CHECK(obj->Has(sym3));
2975 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2976 CHECK(obj->Delete(sym2));
2977 CHECK(obj->Has(sym1));
2978 CHECK(!obj->Has(sym2));
2979 CHECK(obj->Has(sym3));
2980 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2981 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2982 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2983 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2984 v8::Integer::New(isolate, 42)));
2985 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2987 // Symbol properties are inherited.
2988 v8::Local<v8::Object> child = v8::Object::New(isolate);
2989 child->SetPrototype(obj);
2990 CHECK(child->Has(sym1));
2991 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2992 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2993 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2994 v8::Integer::New(isolate, 42)));
2995 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2999 THREADED_TEST(SymbolTemplateProperties) {
3001 v8::Isolate* isolate = env->GetIsolate();
3002 v8::HandleScope scope(isolate);
3003 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3004 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3005 CHECK(!name.IsEmpty());
3006 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3007 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3008 CHECK(!new_instance.IsEmpty());
3009 CHECK(new_instance->Has(name));
3013 THREADED_TEST(PrivateProperties) {
3015 v8::Isolate* isolate = env->GetIsolate();
3016 v8::HandleScope scope(isolate);
3018 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3019 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3020 v8::Local<v8::Private> priv2 =
3021 v8::Private::New(isolate, v8_str("my-private"));
3023 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3025 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3027 // Make sure delete of a non-existent private symbol property works.
3028 CHECK(obj->DeletePrivate(priv1));
3029 CHECK(!obj->HasPrivate(priv1));
3031 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3032 CHECK(obj->HasPrivate(priv1));
3033 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3034 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3035 CHECK(obj->HasPrivate(priv1));
3036 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3038 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3039 int num_props = obj->GetPropertyNames()->Length();
3040 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3041 v8::Integer::New(isolate, 20)));
3042 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3043 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3045 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3047 // Add another property and delete it afterwards to force the object in
3049 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3050 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3051 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3052 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3053 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3055 CHECK(obj->HasPrivate(priv1));
3056 CHECK(obj->HasPrivate(priv2));
3057 CHECK(obj->DeletePrivate(priv2));
3058 CHECK(obj->HasPrivate(priv1));
3059 CHECK(!obj->HasPrivate(priv2));
3060 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3061 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3063 // Private properties are inherited (for the time being).
3064 v8::Local<v8::Object> child = v8::Object::New(isolate);
3065 child->SetPrototype(obj);
3066 CHECK(child->HasPrivate(priv1));
3067 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3068 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3072 THREADED_TEST(GlobalSymbols) {
3074 v8::Isolate* isolate = env->GetIsolate();
3075 v8::HandleScope scope(isolate);
3077 v8::Local<String> name = v8_str("my-symbol");
3078 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3079 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3080 CHECK(glob2->SameValue(glob));
3082 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3083 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3084 CHECK(glob_api2->SameValue(glob_api));
3085 CHECK(!glob_api->SameValue(glob));
3087 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3088 CHECK(!sym->SameValue(glob));
3090 CompileRun("var sym2 = Symbol.for('my-symbol')");
3091 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3092 CHECK(sym2->SameValue(glob));
3093 CHECK(!sym2->SameValue(glob_api));
3097 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3100 v8::Isolate* isolate = env->GetIsolate();
3101 v8::HandleScope scope(isolate);
3103 v8::Local<v8::Symbol> symbol = getter(isolate);
3104 std::string script = std::string("var sym = ") + name;
3105 CompileRun(script.c_str());
3106 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3108 CHECK(!value.IsEmpty());
3109 CHECK(!symbol.IsEmpty());
3110 CHECK(value->SameValue(symbol));
3114 THREADED_TEST(WellKnownSymbols) {
3115 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3116 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3120 THREADED_TEST(GlobalPrivates) {
3122 v8::Isolate* isolate = env->GetIsolate();
3123 v8::HandleScope scope(isolate);
3125 v8::Local<String> name = v8_str("my-private");
3126 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3127 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3128 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3130 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3131 CHECK(obj->HasPrivate(glob2));
3133 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3134 CHECK(!obj->HasPrivate(priv));
3136 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3137 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3138 CHECK(!obj->Has(intern));
3142 class ScopedArrayBufferContents {
3144 explicit ScopedArrayBufferContents(
3145 const v8::ArrayBuffer::Contents& contents)
3146 : contents_(contents) {}
3147 ~ScopedArrayBufferContents() { free(contents_.Data()); }
3148 void* Data() const { return contents_.Data(); }
3149 size_t ByteLength() const { return contents_.ByteLength(); }
3151 const v8::ArrayBuffer::Contents contents_;
3154 template <typename T>
3155 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3156 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3157 for (int i = 0; i < value->InternalFieldCount(); i++) {
3158 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3163 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3165 v8::Isolate* isolate = env->GetIsolate();
3166 v8::HandleScope handle_scope(isolate);
3168 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3169 CheckInternalFieldsAreZero(ab);
3170 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3171 CHECK(!ab->IsExternal());
3172 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3174 ScopedArrayBufferContents ab_contents(ab->Externalize());
3175 CHECK(ab->IsExternal());
3177 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3178 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3179 DCHECK(data != NULL);
3180 env->Global()->Set(v8_str("ab"), ab);
3182 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3183 CHECK_EQ(1024, result->Int32Value());
3185 result = CompileRun("var u8 = new Uint8Array(ab);"
3189 CHECK_EQ(1024, result->Int32Value());
3190 CHECK_EQ(0xFF, data[0]);
3191 CHECK_EQ(0xAA, data[1]);
3194 result = CompileRun("u8[0] + u8[1]");
3195 CHECK_EQ(0xDD, result->Int32Value());
3199 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3201 v8::Isolate* isolate = env->GetIsolate();
3202 v8::HandleScope handle_scope(isolate);
3205 v8::Local<v8::Value> result =
3206 CompileRun("var ab1 = new ArrayBuffer(2);"
3207 "var u8_a = new Uint8Array(ab1);"
3209 "u8_a[1] = 0xFF; u8_a.buffer");
3210 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3211 CheckInternalFieldsAreZero(ab1);
3212 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3213 CHECK(!ab1->IsExternal());
3214 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3215 CHECK(ab1->IsExternal());
3217 result = CompileRun("ab1.byteLength");
3218 CHECK_EQ(2, result->Int32Value());
3219 result = CompileRun("u8_a[0]");
3220 CHECK_EQ(0xAA, result->Int32Value());
3221 result = CompileRun("u8_a[1]");
3222 CHECK_EQ(0xFF, result->Int32Value());
3223 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3226 CHECK_EQ(0xBB, result->Int32Value());
3227 result = CompileRun("u8_b[1]");
3228 CHECK_EQ(0xFF, result->Int32Value());
3230 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3231 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3232 CHECK_EQ(0xBB, ab1_data[0]);
3233 CHECK_EQ(0xFF, ab1_data[1]);
3236 result = CompileRun("u8_a[0] + u8_a[1]");
3237 CHECK_EQ(0xDD, result->Int32Value());
3241 THREADED_TEST(ArrayBuffer_External) {
3243 v8::Isolate* isolate = env->GetIsolate();
3244 v8::HandleScope handle_scope(isolate);
3246 i::ScopedVector<uint8_t> my_data(100);
3247 memset(my_data.start(), 0, 100);
3248 Local<v8::ArrayBuffer> ab3 =
3249 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3250 CheckInternalFieldsAreZero(ab3);
3251 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3252 CHECK(ab3->IsExternal());
3254 env->Global()->Set(v8_str("ab3"), ab3);
3256 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3257 CHECK_EQ(100, result->Int32Value());
3259 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3263 CHECK_EQ(100, result->Int32Value());
3264 CHECK_EQ(0xBB, my_data[0]);
3265 CHECK_EQ(0xCC, my_data[1]);
3268 result = CompileRun("u8_b[0] + u8_b[1]");
3269 CHECK_EQ(0xDD, result->Int32Value());
3273 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3274 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3275 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3279 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3280 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3281 CHECK_EQ(0, static_cast<int>(ta->Length()));
3282 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3286 static void CheckIsTypedArrayVarNeutered(const char* name) {
3287 i::ScopedVector<char> source(1024);
3289 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3291 CHECK(CompileRun(source.start())->IsTrue());
3292 v8::Handle<v8::TypedArray> ta =
3293 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3294 CheckIsNeutered(ta);
3298 template <typename TypedArray, int kElementSize>
3299 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3302 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3303 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3304 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3305 CHECK_EQ(length, static_cast<int>(ta->Length()));
3306 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3311 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3313 v8::Isolate* isolate = env->GetIsolate();
3314 v8::HandleScope handle_scope(isolate);
3316 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3318 v8::Handle<v8::Uint8Array> u8a =
3319 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3320 v8::Handle<v8::Uint8ClampedArray> u8c =
3321 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3322 v8::Handle<v8::Int8Array> i8a =
3323 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3325 v8::Handle<v8::Uint16Array> u16a =
3326 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3327 v8::Handle<v8::Int16Array> i16a =
3328 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3330 v8::Handle<v8::Uint32Array> u32a =
3331 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3332 v8::Handle<v8::Int32Array> i32a =
3333 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3335 v8::Handle<v8::Float32Array> f32a =
3336 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3337 v8::Handle<v8::Float64Array> f64a =
3338 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3340 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3341 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3342 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3343 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3345 ScopedArrayBufferContents contents(buffer->Externalize());
3347 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3348 CheckIsNeutered(u8a);
3349 CheckIsNeutered(u8c);
3350 CheckIsNeutered(i8a);
3351 CheckIsNeutered(u16a);
3352 CheckIsNeutered(i16a);
3353 CheckIsNeutered(u32a);
3354 CheckIsNeutered(i32a);
3355 CheckIsNeutered(f32a);
3356 CheckIsNeutered(f64a);
3357 CheckDataViewIsNeutered(dv);
3361 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3363 v8::Isolate* isolate = env->GetIsolate();
3364 v8::HandleScope handle_scope(isolate);
3367 "var ab = new ArrayBuffer(1024);"
3368 "var u8a = new Uint8Array(ab, 1, 1023);"
3369 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3370 "var i8a = new Int8Array(ab, 1, 1023);"
3371 "var u16a = new Uint16Array(ab, 2, 511);"
3372 "var i16a = new Int16Array(ab, 2, 511);"
3373 "var u32a = new Uint32Array(ab, 4, 255);"
3374 "var i32a = new Int32Array(ab, 4, 255);"
3375 "var f32a = new Float32Array(ab, 4, 255);"
3376 "var f64a = new Float64Array(ab, 8, 127);"
3377 "var dv = new DataView(ab, 1, 1023);");
3379 v8::Handle<v8::ArrayBuffer> ab =
3380 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3382 v8::Handle<v8::DataView> dv =
3383 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3385 ScopedArrayBufferContents contents(ab->Externalize());
3387 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3388 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3390 CheckIsTypedArrayVarNeutered("u8a");
3391 CheckIsTypedArrayVarNeutered("u8c");
3392 CheckIsTypedArrayVarNeutered("i8a");
3393 CheckIsTypedArrayVarNeutered("u16a");
3394 CheckIsTypedArrayVarNeutered("i16a");
3395 CheckIsTypedArrayVarNeutered("u32a");
3396 CheckIsTypedArrayVarNeutered("i32a");
3397 CheckIsTypedArrayVarNeutered("f32a");
3398 CheckIsTypedArrayVarNeutered("f64a");
3400 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3401 CheckDataViewIsNeutered(dv);
3406 THREADED_TEST(HiddenProperties) {
3408 v8::Isolate* isolate = env->GetIsolate();
3409 v8::HandleScope scope(isolate);
3411 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3412 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3413 v8::Local<v8::String> empty = v8_str("");
3414 v8::Local<v8::String> prop_name = v8_str("prop_name");
3416 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3418 // Make sure delete of a non-existent hidden value works
3419 CHECK(obj->DeleteHiddenValue(key));
3421 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3422 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3423 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3424 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3426 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3428 // Make sure we do not find the hidden property.
3429 CHECK(!obj->Has(empty));
3430 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3431 CHECK(obj->Get(empty)->IsUndefined());
3432 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3433 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3434 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3435 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3437 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3439 // Add another property and delete it afterwards to force the object in
3441 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3442 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3443 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3444 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3445 CHECK(obj->Delete(prop_name));
3446 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3448 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3450 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3451 CHECK(obj->GetHiddenValue(key).IsEmpty());
3453 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3454 CHECK(obj->DeleteHiddenValue(key));
3455 CHECK(obj->GetHiddenValue(key).IsEmpty());
3459 THREADED_TEST(Regress97784) {
3460 // Regression test for crbug.com/97784
3461 // Messing with the Object.prototype should not have effect on
3462 // hidden properties.
3464 v8::HandleScope scope(env->GetIsolate());
3466 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3467 v8::Local<v8::String> key = v8_str("hidden");
3470 "set_called = false;"
3471 "Object.defineProperty("
3472 " Object.prototype,"
3474 " {get: function() { return 45; },"
3475 " set: function() { set_called = true; }})");
3477 CHECK(obj->GetHiddenValue(key).IsEmpty());
3478 // Make sure that the getter and setter from Object.prototype is not invoked.
3479 // If it did we would have full access to the hidden properties in
3481 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3482 ExpectFalse("set_called");
3483 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3487 static bool interceptor_for_hidden_properties_called;
3488 static void InterceptorForHiddenProperties(
3489 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3490 interceptor_for_hidden_properties_called = true;
3494 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3495 LocalContext context;
3496 v8::Isolate* isolate = context->GetIsolate();
3497 v8::HandleScope scope(isolate);
3499 interceptor_for_hidden_properties_called = false;
3501 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3503 // Associate an interceptor with an object and start setting hidden values.
3504 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3505 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3506 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3507 Local<v8::Function> function = fun_templ->GetFunction();
3508 Local<v8::Object> obj = function->NewInstance();
3509 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3510 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3511 CHECK(!interceptor_for_hidden_properties_called);
3515 THREADED_TEST(External) {
3516 v8::HandleScope scope(CcTest::isolate());
3518 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3520 env->Global()->Set(v8_str("ext"), ext);
3521 Local<Value> reext_obj = CompileRun("this.ext");
3522 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3523 int* ptr = static_cast<int*>(reext->Value());
3528 // Make sure unaligned pointers are wrapped properly.
3529 char* data = i::StrDup("0123456789");
3530 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3531 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3532 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3533 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3535 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3536 CHECK_EQ('0', *char_ptr);
3537 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3538 CHECK_EQ('1', *char_ptr);
3539 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3540 CHECK_EQ('2', *char_ptr);
3541 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3542 CHECK_EQ('3', *char_ptr);
3543 i::DeleteArray(data);
3547 THREADED_TEST(GlobalHandle) {
3548 v8::Isolate* isolate = CcTest::isolate();
3549 v8::Persistent<String> global;
3551 v8::HandleScope scope(isolate);
3552 global.Reset(isolate, v8_str("str"));
3555 v8::HandleScope scope(isolate);
3556 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3560 v8::HandleScope scope(isolate);
3561 global.Reset(isolate, v8_str("str"));
3564 v8::HandleScope scope(isolate);
3565 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3571 THREADED_TEST(ResettingGlobalHandle) {
3572 v8::Isolate* isolate = CcTest::isolate();
3573 v8::Persistent<String> global;
3575 v8::HandleScope scope(isolate);
3576 global.Reset(isolate, v8_str("str"));
3578 v8::internal::GlobalHandles* global_handles =
3579 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3580 int initial_handle_count = global_handles->global_handles_count();
3582 v8::HandleScope scope(isolate);
3583 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3586 v8::HandleScope scope(isolate);
3587 global.Reset(isolate, v8_str("longer"));
3589 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3591 v8::HandleScope scope(isolate);
3592 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3595 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3599 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3600 v8::Isolate* isolate = CcTest::isolate();
3601 v8::Persistent<String> global;
3603 v8::HandleScope scope(isolate);
3604 global.Reset(isolate, v8_str("str"));
3606 v8::internal::GlobalHandles* global_handles =
3607 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3608 int initial_handle_count = global_handles->global_handles_count();
3610 v8::HandleScope scope(isolate);
3611 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3614 v8::HandleScope scope(isolate);
3615 Local<String> empty;
3616 global.Reset(isolate, empty);
3618 CHECK(global.IsEmpty());
3619 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3624 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3625 return unique.Pass();
3630 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3631 const v8::Persistent<T> & global) {
3632 v8::UniquePersistent<String> unique(isolate, global);
3633 return unique.Pass();
3637 THREADED_TEST(UniquePersistent) {
3638 v8::Isolate* isolate = CcTest::isolate();
3639 v8::Persistent<String> global;
3641 v8::HandleScope scope(isolate);
3642 global.Reset(isolate, v8_str("str"));
3644 v8::internal::GlobalHandles* global_handles =
3645 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3646 int initial_handle_count = global_handles->global_handles_count();
3648 v8::UniquePersistent<String> unique(isolate, global);
3649 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3650 // Test assignment via Pass
3652 v8::UniquePersistent<String> copy = unique.Pass();
3653 CHECK(unique.IsEmpty());
3654 CHECK(copy == global);
3655 CHECK_EQ(initial_handle_count + 1,
3656 global_handles->global_handles_count());
3657 unique = copy.Pass();
3659 // Test ctor via Pass
3661 v8::UniquePersistent<String> copy(unique.Pass());
3662 CHECK(unique.IsEmpty());
3663 CHECK(copy == global);
3664 CHECK_EQ(initial_handle_count + 1,
3665 global_handles->global_handles_count());
3666 unique = copy.Pass();
3668 // Test pass through function call
3670 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3671 CHECK(unique.IsEmpty());
3672 CHECK(copy == global);
3673 CHECK_EQ(initial_handle_count + 1,
3674 global_handles->global_handles_count());
3675 unique = copy.Pass();
3677 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3679 // Test pass from function call
3681 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3682 CHECK(unique == global);
3683 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3685 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3690 template<typename K, typename V>
3691 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3693 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3695 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3696 struct WeakCallbackDataType {
3700 static WeakCallbackDataType* WeakCallbackParameter(
3701 MapType* map, const K& key, Local<V> value) {
3702 WeakCallbackDataType* data = new WeakCallbackDataType;
3707 static MapType* MapFromWeakCallbackData(
3708 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3709 return data.GetParameter()->map;
3711 static K KeyFromWeakCallbackData(
3712 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3713 return data.GetParameter()->key;
3715 static void DisposeCallbackData(WeakCallbackDataType* data) {
3718 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3723 template<typename Map>
3724 static void TestPersistentValueMap() {
3726 v8::Isolate* isolate = env->GetIsolate();
3728 v8::internal::GlobalHandles* global_handles =
3729 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3730 int initial_handle_count = global_handles->global_handles_count();
3731 CHECK_EQ(0, static_cast<int>(map.Size()));
3733 HandleScope scope(isolate);
3734 Local<v8::Object> obj = map.Get(7);
3735 CHECK(obj.IsEmpty());
3736 Local<v8::Object> expected = v8::Object::New(isolate);
3737 map.Set(7, expected);
3738 CHECK_EQ(1, static_cast<int>(map.Size()));
3740 CHECK_EQ(expected, obj);
3742 typename Map::PersistentValueReference ref = map.GetReference(7);
3743 CHECK_EQ(expected, ref.NewLocal(isolate));
3745 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3746 CHECK_EQ(0, static_cast<int>(map.Size()));
3747 CHECK(expected == removed);
3748 removed = map.Remove(7);
3749 CHECK(removed.IsEmpty());
3750 map.Set(8, expected);
3751 CHECK_EQ(1, static_cast<int>(map.Size()));
3752 map.Set(8, expected);
3753 CHECK_EQ(1, static_cast<int>(map.Size()));
3755 typename Map::PersistentValueReference ref;
3756 Local<v8::Object> expected2 = v8::Object::New(isolate);
3757 removed = map.Set(8,
3758 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3759 CHECK_EQ(1, static_cast<int>(map.Size()));
3760 CHECK(expected == removed);
3761 CHECK_EQ(expected2, ref.NewLocal(isolate));
3764 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3766 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3767 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3771 CHECK_EQ(0, static_cast<int>(map.Size()));
3772 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3776 TEST(PersistentValueMap) {
3777 // Default case, w/o weak callbacks:
3778 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3780 // Custom traits with weak callbacks:
3781 typedef v8::PersistentValueMap<int, v8::Object,
3782 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3783 TestPersistentValueMap<WeakPersistentValueMap>();
3787 TEST(PersistentValueVector) {
3789 v8::Isolate* isolate = env->GetIsolate();
3790 v8::internal::GlobalHandles* global_handles =
3791 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3792 int handle_count = global_handles->global_handles_count();
3793 HandleScope scope(isolate);
3795 v8::PersistentValueVector<v8::Object> vector(isolate);
3797 Local<v8::Object> obj1 = v8::Object::New(isolate);
3798 Local<v8::Object> obj2 = v8::Object::New(isolate);
3799 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3801 CHECK(vector.IsEmpty());
3802 CHECK_EQ(0, static_cast<int>(vector.Size()));
3804 vector.ReserveCapacity(3);
3805 CHECK(vector.IsEmpty());
3807 vector.Append(obj1);
3808 vector.Append(obj2);
3809 vector.Append(obj1);
3810 vector.Append(obj3.Pass());
3811 vector.Append(obj1);
3813 CHECK(!vector.IsEmpty());
3814 CHECK_EQ(5, static_cast<int>(vector.Size()));
3815 CHECK(obj3.IsEmpty());
3816 CHECK_EQ(obj1, vector.Get(0));
3817 CHECK_EQ(obj1, vector.Get(2));
3818 CHECK_EQ(obj1, vector.Get(4));
3819 CHECK_EQ(obj2, vector.Get(1));
3821 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3824 CHECK(vector.IsEmpty());
3825 CHECK_EQ(0, static_cast<int>(vector.Size()));
3826 CHECK_EQ(handle_count, global_handles->global_handles_count());
3830 THREADED_TEST(GlobalHandleUpcast) {
3831 v8::Isolate* isolate = CcTest::isolate();
3832 v8::HandleScope scope(isolate);
3833 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3834 v8::Persistent<String> global_string(isolate, local);
3835 v8::Persistent<Value>& global_value =
3836 v8::Persistent<Value>::Cast(global_string);
3837 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3838 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3839 global_string.Reset();
3843 THREADED_TEST(HandleEquality) {
3844 v8::Isolate* isolate = CcTest::isolate();
3845 v8::Persistent<String> global1;
3846 v8::Persistent<String> global2;
3848 v8::HandleScope scope(isolate);
3849 global1.Reset(isolate, v8_str("str"));
3850 global2.Reset(isolate, v8_str("str2"));
3852 CHECK_EQ(global1 == global1, true);
3853 CHECK_EQ(global1 != global1, false);
3855 v8::HandleScope scope(isolate);
3856 Local<String> local1 = Local<String>::New(isolate, global1);
3857 Local<String> local2 = Local<String>::New(isolate, global2);
3859 CHECK_EQ(global1 == local1, true);
3860 CHECK_EQ(global1 != local1, false);
3861 CHECK_EQ(local1 == global1, true);
3862 CHECK_EQ(local1 != global1, false);
3864 CHECK_EQ(global1 == local2, false);
3865 CHECK_EQ(global1 != local2, true);
3866 CHECK_EQ(local2 == global1, false);
3867 CHECK_EQ(local2 != global1, true);
3869 CHECK_EQ(local1 == local2, false);
3870 CHECK_EQ(local1 != local2, true);
3872 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3873 CHECK_EQ(local1 == anotherLocal1, true);
3874 CHECK_EQ(local1 != anotherLocal1, false);
3881 THREADED_TEST(LocalHandle) {
3882 v8::HandleScope scope(CcTest::isolate());
3883 v8::Local<String> local =
3884 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3885 CHECK_EQ(local->Length(), 3);
3889 class WeakCallCounter {
3891 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3892 int id() { return id_; }
3893 void increment() { number_of_weak_calls_++; }
3894 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3897 int number_of_weak_calls_;
3901 template<typename T>
3902 struct WeakCallCounterAndPersistent {
3903 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3904 : counter(counter) {}
3905 WeakCallCounter* counter;
3906 v8::Persistent<T> handle;
3910 template <typename T>
3911 static void WeakPointerCallback(
3912 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3913 CHECK_EQ(1234, data.GetParameter()->counter->id());
3914 data.GetParameter()->counter->increment();
3915 data.GetParameter()->handle.Reset();
3919 template<typename T>
3920 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3921 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3925 THREADED_TEST(ApiObjectGroups) {
3927 v8::Isolate* iso = env->GetIsolate();
3928 HandleScope scope(iso);
3930 WeakCallCounter counter(1234);
3932 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3933 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3934 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3935 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3936 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3937 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3940 HandleScope scope(iso);
3941 g1s1.handle.Reset(iso, Object::New(iso));
3942 g1s2.handle.Reset(iso, Object::New(iso));
3943 g1c1.handle.Reset(iso, Object::New(iso));
3944 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3945 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3946 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3948 g2s1.handle.Reset(iso, Object::New(iso));
3949 g2s2.handle.Reset(iso, Object::New(iso));
3950 g2c1.handle.Reset(iso, Object::New(iso));
3951 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3952 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3953 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3956 WeakCallCounterAndPersistent<Value> root(&counter);
3957 root.handle.Reset(iso, g1s1.handle); // make a root.
3959 // Connect group 1 and 2, make a cycle.
3961 HandleScope scope(iso);
3962 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3963 Set(0, Local<Value>::New(iso, g2s2.handle)));
3964 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3965 Set(0, Local<Value>::New(iso, g1s1.handle)));
3969 UniqueId id1 = MakeUniqueId(g1s1.handle);
3970 UniqueId id2 = MakeUniqueId(g2s2.handle);
3971 iso->SetObjectGroupId(g1s1.handle, id1);
3972 iso->SetObjectGroupId(g1s2.handle, id1);
3973 iso->SetReferenceFromGroup(id1, g1c1.handle);
3974 iso->SetObjectGroupId(g2s1.handle, id2);
3975 iso->SetObjectGroupId(g2s2.handle, id2);
3976 iso->SetReferenceFromGroup(id2, g2c1.handle);
3978 // Do a single full GC, ensure incremental marking is stopped.
3979 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3981 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3983 // All object should be alive.
3984 CHECK_EQ(0, counter.NumberOfWeakCalls());
3987 root.handle.SetWeak(&root, &WeakPointerCallback);
3988 // But make children strong roots---all the objects (except for children)
3989 // should be collectable now.
3990 g1c1.handle.ClearWeak();
3991 g2c1.handle.ClearWeak();
3993 // Groups are deleted, rebuild groups.
3995 UniqueId id1 = MakeUniqueId(g1s1.handle);
3996 UniqueId id2 = MakeUniqueId(g2s2.handle);
3997 iso->SetObjectGroupId(g1s1.handle, id1);
3998 iso->SetObjectGroupId(g1s2.handle, id1);
3999 iso->SetReferenceFromGroup(id1, g1c1.handle);
4000 iso->SetObjectGroupId(g2s1.handle, id2);
4001 iso->SetObjectGroupId(g2s2.handle, id2);
4002 iso->SetReferenceFromGroup(id2, g2c1.handle);
4005 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4007 // All objects should be gone. 5 global handles in total.
4008 CHECK_EQ(5, counter.NumberOfWeakCalls());
4010 // And now make children weak again and collect them.
4011 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4012 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4014 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4015 CHECK_EQ(7, counter.NumberOfWeakCalls());
4019 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4021 v8::Isolate* iso = env->GetIsolate();
4022 HandleScope scope(iso);
4024 WeakCallCounter counter(1234);
4026 WeakCallCounterAndPersistent<Object> g1s1(&counter);
4027 WeakCallCounterAndPersistent<String> g1s2(&counter);
4028 WeakCallCounterAndPersistent<String> g1c1(&counter);
4029 WeakCallCounterAndPersistent<Object> g2s1(&counter);
4030 WeakCallCounterAndPersistent<String> g2s2(&counter);
4031 WeakCallCounterAndPersistent<String> g2c1(&counter);
4034 HandleScope scope(iso);
4035 g1s1.handle.Reset(iso, Object::New(iso));
4036 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4037 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4038 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4039 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4040 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4042 g2s1.handle.Reset(iso, Object::New(iso));
4043 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4044 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4045 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4046 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4047 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4050 WeakCallCounterAndPersistent<Value> root(&counter);
4051 root.handle.Reset(iso, g1s1.handle); // make a root.
4053 // Connect group 1 and 2, make a cycle.
4055 HandleScope scope(iso);
4056 CHECK(Local<Object>::New(iso, g1s1.handle)
4057 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4058 CHECK(Local<Object>::New(iso, g2s1.handle)
4059 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4063 UniqueId id1 = MakeUniqueId(g1s1.handle);
4064 UniqueId id2 = MakeUniqueId(g2s2.handle);
4065 iso->SetObjectGroupId(g1s1.handle, id1);
4066 iso->SetObjectGroupId(g1s2.handle, id1);
4067 iso->SetReference(g1s1.handle, g1c1.handle);
4068 iso->SetObjectGroupId(g2s1.handle, id2);
4069 iso->SetObjectGroupId(g2s2.handle, id2);
4070 iso->SetReferenceFromGroup(id2, g2c1.handle);
4072 // Do a single full GC, ensure incremental marking is stopped.
4073 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4075 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4077 // All object should be alive.
4078 CHECK_EQ(0, counter.NumberOfWeakCalls());
4081 root.handle.SetWeak(&root, &WeakPointerCallback);
4082 // But make children strong roots---all the objects (except for children)
4083 // should be collectable now.
4084 g1c1.handle.ClearWeak();
4085 g2c1.handle.ClearWeak();
4087 // Groups are deleted, rebuild groups.
4089 UniqueId id1 = MakeUniqueId(g1s1.handle);
4090 UniqueId id2 = MakeUniqueId(g2s2.handle);
4091 iso->SetObjectGroupId(g1s1.handle, id1);
4092 iso->SetObjectGroupId(g1s2.handle, id1);
4093 iso->SetReference(g1s1.handle, g1c1.handle);
4094 iso->SetObjectGroupId(g2s1.handle, id2);
4095 iso->SetObjectGroupId(g2s2.handle, id2);
4096 iso->SetReferenceFromGroup(id2, g2c1.handle);
4099 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4101 // All objects should be gone. 5 global handles in total.
4102 CHECK_EQ(5, counter.NumberOfWeakCalls());
4104 // And now make children weak again and collect them.
4105 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4106 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4108 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4109 CHECK_EQ(7, counter.NumberOfWeakCalls());
4113 THREADED_TEST(ApiObjectGroupsCycle) {
4115 v8::Isolate* iso = env->GetIsolate();
4116 HandleScope scope(iso);
4118 WeakCallCounter counter(1234);
4120 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4121 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4122 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4123 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4124 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4125 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4126 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4127 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4130 HandleScope scope(iso);
4131 g1s1.handle.Reset(iso, Object::New(iso));
4132 g1s2.handle.Reset(iso, Object::New(iso));
4133 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4134 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4135 CHECK(g1s1.handle.IsWeak());
4136 CHECK(g1s2.handle.IsWeak());
4138 g2s1.handle.Reset(iso, Object::New(iso));
4139 g2s2.handle.Reset(iso, Object::New(iso));
4140 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4141 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4142 CHECK(g2s1.handle.IsWeak());
4143 CHECK(g2s2.handle.IsWeak());
4145 g3s1.handle.Reset(iso, Object::New(iso));
4146 g3s2.handle.Reset(iso, Object::New(iso));
4147 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4148 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4149 CHECK(g3s1.handle.IsWeak());
4150 CHECK(g3s2.handle.IsWeak());
4152 g4s1.handle.Reset(iso, Object::New(iso));
4153 g4s2.handle.Reset(iso, Object::New(iso));
4154 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4155 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4156 CHECK(g4s1.handle.IsWeak());
4157 CHECK(g4s2.handle.IsWeak());
4160 WeakCallCounterAndPersistent<Value> root(&counter);
4161 root.handle.Reset(iso, g1s1.handle); // make a root.
4163 // Connect groups. We're building the following cycle:
4164 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4167 UniqueId id1 = MakeUniqueId(g1s1.handle);
4168 UniqueId id2 = MakeUniqueId(g2s1.handle);
4169 UniqueId id3 = MakeUniqueId(g3s1.handle);
4170 UniqueId id4 = MakeUniqueId(g4s1.handle);
4171 iso->SetObjectGroupId(g1s1.handle, id1);
4172 iso->SetObjectGroupId(g1s2.handle, id1);
4173 iso->SetReferenceFromGroup(id1, g2s1.handle);
4174 iso->SetObjectGroupId(g2s1.handle, id2);
4175 iso->SetObjectGroupId(g2s2.handle, id2);
4176 iso->SetReferenceFromGroup(id2, g3s1.handle);
4177 iso->SetObjectGroupId(g3s1.handle, id3);
4178 iso->SetObjectGroupId(g3s2.handle, id3);
4179 iso->SetReferenceFromGroup(id3, g4s1.handle);
4180 iso->SetObjectGroupId(g4s1.handle, id4);
4181 iso->SetObjectGroupId(g4s2.handle, id4);
4182 iso->SetReferenceFromGroup(id4, g1s1.handle);
4184 // Do a single full GC
4185 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4187 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4189 // All object should be alive.
4190 CHECK_EQ(0, counter.NumberOfWeakCalls());
4193 root.handle.SetWeak(&root, &WeakPointerCallback);
4195 // Groups are deleted, rebuild groups.
4197 UniqueId id1 = MakeUniqueId(g1s1.handle);
4198 UniqueId id2 = MakeUniqueId(g2s1.handle);
4199 UniqueId id3 = MakeUniqueId(g3s1.handle);
4200 UniqueId id4 = MakeUniqueId(g4s1.handle);
4201 iso->SetObjectGroupId(g1s1.handle, id1);
4202 iso->SetObjectGroupId(g1s2.handle, id1);
4203 iso->SetReferenceFromGroup(id1, g2s1.handle);
4204 iso->SetObjectGroupId(g2s1.handle, id2);
4205 iso->SetObjectGroupId(g2s2.handle, id2);
4206 iso->SetReferenceFromGroup(id2, g3s1.handle);
4207 iso->SetObjectGroupId(g3s1.handle, id3);
4208 iso->SetObjectGroupId(g3s2.handle, id3);
4209 iso->SetReferenceFromGroup(id3, g4s1.handle);
4210 iso->SetObjectGroupId(g4s1.handle, id4);
4211 iso->SetObjectGroupId(g4s2.handle, id4);
4212 iso->SetReferenceFromGroup(id4, g1s1.handle);
4215 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4217 // All objects should be gone. 9 global handles in total.
4218 CHECK_EQ(9, counter.NumberOfWeakCalls());
4222 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4223 // on the buildbots, so was made non-threaded for the time being.
4224 TEST(ApiObjectGroupsCycleForScavenger) {
4225 i::FLAG_stress_compaction = false;
4226 i::FLAG_gc_global = false;
4228 v8::Isolate* iso = env->GetIsolate();
4229 HandleScope scope(iso);
4231 WeakCallCounter counter(1234);
4233 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4234 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4235 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4236 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4237 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4238 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4241 HandleScope scope(iso);
4242 g1s1.handle.Reset(iso, Object::New(iso));
4243 g1s2.handle.Reset(iso, Object::New(iso));
4244 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4245 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4247 g2s1.handle.Reset(iso, Object::New(iso));
4248 g2s2.handle.Reset(iso, Object::New(iso));
4249 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4250 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4252 g3s1.handle.Reset(iso, Object::New(iso));
4253 g3s2.handle.Reset(iso, Object::New(iso));
4254 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4255 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4259 WeakCallCounterAndPersistent<Value> root(&counter);
4260 root.handle.Reset(iso, g1s1.handle);
4261 root.handle.MarkPartiallyDependent();
4263 // Connect groups. We're building the following cycle:
4264 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4267 HandleScope handle_scope(iso);
4268 g1s1.handle.MarkPartiallyDependent();
4269 g1s2.handle.MarkPartiallyDependent();
4270 g2s1.handle.MarkPartiallyDependent();
4271 g2s2.handle.MarkPartiallyDependent();
4272 g3s1.handle.MarkPartiallyDependent();
4273 g3s2.handle.MarkPartiallyDependent();
4274 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4275 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4276 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4277 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4278 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4279 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4280 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4281 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4282 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4283 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4284 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4285 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4288 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4290 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4292 // All objects should be alive.
4293 CHECK_EQ(0, counter.NumberOfWeakCalls());
4296 root.handle.SetWeak(&root, &WeakPointerCallback);
4297 root.handle.MarkPartiallyDependent();
4299 // Groups are deleted, rebuild groups.
4301 HandleScope handle_scope(iso);
4302 g1s1.handle.MarkPartiallyDependent();
4303 g1s2.handle.MarkPartiallyDependent();
4304 g2s1.handle.MarkPartiallyDependent();
4305 g2s2.handle.MarkPartiallyDependent();
4306 g3s1.handle.MarkPartiallyDependent();
4307 g3s2.handle.MarkPartiallyDependent();
4308 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4309 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4310 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4311 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4312 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4313 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4314 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4315 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4316 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4317 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4318 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4319 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4322 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4324 // All objects should be gone. 7 global handles in total.
4325 CHECK_EQ(7, counter.NumberOfWeakCalls());
4329 THREADED_TEST(ScriptException) {
4331 v8::HandleScope scope(env->GetIsolate());
4332 Local<Script> script = v8_compile("throw 'panama!';");
4333 v8::TryCatch try_catch;
4334 Local<Value> result = script->Run();
4335 CHECK(result.IsEmpty());
4336 CHECK(try_catch.HasCaught());
4337 String::Utf8Value exception_value(try_catch.Exception());
4338 CHECK_EQ(*exception_value, "panama!");
4342 TEST(TryCatchCustomException) {
4344 v8::HandleScope scope(env->GetIsolate());
4345 v8::TryCatch try_catch;
4346 CompileRun("function CustomError() { this.a = 'b'; }"
4347 "(function f() { throw new CustomError(); })();");
4348 CHECK(try_catch.HasCaught());
4349 CHECK(try_catch.Exception()->ToObject()->
4350 Get(v8_str("a"))->Equals(v8_str("b")));
4354 bool message_received;
4357 static void check_message_0(v8::Handle<v8::Message> message,
4358 v8::Handle<Value> data) {
4359 CHECK_EQ(5.76, data->NumberValue());
4360 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4361 CHECK(!message->IsSharedCrossOrigin());
4362 message_received = true;
4366 THREADED_TEST(MessageHandler0) {
4367 message_received = false;
4368 v8::HandleScope scope(CcTest::isolate());
4369 CHECK(!message_received);
4370 LocalContext context;
4371 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4372 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4374 CHECK(message_received);
4375 // clear out the message listener
4376 v8::V8::RemoveMessageListeners(check_message_0);
4380 static void check_message_1(v8::Handle<v8::Message> message,
4381 v8::Handle<Value> data) {
4382 CHECK(data->IsNumber());
4383 CHECK_EQ(1337, data->Int32Value());
4384 CHECK(!message->IsSharedCrossOrigin());
4385 message_received = true;
4389 TEST(MessageHandler1) {
4390 message_received = false;
4391 v8::HandleScope scope(CcTest::isolate());
4392 CHECK(!message_received);
4393 v8::V8::AddMessageListener(check_message_1);
4394 LocalContext context;
4395 CompileRun("throw 1337;");
4396 CHECK(message_received);
4397 // clear out the message listener
4398 v8::V8::RemoveMessageListeners(check_message_1);
4402 static void check_message_2(v8::Handle<v8::Message> message,
4403 v8::Handle<Value> data) {
4404 LocalContext context;
4405 CHECK(data->IsObject());
4406 v8::Local<v8::Value> hidden_property =
4407 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4408 CHECK(v8_str("hidden value")->Equals(hidden_property));
4409 CHECK(!message->IsSharedCrossOrigin());
4410 message_received = true;
4414 TEST(MessageHandler2) {
4415 message_received = false;
4416 v8::HandleScope scope(CcTest::isolate());
4417 CHECK(!message_received);
4418 v8::V8::AddMessageListener(check_message_2);
4419 LocalContext context;
4420 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4421 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4422 v8_str("hidden value"));
4423 context->Global()->Set(v8_str("error"), error);
4424 CompileRun("throw error;");
4425 CHECK(message_received);
4426 // clear out the message listener
4427 v8::V8::RemoveMessageListeners(check_message_2);
4431 static void check_message_3(v8::Handle<v8::Message> message,
4432 v8::Handle<Value> data) {
4433 CHECK(message->IsSharedCrossOrigin());
4434 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4435 message_received = true;
4439 TEST(MessageHandler3) {
4440 message_received = false;
4441 v8::Isolate* isolate = CcTest::isolate();
4442 v8::HandleScope scope(isolate);
4443 CHECK(!message_received);
4444 v8::V8::AddMessageListener(check_message_3);
4445 LocalContext context;
4446 v8::ScriptOrigin origin =
4447 v8::ScriptOrigin(v8_str("6.75"),
4448 v8::Integer::New(isolate, 1),
4449 v8::Integer::New(isolate, 2),
4451 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4454 CHECK(message_received);
4455 // clear out the message listener
4456 v8::V8::RemoveMessageListeners(check_message_3);
4460 static void check_message_4(v8::Handle<v8::Message> message,
4461 v8::Handle<Value> data) {
4462 CHECK(!message->IsSharedCrossOrigin());
4463 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4464 message_received = true;
4468 TEST(MessageHandler4) {
4469 message_received = false;
4470 v8::Isolate* isolate = CcTest::isolate();
4471 v8::HandleScope scope(isolate);
4472 CHECK(!message_received);
4473 v8::V8::AddMessageListener(check_message_4);
4474 LocalContext context;
4475 v8::ScriptOrigin origin =
4476 v8::ScriptOrigin(v8_str("6.75"),
4477 v8::Integer::New(isolate, 1),
4478 v8::Integer::New(isolate, 2),
4479 v8::False(isolate));
4480 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4483 CHECK(message_received);
4484 // clear out the message listener
4485 v8::V8::RemoveMessageListeners(check_message_4);
4489 static void check_message_5a(v8::Handle<v8::Message> message,
4490 v8::Handle<Value> data) {
4491 CHECK(message->IsSharedCrossOrigin());
4492 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4493 message_received = true;
4497 static void check_message_5b(v8::Handle<v8::Message> message,
4498 v8::Handle<Value> data) {
4499 CHECK(!message->IsSharedCrossOrigin());
4500 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4501 message_received = true;
4505 TEST(MessageHandler5) {
4506 message_received = false;
4507 v8::Isolate* isolate = CcTest::isolate();
4508 v8::HandleScope scope(isolate);
4509 CHECK(!message_received);
4510 v8::V8::AddMessageListener(check_message_5a);
4511 LocalContext context;
4512 v8::ScriptOrigin origin =
4513 v8::ScriptOrigin(v8_str("6.75"),
4514 v8::Integer::New(isolate, 1),
4515 v8::Integer::New(isolate, 2),
4517 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4520 CHECK(message_received);
4521 // clear out the message listener
4522 v8::V8::RemoveMessageListeners(check_message_5a);
4524 message_received = false;
4525 v8::V8::AddMessageListener(check_message_5b);
4527 v8::ScriptOrigin(v8_str("6.75"),
4528 v8::Integer::New(isolate, 1),
4529 v8::Integer::New(isolate, 2),
4530 v8::False(isolate));
4531 script = Script::Compile(v8_str("throw 'error'"),
4534 CHECK(message_received);
4535 // clear out the message listener
4536 v8::V8::RemoveMessageListeners(check_message_5b);
4540 THREADED_TEST(GetSetProperty) {
4541 LocalContext context;
4542 v8::Isolate* isolate = context->GetIsolate();
4543 v8::HandleScope scope(isolate);
4544 context->Global()->Set(v8_str("foo"), v8_num(14));
4545 context->Global()->Set(v8_str("12"), v8_num(92));
4546 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4547 context->Global()->Set(v8_num(13), v8_num(56));
4548 Local<Value> foo = CompileRun("this.foo");
4549 CHECK_EQ(14, foo->Int32Value());
4550 Local<Value> twelve = CompileRun("this[12]");
4551 CHECK_EQ(92, twelve->Int32Value());
4552 Local<Value> sixteen = CompileRun("this[16]");
4553 CHECK_EQ(32, sixteen->Int32Value());
4554 Local<Value> thirteen = CompileRun("this[13]");
4555 CHECK_EQ(56, thirteen->Int32Value());
4557 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4558 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4559 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4561 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4562 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4563 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4565 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4566 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4567 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4571 THREADED_TEST(PropertyAttributes) {
4572 LocalContext context;
4573 v8::HandleScope scope(context->GetIsolate());
4575 Local<String> prop = v8_str("none");
4576 context->Global()->Set(prop, v8_num(7));
4577 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4579 prop = v8_str("read_only");
4580 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4581 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4582 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4583 CompileRun("read_only = 9");
4584 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4585 context->Global()->Set(prop, v8_num(10));
4586 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4588 prop = v8_str("dont_delete");
4589 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4590 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4591 CompileRun("delete dont_delete");
4592 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4593 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4595 prop = v8_str("dont_enum");
4596 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4597 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4599 prop = v8_str("absent");
4600 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4601 Local<Value> fake_prop = v8_num(1);
4602 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4605 Local<Value> exception =
4606 CompileRun("({ toString: function() { throw 'exception';} })");
4607 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4608 CHECK(try_catch.HasCaught());
4609 String::Utf8Value exception_value(try_catch.Exception());
4610 CHECK_EQ("exception", *exception_value);
4615 THREADED_TEST(Array) {
4616 LocalContext context;
4617 v8::HandleScope scope(context->GetIsolate());
4618 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4619 CHECK_EQ(0, array->Length());
4620 CHECK(array->Get(0)->IsUndefined());
4621 CHECK(!array->Has(0));
4622 CHECK(array->Get(100)->IsUndefined());
4623 CHECK(!array->Has(100));
4624 array->Set(2, v8_num(7));
4625 CHECK_EQ(3, array->Length());
4626 CHECK(!array->Has(0));
4627 CHECK(!array->Has(1));
4628 CHECK(array->Has(2));
4629 CHECK_EQ(7, array->Get(2)->Int32Value());
4630 Local<Value> obj = CompileRun("[1, 2, 3]");
4631 Local<v8::Array> arr = obj.As<v8::Array>();
4632 CHECK_EQ(3, arr->Length());
4633 CHECK_EQ(1, arr->Get(0)->Int32Value());
4634 CHECK_EQ(2, arr->Get(1)->Int32Value());
4635 CHECK_EQ(3, arr->Get(2)->Int32Value());
4636 array = v8::Array::New(context->GetIsolate(), 27);
4637 CHECK_EQ(27, array->Length());
4638 array = v8::Array::New(context->GetIsolate(), -27);
4639 CHECK_EQ(0, array->Length());
4643 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4644 v8::EscapableHandleScope scope(args.GetIsolate());
4645 ApiTestFuzzer::Fuzz();
4646 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4647 for (int i = 0; i < args.Length(); i++)
4648 result->Set(i, args[i]);
4649 args.GetReturnValue().Set(scope.Escape(result));
4653 THREADED_TEST(Vector) {
4654 v8::Isolate* isolate = CcTest::isolate();
4655 v8::HandleScope scope(isolate);
4656 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4657 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4658 LocalContext context(0, global);
4660 const char* fun = "f()";
4661 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4662 CHECK_EQ(0, a0->Length());
4664 const char* fun2 = "f(11)";
4665 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4666 CHECK_EQ(1, a1->Length());
4667 CHECK_EQ(11, a1->Get(0)->Int32Value());
4669 const char* fun3 = "f(12, 13)";
4670 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4671 CHECK_EQ(2, a2->Length());
4672 CHECK_EQ(12, a2->Get(0)->Int32Value());
4673 CHECK_EQ(13, a2->Get(1)->Int32Value());
4675 const char* fun4 = "f(14, 15, 16)";
4676 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4677 CHECK_EQ(3, a3->Length());
4678 CHECK_EQ(14, a3->Get(0)->Int32Value());
4679 CHECK_EQ(15, a3->Get(1)->Int32Value());
4680 CHECK_EQ(16, a3->Get(2)->Int32Value());
4682 const char* fun5 = "f(17, 18, 19, 20)";
4683 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4684 CHECK_EQ(4, a4->Length());
4685 CHECK_EQ(17, a4->Get(0)->Int32Value());
4686 CHECK_EQ(18, a4->Get(1)->Int32Value());
4687 CHECK_EQ(19, a4->Get(2)->Int32Value());
4688 CHECK_EQ(20, a4->Get(3)->Int32Value());
4692 THREADED_TEST(FunctionCall) {
4693 LocalContext context;
4694 v8::Isolate* isolate = context->GetIsolate();
4695 v8::HandleScope scope(isolate);
4699 " for (var i = 0; i < arguments.length; i++) {"
4700 " result.push(arguments[i]);"
4704 "function ReturnThisSloppy() {"
4707 "function ReturnThisStrict() {"
4711 Local<Function> Foo =
4712 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4713 Local<Function> ReturnThisSloppy =
4714 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4715 Local<Function> ReturnThisStrict =
4716 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4718 v8::Handle<Value>* args0 = NULL;
4719 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4720 CHECK_EQ(0, a0->Length());
4722 v8::Handle<Value> args1[] = { v8_num(1.1) };
4723 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4724 CHECK_EQ(1, a1->Length());
4725 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4727 v8::Handle<Value> args2[] = { v8_num(2.2),
4729 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4730 CHECK_EQ(2, a2->Length());
4731 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4732 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4734 v8::Handle<Value> args3[] = { v8_num(4.4),
4737 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4738 CHECK_EQ(3, a3->Length());
4739 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4740 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4741 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4743 v8::Handle<Value> args4[] = { v8_num(7.7),
4747 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4748 CHECK_EQ(4, a4->Length());
4749 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4750 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4751 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4752 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4754 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4755 CHECK(r1->StrictEquals(context->Global()));
4756 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4757 CHECK(r2->StrictEquals(context->Global()));
4758 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4759 CHECK(r3->IsNumberObject());
4760 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4761 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4762 CHECK(r4->IsStringObject());
4763 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4764 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4765 CHECK(r5->IsBooleanObject());
4766 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4768 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4769 CHECK(r6->IsUndefined());
4770 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4771 CHECK(r7->IsNull());
4772 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4773 CHECK(r8->StrictEquals(v8_num(42)));
4774 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4775 CHECK(r9->StrictEquals(v8_str("hello")));
4776 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4777 CHECK(r10->StrictEquals(v8::True(isolate)));
4781 THREADED_TEST(ConstructCall) {
4782 LocalContext context;
4783 v8::Isolate* isolate = context->GetIsolate();
4784 v8::HandleScope scope(isolate);
4788 " for (var i = 0; i < arguments.length; i++) {"
4789 " result.push(arguments[i]);"
4793 Local<Function> Foo =
4794 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4796 v8::Handle<Value>* args0 = NULL;
4797 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4798 CHECK_EQ(0, a0->Length());
4800 v8::Handle<Value> args1[] = { v8_num(1.1) };
4801 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4802 CHECK_EQ(1, a1->Length());
4803 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4805 v8::Handle<Value> args2[] = { v8_num(2.2),
4807 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4808 CHECK_EQ(2, a2->Length());
4809 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4810 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4812 v8::Handle<Value> args3[] = { v8_num(4.4),
4815 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4816 CHECK_EQ(3, a3->Length());
4817 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4818 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4819 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4821 v8::Handle<Value> args4[] = { v8_num(7.7),
4825 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4826 CHECK_EQ(4, a4->Length());
4827 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4828 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4829 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4830 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4834 static void CheckUncle(v8::TryCatch* try_catch) {
4835 CHECK(try_catch->HasCaught());
4836 String::Utf8Value str_value(try_catch->Exception());
4837 CHECK_EQ(*str_value, "uncle?");
4842 THREADED_TEST(ConversionNumber) {
4844 v8::HandleScope scope(env->GetIsolate());
4845 // Very large number.
4846 CompileRun("var obj = Math.pow(2,32) * 1237;");
4847 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4848 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4849 CHECK_EQ(0, obj->ToInt32()->Value());
4850 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4852 CompileRun("var obj = -1234567890123;");
4853 obj = env->Global()->Get(v8_str("obj"));
4854 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4855 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4856 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4857 // Small positive integer.
4858 CompileRun("var obj = 42;");
4859 obj = env->Global()->Get(v8_str("obj"));
4860 CHECK_EQ(42.0, obj->ToNumber()->Value());
4861 CHECK_EQ(42, obj->ToInt32()->Value());
4862 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4863 // Negative integer.
4864 CompileRun("var obj = -37;");
4865 obj = env->Global()->Get(v8_str("obj"));
4866 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4867 CHECK_EQ(-37, obj->ToInt32()->Value());
4868 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4869 // Positive non-int32 integer.
4870 CompileRun("var obj = 0x81234567;");
4871 obj = env->Global()->Get(v8_str("obj"));
4872 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4873 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4874 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4876 CompileRun("var obj = 42.3;");
4877 obj = env->Global()->Get(v8_str("obj"));
4878 CHECK_EQ(42.3, obj->ToNumber()->Value());
4879 CHECK_EQ(42, obj->ToInt32()->Value());
4880 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4881 // Large negative fraction.
4882 CompileRun("var obj = -5726623061.75;");
4883 obj = env->Global()->Get(v8_str("obj"));
4884 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4885 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4886 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4890 THREADED_TEST(isNumberType) {
4892 v8::HandleScope scope(env->GetIsolate());
4893 // Very large number.
4894 CompileRun("var obj = Math.pow(2,32) * 1237;");
4895 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4896 CHECK(!obj->IsInt32());
4897 CHECK(!obj->IsUint32());
4898 // Large negative number.
4899 CompileRun("var obj = -1234567890123;");
4900 obj = env->Global()->Get(v8_str("obj"));
4901 CHECK(!obj->IsInt32());
4902 CHECK(!obj->IsUint32());
4903 // Small positive integer.
4904 CompileRun("var obj = 42;");
4905 obj = env->Global()->Get(v8_str("obj"));
4906 CHECK(obj->IsInt32());
4907 CHECK(obj->IsUint32());
4908 // Negative integer.
4909 CompileRun("var obj = -37;");
4910 obj = env->Global()->Get(v8_str("obj"));
4911 CHECK(obj->IsInt32());
4912 CHECK(!obj->IsUint32());
4913 // Positive non-int32 integer.
4914 CompileRun("var obj = 0x81234567;");
4915 obj = env->Global()->Get(v8_str("obj"));
4916 CHECK(!obj->IsInt32());
4917 CHECK(obj->IsUint32());
4919 CompileRun("var obj = 42.3;");
4920 obj = env->Global()->Get(v8_str("obj"));
4921 CHECK(!obj->IsInt32());
4922 CHECK(!obj->IsUint32());
4923 // Large negative fraction.
4924 CompileRun("var obj = -5726623061.75;");
4925 obj = env->Global()->Get(v8_str("obj"));
4926 CHECK(!obj->IsInt32());
4927 CHECK(!obj->IsUint32());
4929 CompileRun("var obj = 0.0;");
4930 obj = env->Global()->Get(v8_str("obj"));
4931 CHECK(obj->IsInt32());
4932 CHECK(obj->IsUint32());
4934 CompileRun("var obj = -0.0;");
4935 obj = env->Global()->Get(v8_str("obj"));
4936 CHECK(!obj->IsInt32());
4937 CHECK(!obj->IsUint32());
4941 THREADED_TEST(ConversionException) {
4943 v8::Isolate* isolate = env->GetIsolate();
4944 v8::HandleScope scope(isolate);
4946 "function TestClass() { };"
4947 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4948 "var obj = new TestClass();");
4949 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4951 v8::TryCatch try_catch;
4953 Local<Value> to_string_result = obj->ToString();
4954 CHECK(to_string_result.IsEmpty());
4955 CheckUncle(&try_catch);
4957 Local<Value> to_number_result = obj->ToNumber();
4958 CHECK(to_number_result.IsEmpty());
4959 CheckUncle(&try_catch);
4961 Local<Value> to_integer_result = obj->ToInteger();
4962 CHECK(to_integer_result.IsEmpty());
4963 CheckUncle(&try_catch);
4965 Local<Value> to_uint32_result = obj->ToUint32();
4966 CHECK(to_uint32_result.IsEmpty());
4967 CheckUncle(&try_catch);
4969 Local<Value> to_int32_result = obj->ToInt32();
4970 CHECK(to_int32_result.IsEmpty());
4971 CheckUncle(&try_catch);
4973 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4974 CHECK(to_object_result.IsEmpty());
4975 CHECK(try_catch.HasCaught());
4978 int32_t int32_value = obj->Int32Value();
4979 CHECK_EQ(0, int32_value);
4980 CheckUncle(&try_catch);
4982 uint32_t uint32_value = obj->Uint32Value();
4983 CHECK_EQ(0, uint32_value);
4984 CheckUncle(&try_catch);
4986 double number_value = obj->NumberValue();
4987 CHECK_NE(0, std::isnan(number_value));
4988 CheckUncle(&try_catch);
4990 int64_t integer_value = obj->IntegerValue();
4991 CHECK_EQ(0.0, static_cast<double>(integer_value));
4992 CheckUncle(&try_catch);
4996 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4997 ApiTestFuzzer::Fuzz();
4998 args.GetIsolate()->ThrowException(v8_str("konto"));
5002 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5003 if (args.Length() < 1) {
5004 args.GetReturnValue().Set(false);
5007 v8::HandleScope scope(args.GetIsolate());
5008 v8::TryCatch try_catch;
5009 Local<Value> result = CompileRun(args[0]->ToString());
5010 CHECK(!try_catch.HasCaught() || result.IsEmpty());
5011 args.GetReturnValue().Set(try_catch.HasCaught());
5015 THREADED_TEST(APICatch) {
5016 v8::Isolate* isolate = CcTest::isolate();
5017 v8::HandleScope scope(isolate);
5018 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5019 templ->Set(v8_str("ThrowFromC"),
5020 v8::FunctionTemplate::New(isolate, ThrowFromC));
5021 LocalContext context(0, templ);
5023 "var thrown = false;"
5029 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5030 CHECK(thrown->BooleanValue());
5034 THREADED_TEST(APIThrowTryCatch) {
5035 v8::Isolate* isolate = CcTest::isolate();
5036 v8::HandleScope scope(isolate);
5037 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5038 templ->Set(v8_str("ThrowFromC"),
5039 v8::FunctionTemplate::New(isolate, ThrowFromC));
5040 LocalContext context(0, templ);
5041 v8::TryCatch try_catch;
5042 CompileRun("ThrowFromC();");
5043 CHECK(try_catch.HasCaught());
5047 // Test that a try-finally block doesn't shadow a try-catch block
5048 // when setting up an external handler.
5050 // BUG(271): Some of the exception propagation does not work on the
5051 // ARM simulator because the simulator separates the C++ stack and the
5052 // JS stack. This test therefore fails on the simulator. The test is
5053 // not threaded to allow the threading tests to run on the simulator.
5054 TEST(TryCatchInTryFinally) {
5055 v8::Isolate* isolate = CcTest::isolate();
5056 v8::HandleScope scope(isolate);
5057 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5058 templ->Set(v8_str("CCatcher"),
5059 v8::FunctionTemplate::New(isolate, CCatcher));
5060 LocalContext context(0, templ);
5061 Local<Value> result = CompileRun("try {"
5063 " CCatcher('throw 7;');"
5068 CHECK(result->IsTrue());
5072 static void check_reference_error_message(
5073 v8::Handle<v8::Message> message,
5074 v8::Handle<v8::Value> data) {
5075 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5076 CHECK(message->Get()->Equals(v8_str(reference_error)));
5080 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5081 ApiTestFuzzer::Fuzz();
5086 // Test that overwritten methods are not invoked on uncaught exception
5087 // formatting. However, they are invoked when performing normal error
5088 // string conversions.
5089 TEST(APIThrowMessageOverwrittenToString) {
5090 v8::Isolate* isolate = CcTest::isolate();
5091 v8::HandleScope scope(isolate);
5092 v8::V8::AddMessageListener(check_reference_error_message);
5093 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5094 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5095 LocalContext context(NULL, templ);
5096 CompileRun("asdf;");
5097 CompileRun("var limit = {};"
5098 "limit.valueOf = fail;"
5099 "Error.stackTraceLimit = limit;");
5101 CompileRun("Array.prototype.pop = fail;");
5102 CompileRun("Object.prototype.hasOwnProperty = fail;");
5103 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5104 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5105 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5106 CompileRun("ReferenceError.prototype.toString ="
5107 " function() { return 'Whoops' }");
5108 CompileRun("asdf;");
5109 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5110 CompileRun("asdf;");
5111 CompileRun("ReferenceError.prototype.constructor = void 0;");
5112 CompileRun("asdf;");
5113 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5114 CompileRun("asdf;");
5115 CompileRun("ReferenceError.prototype = new Object();");
5116 CompileRun("asdf;");
5117 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5118 CHECK(string->Equals(v8_str("Whoops")));
5119 CompileRun("ReferenceError.prototype.constructor = new Object();"
5120 "ReferenceError.prototype.constructor.name = 1;"
5121 "Number.prototype.toString = function() { return 'Whoops'; };"
5122 "ReferenceError.prototype.toString = Object.prototype.toString;");
5123 CompileRun("asdf;");
5124 v8::V8::RemoveMessageListeners(check_reference_error_message);
5128 static void check_custom_error_tostring(
5129 v8::Handle<v8::Message> message,
5130 v8::Handle<v8::Value> data) {
5131 const char* uncaught_error = "Uncaught MyError toString";
5132 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5136 TEST(CustomErrorToString) {
5137 LocalContext context;
5138 v8::HandleScope scope(context->GetIsolate());
5139 v8::V8::AddMessageListener(check_custom_error_tostring);
5141 "function MyError(name, message) { "
5142 " this.name = name; "
5143 " this.message = message; "
5145 "MyError.prototype = Object.create(Error.prototype); "
5146 "MyError.prototype.toString = function() { "
5147 " return 'MyError toString'; "
5149 "throw new MyError('my name', 'my message'); ");
5150 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5154 static void check_custom_error_message(
5155 v8::Handle<v8::Message> message,
5156 v8::Handle<v8::Value> data) {
5157 const char* uncaught_error = "Uncaught MyError: my message";
5158 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5159 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5163 TEST(CustomErrorMessage) {
5164 LocalContext context;
5165 v8::HandleScope scope(context->GetIsolate());
5166 v8::V8::AddMessageListener(check_custom_error_message);
5170 "function MyError(msg) { "
5171 " this.name = 'MyError'; "
5172 " this.message = msg; "
5174 "MyError.prototype = new Error(); "
5175 "throw new MyError('my message'); ");
5179 "function MyError(msg) { "
5180 " this.name = 'MyError'; "
5181 " this.message = msg; "
5183 "inherits = function(childCtor, parentCtor) { "
5184 " function tempCtor() {}; "
5185 " tempCtor.prototype = parentCtor.prototype; "
5186 " childCtor.superClass_ = parentCtor.prototype; "
5187 " childCtor.prototype = new tempCtor(); "
5188 " childCtor.prototype.constructor = childCtor; "
5190 "inherits(MyError, Error); "
5191 "throw new MyError('my message'); ");
5195 "function MyError(msg) { "
5196 " this.name = 'MyError'; "
5197 " this.message = msg; "
5199 "MyError.prototype = Object.create(Error.prototype); "
5200 "throw new MyError('my message'); ");
5202 v8::V8::RemoveMessageListeners(check_custom_error_message);
5206 static void receive_message(v8::Handle<v8::Message> message,
5207 v8::Handle<v8::Value> data) {
5209 message_received = true;
5213 TEST(APIThrowMessage) {
5214 message_received = false;
5215 v8::Isolate* isolate = CcTest::isolate();
5216 v8::HandleScope scope(isolate);
5217 v8::V8::AddMessageListener(receive_message);
5218 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5219 templ->Set(v8_str("ThrowFromC"),
5220 v8::FunctionTemplate::New(isolate, ThrowFromC));
5221 LocalContext context(0, templ);
5222 CompileRun("ThrowFromC();");
5223 CHECK(message_received);
5224 v8::V8::RemoveMessageListeners(receive_message);
5228 TEST(APIThrowMessageAndVerboseTryCatch) {
5229 message_received = false;
5230 v8::Isolate* isolate = CcTest::isolate();
5231 v8::HandleScope scope(isolate);
5232 v8::V8::AddMessageListener(receive_message);
5233 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5234 templ->Set(v8_str("ThrowFromC"),
5235 v8::FunctionTemplate::New(isolate, ThrowFromC));
5236 LocalContext context(0, templ);
5237 v8::TryCatch try_catch;
5238 try_catch.SetVerbose(true);
5239 Local<Value> result = CompileRun("ThrowFromC();");
5240 CHECK(try_catch.HasCaught());
5241 CHECK(result.IsEmpty());
5242 CHECK(message_received);
5243 v8::V8::RemoveMessageListeners(receive_message);
5247 TEST(APIStackOverflowAndVerboseTryCatch) {
5248 message_received = false;
5249 LocalContext context;
5250 v8::HandleScope scope(context->GetIsolate());
5251 v8::V8::AddMessageListener(receive_message);
5252 v8::TryCatch try_catch;
5253 try_catch.SetVerbose(true);
5254 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5255 CHECK(try_catch.HasCaught());
5256 CHECK(result.IsEmpty());
5257 CHECK(message_received);
5258 v8::V8::RemoveMessageListeners(receive_message);
5262 THREADED_TEST(ExternalScriptException) {
5263 v8::Isolate* isolate = CcTest::isolate();
5264 v8::HandleScope scope(isolate);
5265 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5266 templ->Set(v8_str("ThrowFromC"),
5267 v8::FunctionTemplate::New(isolate, ThrowFromC));
5268 LocalContext context(0, templ);
5270 v8::TryCatch try_catch;
5271 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5272 CHECK(result.IsEmpty());
5273 CHECK(try_catch.HasCaught());
5274 String::Utf8Value exception_value(try_catch.Exception());
5275 CHECK_EQ("konto", *exception_value);
5280 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5281 ApiTestFuzzer::Fuzz();
5282 CHECK_EQ(4, args.Length());
5283 int count = args[0]->Int32Value();
5284 int cInterval = args[2]->Int32Value();
5286 args.GetIsolate()->ThrowException(v8_str("FromC"));
5289 Local<v8::Object> global =
5290 args.GetIsolate()->GetCurrentContext()->Global();
5291 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5292 v8::Handle<Value> argv[] = { v8_num(count - 1),
5296 if (count % cInterval == 0) {
5297 v8::TryCatch try_catch;
5298 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5299 int expected = args[3]->Int32Value();
5300 if (try_catch.HasCaught()) {
5301 CHECK_EQ(expected, count);
5302 CHECK(result.IsEmpty());
5303 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5305 CHECK_NE(expected, count);
5307 args.GetReturnValue().Set(result);
5310 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5317 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5318 ApiTestFuzzer::Fuzz();
5319 CHECK_EQ(3, args.Length());
5320 bool equality = args[0]->BooleanValue();
5321 int count = args[1]->Int32Value();
5322 int expected = args[2]->Int32Value();
5324 CHECK_EQ(count, expected);
5326 CHECK_NE(count, expected);
5331 THREADED_TEST(EvalInTryFinally) {
5332 LocalContext context;
5333 v8::HandleScope scope(context->GetIsolate());
5334 v8::TryCatch try_catch;
5335 CompileRun("(function() {"
5337 " eval('asldkf (*&^&*^');"
5342 CHECK(!try_catch.HasCaught());
5346 // This test works by making a stack of alternating JavaScript and C
5347 // activations. These activations set up exception handlers with regular
5348 // intervals, one interval for C activations and another for JavaScript
5349 // activations. When enough activations have been created an exception is
5350 // thrown and we check that the right activation catches the exception and that
5351 // no other activations do. The right activation is always the topmost one with
5352 // a handler, regardless of whether it is in JavaScript or C.
5354 // The notation used to describe a test case looks like this:
5356 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5358 // Each entry is an activation, either JS or C. The index is the count at that
5359 // level. Stars identify activations with exception handlers, the @ identifies
5360 // the exception handler that should catch the exception.
5362 // BUG(271): Some of the exception propagation does not work on the
5363 // ARM simulator because the simulator separates the C++ stack and the
5364 // JS stack. This test therefore fails on the simulator. The test is
5365 // not threaded to allow the threading tests to run on the simulator.
5366 TEST(ExceptionOrder) {
5367 v8::Isolate* isolate = CcTest::isolate();
5368 v8::HandleScope scope(isolate);
5369 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5370 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5371 templ->Set(v8_str("CThrowCountDown"),
5372 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5373 LocalContext context(0, templ);
5375 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5376 " if (count == 0) throw 'FromJS';"
5377 " if (count % jsInterval == 0) {"
5379 " var value = CThrowCountDown(count - 1,"
5383 " check(false, count, expected);"
5386 " check(true, count, expected);"
5389 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5392 Local<Function> fun =
5393 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5396 // count jsInterval cInterval expected
5398 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5399 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5400 fun->Call(fun, argc, a0);
5402 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5403 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5404 fun->Call(fun, argc, a1);
5406 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5407 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5408 fun->Call(fun, argc, a2);
5410 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5411 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5412 fun->Call(fun, argc, a3);
5414 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5415 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5416 fun->Call(fun, argc, a4);
5418 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5419 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5420 fun->Call(fun, argc, a5);
5424 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5425 ApiTestFuzzer::Fuzz();
5426 CHECK_EQ(1, args.Length());
5427 args.GetIsolate()->ThrowException(args[0]);
5431 THREADED_TEST(ThrowValues) {
5432 v8::Isolate* isolate = CcTest::isolate();
5433 v8::HandleScope scope(isolate);
5434 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5435 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5436 LocalContext context(0, templ);
5437 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5438 "function Run(obj) {"
5444 " return 'no exception';"
5446 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5447 CHECK_EQ(5, result->Length());
5448 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5449 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5450 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5451 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5452 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5453 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5454 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5458 THREADED_TEST(CatchZero) {
5459 LocalContext context;
5460 v8::HandleScope scope(context->GetIsolate());
5461 v8::TryCatch try_catch;
5462 CHECK(!try_catch.HasCaught());
5463 CompileRun("throw 10");
5464 CHECK(try_catch.HasCaught());
5465 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5467 CHECK(!try_catch.HasCaught());
5468 CompileRun("throw 0");
5469 CHECK(try_catch.HasCaught());
5470 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5474 THREADED_TEST(CatchExceptionFromWith) {
5475 LocalContext context;
5476 v8::HandleScope scope(context->GetIsolate());
5477 v8::TryCatch try_catch;
5478 CHECK(!try_catch.HasCaught());
5479 CompileRun("var o = {}; with (o) { throw 42; }");
5480 CHECK(try_catch.HasCaught());
5484 THREADED_TEST(TryCatchAndFinallyHidingException) {
5485 LocalContext context;
5486 v8::HandleScope scope(context->GetIsolate());
5487 v8::TryCatch try_catch;
5488 CHECK(!try_catch.HasCaught());
5489 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5490 CompileRun("f({toString: function() { throw 42; }});");
5491 CHECK(!try_catch.HasCaught());
5495 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5496 v8::TryCatch try_catch;
5500 THREADED_TEST(TryCatchAndFinally) {
5501 LocalContext context;
5502 v8::Isolate* isolate = context->GetIsolate();
5503 v8::HandleScope scope(isolate);
5504 context->Global()->Set(
5505 v8_str("native_with_try_catch"),
5506 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5507 v8::TryCatch try_catch;
5508 CHECK(!try_catch.HasCaught());
5511 " throw new Error('a');\n"
5513 " native_with_try_catch();\n"
5515 CHECK(try_catch.HasCaught());
5519 static void TryCatchNested1Helper(int depth) {
5521 v8::TryCatch try_catch;
5522 try_catch.SetVerbose(true);
5523 TryCatchNested1Helper(depth - 1);
5524 CHECK(try_catch.HasCaught());
5525 try_catch.ReThrow();
5527 CcTest::isolate()->ThrowException(v8_str("E1"));
5532 static void TryCatchNested2Helper(int depth) {
5534 v8::TryCatch try_catch;
5535 try_catch.SetVerbose(true);
5536 TryCatchNested2Helper(depth - 1);
5537 CHECK(try_catch.HasCaught());
5538 try_catch.ReThrow();
5540 CompileRun("throw 'E2';");
5545 TEST(TryCatchNested) {
5546 v8::V8::Initialize();
5547 LocalContext context;
5548 v8::HandleScope scope(context->GetIsolate());
5551 // Test nested try-catch with a native throw in the end.
5552 v8::TryCatch try_catch;
5553 TryCatchNested1Helper(5);
5554 CHECK(try_catch.HasCaught());
5555 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5559 // Test nested try-catch with a JavaScript throw in the end.
5560 v8::TryCatch try_catch;
5561 TryCatchNested2Helper(5);
5562 CHECK(try_catch.HasCaught());
5563 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5568 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5569 CHECK(try_catch->HasCaught());
5570 Handle<Message> message = try_catch->Message();
5571 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5572 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5573 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5574 "Uncaught Error: a"));
5575 CHECK_EQ(1, message->GetLineNumber());
5576 CHECK_EQ(6, message->GetStartColumn());
5580 void TryCatchMixedNestingHelper(
5581 const v8::FunctionCallbackInfo<v8::Value>& args) {
5582 ApiTestFuzzer::Fuzz();
5583 v8::TryCatch try_catch;
5584 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5585 CHECK(try_catch.HasCaught());
5586 TryCatchMixedNestingCheck(&try_catch);
5587 try_catch.ReThrow();
5591 // This test ensures that an outer TryCatch in the following situation:
5592 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5593 // does not clobber the Message object generated for the inner TryCatch.
5594 // This exercises the ability of TryCatch.ReThrow() to restore the
5595 // inner pending Message before throwing the exception again.
5596 TEST(TryCatchMixedNesting) {
5597 v8::Isolate* isolate = CcTest::isolate();
5598 v8::HandleScope scope(isolate);
5599 v8::V8::Initialize();
5600 v8::TryCatch try_catch;
5601 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5602 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5603 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5604 LocalContext context(0, templ);
5605 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5606 TryCatchMixedNestingCheck(&try_catch);
5610 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5611 ApiTestFuzzer::Fuzz();
5612 v8::TryCatch try_catch;
5613 args.GetIsolate()->ThrowException(v8_str("boom"));
5614 CHECK(try_catch.HasCaught());
5618 TEST(TryCatchNative) {
5619 v8::Isolate* isolate = CcTest::isolate();
5620 v8::HandleScope scope(isolate);
5621 v8::V8::Initialize();
5622 v8::TryCatch try_catch;
5623 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5624 templ->Set(v8_str("TryCatchNativeHelper"),
5625 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5626 LocalContext context(0, templ);
5627 CompileRun("TryCatchNativeHelper();");
5628 CHECK(!try_catch.HasCaught());
5632 void TryCatchNativeResetHelper(
5633 const v8::FunctionCallbackInfo<v8::Value>& args) {
5634 ApiTestFuzzer::Fuzz();
5635 v8::TryCatch try_catch;
5636 args.GetIsolate()->ThrowException(v8_str("boom"));
5637 CHECK(try_catch.HasCaught());
5639 CHECK(!try_catch.HasCaught());
5643 TEST(TryCatchNativeReset) {
5644 v8::Isolate* isolate = CcTest::isolate();
5645 v8::HandleScope scope(isolate);
5646 v8::V8::Initialize();
5647 v8::TryCatch try_catch;
5648 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5649 templ->Set(v8_str("TryCatchNativeResetHelper"),
5650 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5651 LocalContext context(0, templ);
5652 CompileRun("TryCatchNativeResetHelper();");
5653 CHECK(!try_catch.HasCaught());
5657 THREADED_TEST(Equality) {
5658 LocalContext context;
5659 v8::Isolate* isolate = context->GetIsolate();
5660 v8::HandleScope scope(context->GetIsolate());
5661 // Check that equality works at all before relying on CHECK_EQ
5662 CHECK(v8_str("a")->Equals(v8_str("a")));
5663 CHECK(!v8_str("a")->Equals(v8_str("b")));
5665 CHECK_EQ(v8_str("a"), v8_str("a"));
5666 CHECK_NE(v8_str("a"), v8_str("b"));
5667 CHECK_EQ(v8_num(1), v8_num(1));
5668 CHECK_EQ(v8_num(1.00), v8_num(1));
5669 CHECK_NE(v8_num(1), v8_num(2));
5671 // Assume String is not internalized.
5672 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5673 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5674 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5675 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5676 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5677 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5678 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5679 CHECK(!not_a_number->StrictEquals(not_a_number));
5680 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5681 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5683 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5684 v8::Persistent<v8::Object> alias(isolate, obj);
5685 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5688 CHECK(v8_str("a")->SameValue(v8_str("a")));
5689 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5690 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5691 CHECK(v8_num(1)->SameValue(v8_num(1)));
5692 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5693 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5694 CHECK(not_a_number->SameValue(not_a_number));
5695 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5696 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5700 THREADED_TEST(MultiRun) {
5701 LocalContext context;
5702 v8::HandleScope scope(context->GetIsolate());
5703 Local<Script> script = v8_compile("x");
5704 for (int i = 0; i < 10; i++)
5709 static void GetXValue(Local<String> name,
5710 const v8::PropertyCallbackInfo<v8::Value>& info) {
5711 ApiTestFuzzer::Fuzz();
5712 CHECK_EQ(info.Data(), v8_str("donut"));
5713 CHECK_EQ(name, v8_str("x"));
5714 info.GetReturnValue().Set(name);
5718 THREADED_TEST(SimplePropertyRead) {
5719 LocalContext context;
5720 v8::Isolate* isolate = context->GetIsolate();
5721 v8::HandleScope scope(isolate);
5722 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5723 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5724 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5725 Local<Script> script = v8_compile("obj.x");
5726 for (int i = 0; i < 10; i++) {
5727 Local<Value> result = script->Run();
5728 CHECK_EQ(result, v8_str("x"));
5733 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5734 LocalContext context;
5735 v8::Isolate* isolate = context->GetIsolate();
5736 v8::HandleScope scope(isolate);
5737 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5738 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5739 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5741 // Uses getOwnPropertyDescriptor to check the configurable status
5742 Local<Script> script_desc = v8_compile(
5743 "var prop = Object.getOwnPropertyDescriptor( "
5745 "prop.configurable;");
5746 Local<Value> result = script_desc->Run();
5747 CHECK_EQ(result->BooleanValue(), true);
5749 // Redefine get - but still configurable
5750 Local<Script> script_define = v8_compile(
5751 "var desc = { get: function(){return 42; },"
5752 " configurable: true };"
5753 "Object.defineProperty(obj, 'x', desc);"
5755 result = script_define->Run();
5756 CHECK_EQ(result, v8_num(42));
5758 // Check that the accessor is still configurable
5759 result = script_desc->Run();
5760 CHECK_EQ(result->BooleanValue(), true);
5762 // Redefine to a non-configurable
5763 script_define = v8_compile(
5764 "var desc = { get: function(){return 43; },"
5765 " configurable: false };"
5766 "Object.defineProperty(obj, 'x', desc);"
5768 result = script_define->Run();
5769 CHECK_EQ(result, v8_num(43));
5770 result = script_desc->Run();
5771 CHECK_EQ(result->BooleanValue(), false);
5773 // Make sure that it is not possible to redefine again
5774 v8::TryCatch try_catch;
5775 result = script_define->Run();
5776 CHECK(try_catch.HasCaught());
5777 String::Utf8Value exception_value(try_catch.Exception());
5778 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5782 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5783 v8::Isolate* isolate = CcTest::isolate();
5784 v8::HandleScope scope(isolate);
5785 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5786 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5787 LocalContext context;
5788 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5790 Local<Script> script_desc = v8_compile(
5792 "Object.getOwnPropertyDescriptor( "
5794 "prop.configurable;");
5795 Local<Value> result = script_desc->Run();
5796 CHECK_EQ(result->BooleanValue(), true);
5798 Local<Script> script_define = v8_compile(
5799 "var desc = {get: function(){return 42; },"
5800 " configurable: true };"
5801 "Object.defineProperty(obj, 'x', desc);"
5803 result = script_define->Run();
5804 CHECK_EQ(result, v8_num(42));
5807 result = script_desc->Run();
5808 CHECK_EQ(result->BooleanValue(), true);
5811 script_define = v8_compile(
5812 "var desc = {get: function(){return 43; },"
5813 " configurable: false };"
5814 "Object.defineProperty(obj, 'x', desc);"
5816 result = script_define->Run();
5817 CHECK_EQ(result, v8_num(43));
5818 result = script_desc->Run();
5820 CHECK_EQ(result->BooleanValue(), false);
5822 v8::TryCatch try_catch;
5823 result = script_define->Run();
5824 CHECK(try_catch.HasCaught());
5825 String::Utf8Value exception_value(try_catch.Exception());
5826 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5830 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5832 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5836 THREADED_TEST(DefineAPIAccessorOnObject) {
5837 v8::Isolate* isolate = CcTest::isolate();
5838 v8::HandleScope scope(isolate);
5839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840 LocalContext context;
5842 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5843 CompileRun("var obj2 = {};");
5845 CHECK(CompileRun("obj1.x")->IsUndefined());
5846 CHECK(CompileRun("obj2.x")->IsUndefined());
5848 CHECK(GetGlobalProperty(&context, "obj1")->
5849 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5851 ExpectString("obj1.x", "x");
5852 CHECK(CompileRun("obj2.x")->IsUndefined());
5854 CHECK(GetGlobalProperty(&context, "obj2")->
5855 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5857 ExpectString("obj1.x", "x");
5858 ExpectString("obj2.x", "x");
5860 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5861 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5863 CompileRun("Object.defineProperty(obj1, 'x',"
5864 "{ get: function() { return 'y'; }, configurable: true })");
5866 ExpectString("obj1.x", "y");
5867 ExpectString("obj2.x", "x");
5869 CompileRun("Object.defineProperty(obj2, 'x',"
5870 "{ get: function() { return 'y'; }, configurable: true })");
5872 ExpectString("obj1.x", "y");
5873 ExpectString("obj2.x", "y");
5875 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5876 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5878 CHECK(GetGlobalProperty(&context, "obj1")->
5879 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5880 CHECK(GetGlobalProperty(&context, "obj2")->
5881 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5883 ExpectString("obj1.x", "x");
5884 ExpectString("obj2.x", "x");
5886 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5887 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5889 // Define getters/setters, but now make them not configurable.
5890 CompileRun("Object.defineProperty(obj1, 'x',"
5891 "{ get: function() { return 'z'; }, configurable: false })");
5892 CompileRun("Object.defineProperty(obj2, 'x',"
5893 "{ get: function() { return 'z'; }, configurable: false })");
5895 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5896 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5898 ExpectString("obj1.x", "z");
5899 ExpectString("obj2.x", "z");
5901 CHECK(!GetGlobalProperty(&context, "obj1")->
5902 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5903 CHECK(!GetGlobalProperty(&context, "obj2")->
5904 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5906 ExpectString("obj1.x", "z");
5907 ExpectString("obj2.x", "z");
5911 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5912 v8::Isolate* isolate = CcTest::isolate();
5913 v8::HandleScope scope(isolate);
5914 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5915 LocalContext context;
5917 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5918 CompileRun("var obj2 = {};");
5920 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5923 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5924 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5927 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5929 ExpectString("obj1.x", "x");
5930 ExpectString("obj2.x", "x");
5932 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5933 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5935 CHECK(!GetGlobalProperty(&context, "obj1")->
5936 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5937 CHECK(!GetGlobalProperty(&context, "obj2")->
5938 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5941 v8::TryCatch try_catch;
5942 CompileRun("Object.defineProperty(obj1, 'x',"
5943 "{get: function() { return 'func'; }})");
5944 CHECK(try_catch.HasCaught());
5945 String::Utf8Value exception_value(try_catch.Exception());
5946 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5949 v8::TryCatch try_catch;
5950 CompileRun("Object.defineProperty(obj2, 'x',"
5951 "{get: function() { return 'func'; }})");
5952 CHECK(try_catch.HasCaught());
5953 String::Utf8Value exception_value(try_catch.Exception());
5954 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5959 static void Get239Value(Local<String> name,
5960 const v8::PropertyCallbackInfo<v8::Value>& info) {
5961 ApiTestFuzzer::Fuzz();
5962 CHECK_EQ(info.Data(), v8_str("donut"));
5963 CHECK_EQ(name, v8_str("239"));
5964 info.GetReturnValue().Set(name);
5968 THREADED_TEST(ElementAPIAccessor) {
5969 v8::Isolate* isolate = CcTest::isolate();
5970 v8::HandleScope scope(isolate);
5971 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5972 LocalContext context;
5974 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5975 CompileRun("var obj2 = {};");
5977 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5981 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5986 ExpectString("obj1[239]", "239");
5987 ExpectString("obj2[239]", "239");
5988 ExpectString("obj1['239']", "239");
5989 ExpectString("obj2['239']", "239");
5993 v8::Persistent<Value> xValue;
5996 static void SetXValue(Local<String> name,
5998 const v8::PropertyCallbackInfo<void>& info) {
5999 CHECK_EQ(value, v8_num(4));
6000 CHECK_EQ(info.Data(), v8_str("donut"));
6001 CHECK_EQ(name, v8_str("x"));
6002 CHECK(xValue.IsEmpty());
6003 xValue.Reset(info.GetIsolate(), value);
6007 THREADED_TEST(SimplePropertyWrite) {
6008 v8::Isolate* isolate = CcTest::isolate();
6009 v8::HandleScope scope(isolate);
6010 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6011 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6012 LocalContext context;
6013 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6014 Local<Script> script = v8_compile("obj.x = 4");
6015 for (int i = 0; i < 10; i++) {
6016 CHECK(xValue.IsEmpty());
6018 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6024 THREADED_TEST(SetterOnly) {
6025 v8::Isolate* isolate = CcTest::isolate();
6026 v8::HandleScope scope(isolate);
6027 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6028 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6029 LocalContext context;
6030 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6031 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6032 for (int i = 0; i < 10; i++) {
6033 CHECK(xValue.IsEmpty());
6035 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6041 THREADED_TEST(NoAccessors) {
6042 v8::Isolate* isolate = CcTest::isolate();
6043 v8::HandleScope scope(isolate);
6044 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6045 templ->SetAccessor(v8_str("x"),
6046 static_cast<v8::AccessorGetterCallback>(NULL),
6049 LocalContext context;
6050 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6051 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6052 for (int i = 0; i < 10; i++) {
6058 static void XPropertyGetter(Local<String> property,
6059 const v8::PropertyCallbackInfo<v8::Value>& info) {
6060 ApiTestFuzzer::Fuzz();
6061 CHECK(info.Data()->IsUndefined());
6062 info.GetReturnValue().Set(property);
6066 THREADED_TEST(NamedInterceptorPropertyRead) {
6067 v8::Isolate* isolate = CcTest::isolate();
6068 v8::HandleScope scope(isolate);
6069 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6070 templ->SetNamedPropertyHandler(XPropertyGetter);
6071 LocalContext context;
6072 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6073 Local<Script> script = v8_compile("obj.x");
6074 for (int i = 0; i < 10; i++) {
6075 Local<Value> result = script->Run();
6076 CHECK_EQ(result, v8_str("x"));
6081 THREADED_TEST(NamedInterceptorDictionaryIC) {
6082 v8::Isolate* isolate = CcTest::isolate();
6083 v8::HandleScope scope(isolate);
6084 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6085 templ->SetNamedPropertyHandler(XPropertyGetter);
6086 LocalContext context;
6087 // Create an object with a named interceptor.
6088 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6089 Local<Script> script = v8_compile("interceptor_obj.x");
6090 for (int i = 0; i < 10; i++) {
6091 Local<Value> result = script->Run();
6092 CHECK_EQ(result, v8_str("x"));
6094 // Create a slow case object and a function accessing a property in
6095 // that slow case object (with dictionary probing in generated
6096 // code). Then force object with a named interceptor into slow-case,
6097 // pass it to the function, and check that the interceptor is called
6098 // instead of accessing the local property.
6099 Local<Value> result =
6100 CompileRun("function get_x(o) { return o.x; };"
6101 "var obj = { x : 42, y : 0 };"
6103 "for (var i = 0; i < 10; i++) get_x(obj);"
6104 "interceptor_obj.x = 42;"
6105 "interceptor_obj.y = 10;"
6106 "delete interceptor_obj.y;"
6107 "get_x(interceptor_obj)");
6108 CHECK_EQ(result, v8_str("x"));
6112 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6113 v8::Isolate* isolate = CcTest::isolate();
6114 v8::HandleScope scope(isolate);
6115 v8::Local<Context> context1 = Context::New(isolate);
6118 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6119 templ->SetNamedPropertyHandler(XPropertyGetter);
6120 // Create an object with a named interceptor.
6121 v8::Local<v8::Object> object = templ->NewInstance();
6122 context1->Global()->Set(v8_str("interceptor_obj"), object);
6124 // Force the object into the slow case.
6125 CompileRun("interceptor_obj.y = 0;"
6126 "delete interceptor_obj.y;");
6130 // Introduce the object into a different context.
6131 // Repeat named loads to exercise ICs.
6132 LocalContext context2;
6133 context2->Global()->Set(v8_str("interceptor_obj"), object);
6134 Local<Value> result =
6135 CompileRun("function get_x(o) { return o.x; }"
6136 "interceptor_obj.x = 42;"
6137 "for (var i=0; i != 10; i++) {"
6138 " get_x(interceptor_obj);"
6140 "get_x(interceptor_obj)");
6141 // Check that the interceptor was actually invoked.
6142 CHECK_EQ(result, v8_str("x"));
6145 // Return to the original context and force some object to the slow case
6146 // to cause the NormalizedMapCache to verify.
6148 CompileRun("var obj = { x : 0 }; delete obj.x;");
6153 static void SetXOnPrototypeGetter(
6154 Local<String> property,
6155 const v8::PropertyCallbackInfo<v8::Value>& info) {
6156 // Set x on the prototype object and do not handle the get request.
6157 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6158 proto.As<v8::Object>()->Set(v8_str("x"),
6159 v8::Integer::New(info.GetIsolate(), 23));
6163 // This is a regression test for http://crbug.com/20104. Map
6164 // transitions should not interfere with post interceptor lookup.
6165 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6166 v8::Isolate* isolate = CcTest::isolate();
6167 v8::HandleScope scope(isolate);
6168 Local<v8::FunctionTemplate> function_template =
6169 v8::FunctionTemplate::New(isolate);
6170 Local<v8::ObjectTemplate> instance_template
6171 = function_template->InstanceTemplate();
6172 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6173 LocalContext context;
6174 context->Global()->Set(v8_str("F"), function_template->GetFunction());
6175 // Create an instance of F and introduce a map transition for x.
6176 CompileRun("var o = new F(); o.x = 23;");
6177 // Create an instance of F and invoke the getter. The result should be 23.
6178 Local<Value> result = CompileRun("o = new F(); o.x");
6179 CHECK_EQ(result->Int32Value(), 23);
6183 static void IndexedPropertyGetter(
6185 const v8::PropertyCallbackInfo<v8::Value>& info) {
6186 ApiTestFuzzer::Fuzz();
6188 info.GetReturnValue().Set(v8_num(625));
6193 static void IndexedPropertySetter(
6196 const v8::PropertyCallbackInfo<v8::Value>& info) {
6197 ApiTestFuzzer::Fuzz();
6199 info.GetReturnValue().Set(value);
6204 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6205 v8::Isolate* isolate = CcTest::isolate();
6206 v8::HandleScope scope(isolate);
6207 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6208 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6209 IndexedPropertySetter);
6210 LocalContext context;
6211 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6212 Local<Script> getter_script = v8_compile(
6213 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6214 Local<Script> setter_script = v8_compile(
6215 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6218 Local<Script> interceptor_setter_script = v8_compile(
6219 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6221 "obj.foo;"); // This setter should not run, due to the interceptor.
6222 Local<Script> interceptor_getter_script = v8_compile(
6224 Local<Value> result = getter_script->Run();
6225 CHECK_EQ(v8_num(5), result);
6226 result = setter_script->Run();
6227 CHECK_EQ(v8_num(23), result);
6228 result = interceptor_setter_script->Run();
6229 CHECK_EQ(v8_num(23), result);
6230 result = interceptor_getter_script->Run();
6231 CHECK_EQ(v8_num(625), result);
6235 static void UnboxedDoubleIndexedPropertyGetter(
6237 const v8::PropertyCallbackInfo<v8::Value>& info) {
6238 ApiTestFuzzer::Fuzz();
6240 info.GetReturnValue().Set(v8_num(index));
6245 static void UnboxedDoubleIndexedPropertySetter(
6248 const v8::PropertyCallbackInfo<v8::Value>& info) {
6249 ApiTestFuzzer::Fuzz();
6251 info.GetReturnValue().Set(v8_num(index));
6256 void UnboxedDoubleIndexedPropertyEnumerator(
6257 const v8::PropertyCallbackInfo<v8::Array>& info) {
6258 // Force the list of returned keys to be stored in a FastDoubleArray.
6259 Local<Script> indexed_property_names_script = v8_compile(
6260 "keys = new Array(); keys[125000] = 1;"
6261 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6262 "keys.length = 25; keys;");
6263 Local<Value> result = indexed_property_names_script->Run();
6264 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6268 // Make sure that the the interceptor code in the runtime properly handles
6269 // merging property name lists for double-array-backed arrays.
6270 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6271 v8::Isolate* isolate = CcTest::isolate();
6272 v8::HandleScope scope(isolate);
6273 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6274 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6275 UnboxedDoubleIndexedPropertySetter,
6278 UnboxedDoubleIndexedPropertyEnumerator);
6279 LocalContext context;
6280 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6281 // When obj is created, force it to be Stored in a FastDoubleArray.
6282 Local<Script> create_unboxed_double_script = v8_compile(
6283 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6285 "for (x in obj) {key_count++;};"
6287 Local<Value> result = create_unboxed_double_script->Run();
6288 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6289 Local<Script> key_count_check = v8_compile("key_count;");
6290 result = key_count_check->Run();
6291 CHECK_EQ(v8_num(40013), result);
6295 void SloppyArgsIndexedPropertyEnumerator(
6296 const v8::PropertyCallbackInfo<v8::Array>& info) {
6297 // Force the list of returned keys to be stored in a Arguments object.
6298 Local<Script> indexed_property_names_script = v8_compile(
6300 " return arguments;"
6302 "keys = f(0, 1, 2, 3);"
6304 Local<Object> result =
6305 Local<Object>::Cast(indexed_property_names_script->Run());
6306 // Have to populate the handle manually, as it's not Cast-able.
6307 i::Handle<i::JSObject> o =
6308 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6309 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6310 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6314 static void SloppyIndexedPropertyGetter(
6316 const v8::PropertyCallbackInfo<v8::Value>& info) {
6317 ApiTestFuzzer::Fuzz();
6319 info.GetReturnValue().Set(v8_num(index));
6324 // Make sure that the the interceptor code in the runtime properly handles
6325 // merging property name lists for non-string arguments arrays.
6326 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6327 v8::Isolate* isolate = CcTest::isolate();
6328 v8::HandleScope scope(isolate);
6329 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6330 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6334 SloppyArgsIndexedPropertyEnumerator);
6335 LocalContext context;
6336 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6337 Local<Script> create_args_script = v8_compile(
6338 "var key_count = 0;"
6339 "for (x in obj) {key_count++;} key_count;");
6340 Local<Value> result = create_args_script->Run();
6341 CHECK_EQ(v8_num(4), result);
6345 static void IdentityIndexedPropertyGetter(
6347 const v8::PropertyCallbackInfo<v8::Value>& info) {
6348 info.GetReturnValue().Set(index);
6352 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6353 v8::Isolate* isolate = CcTest::isolate();
6354 v8::HandleScope scope(isolate);
6355 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6356 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6358 LocalContext context;
6359 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6361 // Check fast object case.
6362 const char* fast_case_code =
6363 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6364 ExpectString(fast_case_code, "0");
6367 const char* slow_case_code =
6368 "obj.x = 1; delete obj.x;"
6369 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6370 ExpectString(slow_case_code, "1");
6374 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6375 v8::Isolate* isolate = CcTest::isolate();
6376 v8::HandleScope scope(isolate);
6377 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6378 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6380 LocalContext context;
6381 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6386 " for (var i = 0; i < 100; i++) {"
6388 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6394 ExpectString(code, "PASSED");
6398 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6399 v8::Isolate* isolate = CcTest::isolate();
6400 v8::HandleScope scope(isolate);
6401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6402 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6404 LocalContext context;
6405 Local<v8::Object> obj = templ->NewInstance();
6406 obj->TurnOnAccessCheck();
6407 context->Global()->Set(v8_str("obj"), obj);
6410 "var result = 'PASSED';"
6411 "for (var i = 0; i < 100; i++) {"
6414 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6421 ExpectString(code, "PASSED");
6425 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6426 i::FLAG_allow_natives_syntax = true;
6427 v8::Isolate* isolate = CcTest::isolate();
6428 v8::HandleScope scope(isolate);
6429 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6430 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6432 LocalContext context;
6433 Local<v8::Object> obj = templ->NewInstance();
6434 context->Global()->Set(v8_str("obj"), obj);
6437 "var result = 'PASSED';"
6438 "for (var i = 0; i < 100; i++) {"
6439 " var expected = i;"
6441 " %EnableAccessChecks(obj);"
6446 " result = 'Should not have reached this!';"
6448 " } else if (v != expected) {"
6449 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6457 " if (i == 5) %DisableAccessChecks(obj);"
6460 ExpectString(code, "PASSED");
6464 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6465 v8::Isolate* isolate = CcTest::isolate();
6466 v8::HandleScope scope(isolate);
6467 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6468 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6470 LocalContext context;
6471 Local<v8::Object> obj = templ->NewInstance();
6472 context->Global()->Set(v8_str("obj"), obj);
6476 " for (var i = 0; i < 100; i++) {"
6478 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6484 ExpectString(code, "PASSED");
6488 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6489 v8::Isolate* isolate = CcTest::isolate();
6490 v8::HandleScope scope(isolate);
6491 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6492 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6494 LocalContext context;
6495 Local<v8::Object> obj = templ->NewInstance();
6496 context->Global()->Set(v8_str("obj"), obj);
6500 " for (var i = 0; i < 100; i++) {"
6501 " var expected = i;"
6505 " expected = undefined;"
6508 " /* probe minimal Smi number on 32-bit platforms */"
6509 " key = -(1 << 30);"
6510 " expected = undefined;"
6513 " /* probe minimal Smi number on 64-bit platforms */"
6515 " expected = undefined;"
6517 " var v = obj[key];"
6518 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6524 ExpectString(code, "PASSED");
6528 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6529 v8::Isolate* isolate = CcTest::isolate();
6530 v8::HandleScope scope(isolate);
6531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6532 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6534 LocalContext context;
6535 Local<v8::Object> obj = templ->NewInstance();
6536 context->Global()->Set(v8_str("obj"), obj);
6540 " for (var i = 0; i < 100; i++) {"
6541 " var expected = i;"
6545 " expected = undefined;"
6547 " var v = obj[key];"
6548 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6554 ExpectString(code, "PASSED");
6558 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6559 v8::Isolate* isolate = CcTest::isolate();
6560 v8::HandleScope scope(isolate);
6561 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6562 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6564 LocalContext context;
6565 Local<v8::Object> obj = templ->NewInstance();
6566 context->Global()->Set(v8_str("obj"), obj);
6569 "var original = obj;"
6571 " for (var i = 0; i < 100; i++) {"
6572 " var expected = i;"
6574 " obj = {50: 'foobar'};"
6575 " expected = 'foobar';"
6578 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6579 " if (i == 50) obj = original;"
6585 ExpectString(code, "PASSED");
6589 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6590 v8::Isolate* isolate = CcTest::isolate();
6591 v8::HandleScope scope(isolate);
6592 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6593 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6595 LocalContext context;
6596 Local<v8::Object> obj = templ->NewInstance();
6597 context->Global()->Set(v8_str("obj"), obj);
6600 "var original = obj;"
6602 " for (var i = 0; i < 100; i++) {"
6603 " var expected = i;"
6606 " expected = undefined;"
6609 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6610 " if (i == 5) obj = original;"
6616 ExpectString(code, "PASSED");
6620 THREADED_TEST(IndexedInterceptorOnProto) {
6621 v8::Isolate* isolate = CcTest::isolate();
6622 v8::HandleScope scope(isolate);
6623 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6624 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6626 LocalContext context;
6627 Local<v8::Object> obj = templ->NewInstance();
6628 context->Global()->Set(v8_str("obj"), obj);
6631 "var o = {__proto__: obj};"
6633 " for (var i = 0; i < 100; i++) {"
6635 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6641 ExpectString(code, "PASSED");
6645 THREADED_TEST(MultiContexts) {
6646 v8::Isolate* isolate = CcTest::isolate();
6647 v8::HandleScope scope(isolate);
6648 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6649 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6652 Local<String> password = v8_str("Password");
6654 // Create an environment
6655 LocalContext context0(0, templ);
6656 context0->SetSecurityToken(password);
6657 v8::Handle<v8::Object> global0 = context0->Global();
6658 global0->Set(v8_str("custom"), v8_num(1234));
6659 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6661 // Create an independent environment
6662 LocalContext context1(0, templ);
6663 context1->SetSecurityToken(password);
6664 v8::Handle<v8::Object> global1 = context1->Global();
6665 global1->Set(v8_str("custom"), v8_num(1234));
6666 CHECK_NE(global0, global1);
6667 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6668 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6670 // Now create a new context with the old global
6671 LocalContext context2(0, templ, global1);
6672 context2->SetSecurityToken(password);
6673 v8::Handle<v8::Object> global2 = context2->Global();
6674 CHECK_EQ(global1, global2);
6675 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6676 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6680 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6681 // Make sure that functions created by cloning boilerplates cannot
6682 // communicate through their __proto__ field.
6684 v8::HandleScope scope(CcTest::isolate());
6687 v8::Handle<v8::Object> global0 =
6689 v8::Handle<v8::Object> object0 =
6690 global0->Get(v8_str("Object")).As<v8::Object>();
6691 v8::Handle<v8::Object> tostring0 =
6692 object0->Get(v8_str("toString")).As<v8::Object>();
6693 v8::Handle<v8::Object> proto0 =
6694 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6695 proto0->Set(v8_str("custom"), v8_num(1234));
6698 v8::Handle<v8::Object> global1 =
6700 v8::Handle<v8::Object> object1 =
6701 global1->Get(v8_str("Object")).As<v8::Object>();
6702 v8::Handle<v8::Object> tostring1 =
6703 object1->Get(v8_str("toString")).As<v8::Object>();
6704 v8::Handle<v8::Object> proto1 =
6705 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6706 CHECK(!proto1->Has(v8_str("custom")));
6710 THREADED_TEST(Regress892105) {
6711 // Make sure that object and array literals created by cloning
6712 // boilerplates cannot communicate through their __proto__
6713 // field. This is rather difficult to check, but we try to add stuff
6714 // to Object.prototype and Array.prototype and create a new
6715 // environment. This should succeed.
6717 v8::HandleScope scope(CcTest::isolate());
6719 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6720 "Array.prototype.arr = 4567;"
6724 Local<Script> script0 = v8_compile(source);
6725 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6728 Local<Script> script1 = v8_compile(source);
6729 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6733 THREADED_TEST(UndetectableObject) {
6735 v8::HandleScope scope(env->GetIsolate());
6737 Local<v8::FunctionTemplate> desc =
6738 v8::FunctionTemplate::New(env->GetIsolate());
6739 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6741 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6742 env->Global()->Set(v8_str("undetectable"), obj);
6744 ExpectString("undetectable.toString()", "[object Object]");
6745 ExpectString("typeof undetectable", "undefined");
6746 ExpectString("typeof(undetectable)", "undefined");
6747 ExpectBoolean("typeof undetectable == 'undefined'", true);
6748 ExpectBoolean("typeof undetectable == 'object'", false);
6749 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6750 ExpectBoolean("!undetectable", true);
6752 ExpectObject("true&&undetectable", obj);
6753 ExpectBoolean("false&&undetectable", false);
6754 ExpectBoolean("true||undetectable", true);
6755 ExpectObject("false||undetectable", obj);
6757 ExpectObject("undetectable&&true", obj);
6758 ExpectObject("undetectable&&false", obj);
6759 ExpectBoolean("undetectable||true", true);
6760 ExpectBoolean("undetectable||false", false);
6762 ExpectBoolean("undetectable==null", true);
6763 ExpectBoolean("null==undetectable", true);
6764 ExpectBoolean("undetectable==undefined", true);
6765 ExpectBoolean("undefined==undetectable", true);
6766 ExpectBoolean("undetectable==undetectable", true);
6769 ExpectBoolean("undetectable===null", false);
6770 ExpectBoolean("null===undetectable", false);
6771 ExpectBoolean("undetectable===undefined", false);
6772 ExpectBoolean("undefined===undetectable", false);
6773 ExpectBoolean("undetectable===undetectable", true);
6777 THREADED_TEST(VoidLiteral) {
6779 v8::Isolate* isolate = env->GetIsolate();
6780 v8::HandleScope scope(isolate);
6782 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6783 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6785 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6786 env->Global()->Set(v8_str("undetectable"), obj);
6788 ExpectBoolean("undefined == void 0", true);
6789 ExpectBoolean("undetectable == void 0", true);
6790 ExpectBoolean("null == void 0", true);
6791 ExpectBoolean("undefined === void 0", true);
6792 ExpectBoolean("undetectable === void 0", false);
6793 ExpectBoolean("null === void 0", false);
6795 ExpectBoolean("void 0 == undefined", true);
6796 ExpectBoolean("void 0 == undetectable", true);
6797 ExpectBoolean("void 0 == null", true);
6798 ExpectBoolean("void 0 === undefined", true);
6799 ExpectBoolean("void 0 === undetectable", false);
6800 ExpectBoolean("void 0 === null", false);
6802 ExpectString("(function() {"
6804 " return x === void 0;"
6806 " return e.toString();"
6809 "ReferenceError: x is not defined");
6810 ExpectString("(function() {"
6812 " return void 0 === x;"
6814 " return e.toString();"
6817 "ReferenceError: x is not defined");
6821 THREADED_TEST(ExtensibleOnUndetectable) {
6823 v8::Isolate* isolate = env->GetIsolate();
6824 v8::HandleScope scope(isolate);
6826 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6827 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6829 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6830 env->Global()->Set(v8_str("undetectable"), obj);
6832 Local<String> source = v8_str("undetectable.x = 42;"
6835 Local<Script> script = v8_compile(source);
6837 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6839 ExpectBoolean("Object.isExtensible(undetectable)", true);
6841 source = v8_str("Object.preventExtensions(undetectable);");
6842 script = v8_compile(source);
6844 ExpectBoolean("Object.isExtensible(undetectable)", false);
6846 source = v8_str("undetectable.y = 2000;");
6847 script = v8_compile(source);
6849 ExpectBoolean("undetectable.y == undefined", true);
6854 THREADED_TEST(UndetectableString) {
6856 v8::HandleScope scope(env->GetIsolate());
6858 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6859 String::kUndetectableString);
6860 env->Global()->Set(v8_str("undetectable"), obj);
6862 ExpectString("undetectable", "foo");
6863 ExpectString("typeof undetectable", "undefined");
6864 ExpectString("typeof(undetectable)", "undefined");
6865 ExpectBoolean("typeof undetectable == 'undefined'", true);
6866 ExpectBoolean("typeof undetectable == 'string'", false);
6867 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6868 ExpectBoolean("!undetectable", true);
6870 ExpectObject("true&&undetectable", obj);
6871 ExpectBoolean("false&&undetectable", false);
6872 ExpectBoolean("true||undetectable", true);
6873 ExpectObject("false||undetectable", obj);
6875 ExpectObject("undetectable&&true", obj);
6876 ExpectObject("undetectable&&false", obj);
6877 ExpectBoolean("undetectable||true", true);
6878 ExpectBoolean("undetectable||false", false);
6880 ExpectBoolean("undetectable==null", true);
6881 ExpectBoolean("null==undetectable", true);
6882 ExpectBoolean("undetectable==undefined", true);
6883 ExpectBoolean("undefined==undetectable", true);
6884 ExpectBoolean("undetectable==undetectable", true);
6887 ExpectBoolean("undetectable===null", false);
6888 ExpectBoolean("null===undetectable", false);
6889 ExpectBoolean("undetectable===undefined", false);
6890 ExpectBoolean("undefined===undetectable", false);
6891 ExpectBoolean("undetectable===undetectable", true);
6895 TEST(UndetectableOptimized) {
6896 i::FLAG_allow_natives_syntax = true;
6898 v8::HandleScope scope(env->GetIsolate());
6900 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6901 String::kUndetectableString);
6902 env->Global()->Set(v8_str("undetectable"), obj);
6903 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6906 "function testBranch() {"
6907 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6908 " if (%_IsUndetectableObject(detectable)) throw 2;"
6910 "function testBool() {"
6911 " var b1 = !%_IsUndetectableObject(undetectable);"
6912 " var b2 = %_IsUndetectableObject(detectable);"
6917 "%OptimizeFunctionOnNextCall(testBranch);"
6918 "%OptimizeFunctionOnNextCall(testBool);"
6919 "for (var i = 0; i < 10; i++) {"
6928 // The point of this test is type checking. We run it only so compilers
6929 // don't complain about an unused function.
6930 TEST(PersistentHandles) {
6932 v8::Isolate* isolate = CcTest::isolate();
6933 v8::HandleScope scope(isolate);
6934 Local<String> str = v8_str("foo");
6935 v8::Persistent<String> p_str(isolate, str);
6937 Local<Script> scr = v8_compile("");
6938 v8::Persistent<Script> p_scr(isolate, scr);
6940 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6941 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6946 static void HandleLogDelegator(
6947 const v8::FunctionCallbackInfo<v8::Value>& args) {
6948 ApiTestFuzzer::Fuzz();
6952 THREADED_TEST(GlobalObjectTemplate) {
6953 v8::Isolate* isolate = CcTest::isolate();
6954 v8::HandleScope handle_scope(isolate);
6955 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6956 global_template->Set(v8_str("JSNI_Log"),
6957 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6958 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6959 Context::Scope context_scope(context);
6960 CompileRun("JSNI_Log('LOG')");
6964 static const char* kSimpleExtensionSource =
6970 TEST(SimpleExtensions) {
6971 v8::HandleScope handle_scope(CcTest::isolate());
6972 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6973 const char* extension_names[] = { "simpletest" };
6974 v8::ExtensionConfiguration extensions(1, extension_names);
6975 v8::Handle<Context> context =
6976 Context::New(CcTest::isolate(), &extensions);
6977 Context::Scope lock(context);
6978 v8::Handle<Value> result = CompileRun("Foo()");
6979 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6983 static const char* kStackTraceFromExtensionSource =
6985 " throw new Error();"
6992 TEST(StackTraceInExtension) {
6993 v8::HandleScope handle_scope(CcTest::isolate());
6994 v8::RegisterExtension(new Extension("stacktracetest",
6995 kStackTraceFromExtensionSource));
6996 const char* extension_names[] = { "stacktracetest" };
6997 v8::ExtensionConfiguration extensions(1, extension_names);
6998 v8::Handle<Context> context =
6999 Context::New(CcTest::isolate(), &extensions);
7000 Context::Scope lock(context);
7001 CompileRun("function user() { bar(); }"
7003 "try{ user(); } catch (e) { error = e; }");
7004 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7005 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7006 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7010 TEST(NullExtensions) {
7011 v8::HandleScope handle_scope(CcTest::isolate());
7012 v8::RegisterExtension(new Extension("nulltest", NULL));
7013 const char* extension_names[] = { "nulltest" };
7014 v8::ExtensionConfiguration extensions(1, extension_names);
7015 v8::Handle<Context> context =
7016 Context::New(CcTest::isolate(), &extensions);
7017 Context::Scope lock(context);
7018 v8::Handle<Value> result = CompileRun("1+3");
7019 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7023 static const char* kEmbeddedExtensionSource =
7024 "function Ret54321(){return 54321;}~~@@$"
7025 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7026 static const int kEmbeddedExtensionSourceValidLen = 34;
7029 TEST(ExtensionMissingSourceLength) {
7030 v8::HandleScope handle_scope(CcTest::isolate());
7031 v8::RegisterExtension(new Extension("srclentest_fail",
7032 kEmbeddedExtensionSource));
7033 const char* extension_names[] = { "srclentest_fail" };
7034 v8::ExtensionConfiguration extensions(1, extension_names);
7035 v8::Handle<Context> context =
7036 Context::New(CcTest::isolate(), &extensions);
7037 CHECK_EQ(0, *context);
7041 TEST(ExtensionWithSourceLength) {
7042 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7043 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7044 v8::HandleScope handle_scope(CcTest::isolate());
7045 i::ScopedVector<char> extension_name(32);
7046 i::SNPrintF(extension_name, "ext #%d", source_len);
7047 v8::RegisterExtension(new Extension(extension_name.start(),
7048 kEmbeddedExtensionSource, 0, 0,
7050 const char* extension_names[1] = { extension_name.start() };
7051 v8::ExtensionConfiguration extensions(1, extension_names);
7052 v8::Handle<Context> context =
7053 Context::New(CcTest::isolate(), &extensions);
7054 if (source_len == kEmbeddedExtensionSourceValidLen) {
7055 Context::Scope lock(context);
7056 v8::Handle<Value> result = CompileRun("Ret54321()");
7057 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7059 // Anything but exactly the right length should fail to compile.
7060 CHECK_EQ(0, *context);
7066 static const char* kEvalExtensionSource1 =
7067 "function UseEval1() {"
7069 " return eval('x');"
7073 static const char* kEvalExtensionSource2 =
7077 " return eval('x');"
7079 " this.UseEval2 = e;"
7083 TEST(UseEvalFromExtension) {
7084 v8::HandleScope handle_scope(CcTest::isolate());
7085 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7086 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7087 const char* extension_names[] = { "evaltest1", "evaltest2" };
7088 v8::ExtensionConfiguration extensions(2, extension_names);
7089 v8::Handle<Context> context =
7090 Context::New(CcTest::isolate(), &extensions);
7091 Context::Scope lock(context);
7092 v8::Handle<Value> result = CompileRun("UseEval1()");
7093 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7094 result = CompileRun("UseEval2()");
7095 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7099 static const char* kWithExtensionSource1 =
7100 "function UseWith1() {"
7102 " with({x:87}) { return x; }"
7107 static const char* kWithExtensionSource2 =
7111 " with ({x:87}) { return x; }"
7113 " this.UseWith2 = e;"
7117 TEST(UseWithFromExtension) {
7118 v8::HandleScope handle_scope(CcTest::isolate());
7119 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7120 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7121 const char* extension_names[] = { "withtest1", "withtest2" };
7122 v8::ExtensionConfiguration extensions(2, extension_names);
7123 v8::Handle<Context> context =
7124 Context::New(CcTest::isolate(), &extensions);
7125 Context::Scope lock(context);
7126 v8::Handle<Value> result = CompileRun("UseWith1()");
7127 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7128 result = CompileRun("UseWith2()");
7129 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7133 TEST(AutoExtensions) {
7134 v8::HandleScope handle_scope(CcTest::isolate());
7135 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7136 extension->set_auto_enable(true);
7137 v8::RegisterExtension(extension);
7138 v8::Handle<Context> context =
7139 Context::New(CcTest::isolate());
7140 Context::Scope lock(context);
7141 v8::Handle<Value> result = CompileRun("Foo()");
7142 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7146 static const char* kSyntaxErrorInExtensionSource =
7150 // Test that a syntax error in an extension does not cause a fatal
7151 // error but results in an empty context.
7152 TEST(SyntaxErrorExtensions) {
7153 v8::HandleScope handle_scope(CcTest::isolate());
7154 v8::RegisterExtension(new Extension("syntaxerror",
7155 kSyntaxErrorInExtensionSource));
7156 const char* extension_names[] = { "syntaxerror" };
7157 v8::ExtensionConfiguration extensions(1, extension_names);
7158 v8::Handle<Context> context =
7159 Context::New(CcTest::isolate(), &extensions);
7160 CHECK(context.IsEmpty());
7164 static const char* kExceptionInExtensionSource =
7168 // Test that an exception when installing an extension does not cause
7169 // a fatal error but results in an empty context.
7170 TEST(ExceptionExtensions) {
7171 v8::HandleScope handle_scope(CcTest::isolate());
7172 v8::RegisterExtension(new Extension("exception",
7173 kExceptionInExtensionSource));
7174 const char* extension_names[] = { "exception" };
7175 v8::ExtensionConfiguration extensions(1, extension_names);
7176 v8::Handle<Context> context =
7177 Context::New(CcTest::isolate(), &extensions);
7178 CHECK(context.IsEmpty());
7182 static const char* kNativeCallInExtensionSource =
7183 "function call_runtime_last_index_of(x) {"
7184 " return %StringLastIndexOf(x, 'bob', 10);"
7188 static const char* kNativeCallTest =
7189 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7191 // Test that a native runtime calls are supported in extensions.
7192 TEST(NativeCallInExtensions) {
7193 v8::HandleScope handle_scope(CcTest::isolate());
7194 v8::RegisterExtension(new Extension("nativecall",
7195 kNativeCallInExtensionSource));
7196 const char* extension_names[] = { "nativecall" };
7197 v8::ExtensionConfiguration extensions(1, extension_names);
7198 v8::Handle<Context> context =
7199 Context::New(CcTest::isolate(), &extensions);
7200 Context::Scope lock(context);
7201 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7202 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7206 class NativeFunctionExtension : public Extension {
7208 NativeFunctionExtension(const char* name,
7210 v8::FunctionCallback fun = &Echo)
7211 : Extension(name, source),
7214 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7215 v8::Isolate* isolate,
7216 v8::Handle<v8::String> name) {
7217 return v8::FunctionTemplate::New(isolate, function_);
7220 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7221 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7224 v8::FunctionCallback function_;
7228 TEST(NativeFunctionDeclaration) {
7229 v8::HandleScope handle_scope(CcTest::isolate());
7230 const char* name = "nativedecl";
7231 v8::RegisterExtension(new NativeFunctionExtension(name,
7232 "native function foo();"));
7233 const char* extension_names[] = { name };
7234 v8::ExtensionConfiguration extensions(1, extension_names);
7235 v8::Handle<Context> context =
7236 Context::New(CcTest::isolate(), &extensions);
7237 Context::Scope lock(context);
7238 v8::Handle<Value> result = CompileRun("foo(42);");
7239 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7243 TEST(NativeFunctionDeclarationError) {
7244 v8::HandleScope handle_scope(CcTest::isolate());
7245 const char* name = "nativedeclerr";
7246 // Syntax error in extension code.
7247 v8::RegisterExtension(new NativeFunctionExtension(name,
7248 "native\nfunction foo();"));
7249 const char* extension_names[] = { name };
7250 v8::ExtensionConfiguration extensions(1, extension_names);
7251 v8::Handle<Context> context =
7252 Context::New(CcTest::isolate(), &extensions);
7253 CHECK(context.IsEmpty());
7257 TEST(NativeFunctionDeclarationErrorEscape) {
7258 v8::HandleScope handle_scope(CcTest::isolate());
7259 const char* name = "nativedeclerresc";
7260 // Syntax error in extension code - escape code in "native" means that
7261 // it's not treated as a keyword.
7262 v8::RegisterExtension(new NativeFunctionExtension(
7264 "nativ\\u0065 function foo();"));
7265 const char* extension_names[] = { name };
7266 v8::ExtensionConfiguration extensions(1, extension_names);
7267 v8::Handle<Context> context =
7268 Context::New(CcTest::isolate(), &extensions);
7269 CHECK(context.IsEmpty());
7273 static void CheckDependencies(const char* name, const char* expected) {
7274 v8::HandleScope handle_scope(CcTest::isolate());
7275 v8::ExtensionConfiguration config(1, &name);
7276 LocalContext context(&config);
7277 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7278 context->Global()->Get(v8_str("loaded")));
7289 THREADED_TEST(ExtensionDependency) {
7290 static const char* kEDeps[] = { "D" };
7291 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7292 static const char* kDDeps[] = { "B", "C" };
7293 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7294 static const char* kBCDeps[] = { "A" };
7295 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7296 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7297 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7298 CheckDependencies("A", "undefinedA");
7299 CheckDependencies("B", "undefinedAB");
7300 CheckDependencies("C", "undefinedAC");
7301 CheckDependencies("D", "undefinedABCD");
7302 CheckDependencies("E", "undefinedABCDE");
7303 v8::HandleScope handle_scope(CcTest::isolate());
7304 static const char* exts[2] = { "C", "E" };
7305 v8::ExtensionConfiguration config(2, exts);
7306 LocalContext context(&config);
7307 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7311 static const char* kExtensionTestScript =
7312 "native function A();"
7313 "native function B();"
7314 "native function C();"
7316 " if (i == 0) return A();"
7317 " if (i == 1) return B();"
7318 " if (i == 2) return C();"
7322 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7323 ApiTestFuzzer::Fuzz();
7324 if (args.IsConstructCall()) {
7325 args.This()->Set(v8_str("data"), args.Data());
7326 args.GetReturnValue().SetNull();
7329 args.GetReturnValue().Set(args.Data());
7333 class FunctionExtension : public Extension {
7335 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7336 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7337 v8::Isolate* isolate,
7338 v8::Handle<String> name);
7342 static int lookup_count = 0;
7343 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7344 v8::Isolate* isolate, v8::Handle<String> name) {
7346 if (name->Equals(v8_str("A"))) {
7347 return v8::FunctionTemplate::New(
7348 isolate, CallFun, v8::Integer::New(isolate, 8));
7349 } else if (name->Equals(v8_str("B"))) {
7350 return v8::FunctionTemplate::New(
7351 isolate, CallFun, v8::Integer::New(isolate, 7));
7352 } else if (name->Equals(v8_str("C"))) {
7353 return v8::FunctionTemplate::New(
7354 isolate, CallFun, v8::Integer::New(isolate, 6));
7356 return v8::Handle<v8::FunctionTemplate>();
7361 THREADED_TEST(FunctionLookup) {
7362 v8::RegisterExtension(new FunctionExtension());
7363 v8::HandleScope handle_scope(CcTest::isolate());
7364 static const char* exts[1] = { "functiontest" };
7365 v8::ExtensionConfiguration config(1, exts);
7366 LocalContext context(&config);
7367 CHECK_EQ(3, lookup_count);
7368 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7369 CompileRun("Foo(0)"));
7370 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7371 CompileRun("Foo(1)"));
7372 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7373 CompileRun("Foo(2)"));
7377 THREADED_TEST(NativeFunctionConstructCall) {
7378 v8::RegisterExtension(new FunctionExtension());
7379 v8::HandleScope handle_scope(CcTest::isolate());
7380 static const char* exts[1] = { "functiontest" };
7381 v8::ExtensionConfiguration config(1, exts);
7382 LocalContext context(&config);
7383 for (int i = 0; i < 10; i++) {
7384 // Run a few times to ensure that allocation of objects doesn't
7385 // change behavior of a constructor function.
7386 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7387 CompileRun("(new A()).data"));
7388 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7389 CompileRun("(new B()).data"));
7390 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7391 CompileRun("(new C()).data"));
7396 static const char* last_location;
7397 static const char* last_message;
7398 void StoringErrorCallback(const char* location, const char* message) {
7399 if (last_location == NULL) {
7400 last_location = location;
7401 last_message = message;
7406 // ErrorReporting creates a circular extensions configuration and
7407 // tests that the fatal error handler gets called. This renders V8
7408 // unusable and therefore this test cannot be run in parallel.
7409 TEST(ErrorReporting) {
7410 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7411 static const char* aDeps[] = { "B" };
7412 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7413 static const char* bDeps[] = { "A" };
7414 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7415 last_location = NULL;
7416 v8::ExtensionConfiguration config(1, bDeps);
7417 v8::Handle<Context> context =
7418 Context::New(CcTest::isolate(), &config);
7419 CHECK(context.IsEmpty());
7420 CHECK_NE(last_location, NULL);
7424 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7425 v8::Handle<Value> data) {
7426 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7427 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7428 message->GetScriptOrigin().ResourceName());
7429 message->GetLineNumber();
7430 message->GetSourceLine();
7434 THREADED_TEST(ErrorWithMissingScriptInfo) {
7435 LocalContext context;
7436 v8::HandleScope scope(context->GetIsolate());
7437 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7438 CompileRun("throw Error()");
7439 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7443 struct FlagAndPersistent {
7445 v8::Persistent<v8::Object> handle;
7449 static void DisposeAndSetFlag(
7450 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7451 data.GetParameter()->handle.Reset();
7452 data.GetParameter()->flag = true;
7456 THREADED_TEST(IndependentWeakHandle) {
7457 v8::Isolate* iso = CcTest::isolate();
7458 v8::HandleScope scope(iso);
7459 v8::Handle<Context> context = Context::New(iso);
7460 Context::Scope context_scope(context);
7462 FlagAndPersistent object_a, object_b;
7465 v8::HandleScope handle_scope(iso);
7466 object_a.handle.Reset(iso, v8::Object::New(iso));
7467 object_b.handle.Reset(iso, v8::Object::New(iso));
7470 object_a.flag = false;
7471 object_b.flag = false;
7472 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7473 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7474 CHECK(!object_b.handle.IsIndependent());
7475 object_a.handle.MarkIndependent();
7476 object_b.handle.MarkIndependent();
7477 CHECK(object_b.handle.IsIndependent());
7478 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7479 CHECK(object_a.flag);
7480 CHECK(object_b.flag);
7484 static void InvokeScavenge() {
7485 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7489 static void InvokeMarkSweep() {
7490 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7494 static void ForceScavenge(
7495 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7496 data.GetParameter()->handle.Reset();
7497 data.GetParameter()->flag = true;
7502 static void ForceMarkSweep(
7503 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7504 data.GetParameter()->handle.Reset();
7505 data.GetParameter()->flag = true;
7510 THREADED_TEST(GCFromWeakCallbacks) {
7511 v8::Isolate* isolate = CcTest::isolate();
7512 v8::HandleScope scope(isolate);
7513 v8::Handle<Context> context = Context::New(isolate);
7514 Context::Scope context_scope(context);
7516 static const int kNumberOfGCTypes = 2;
7517 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7519 Callback gc_forcing_callback[kNumberOfGCTypes] =
7520 {&ForceScavenge, &ForceMarkSweep};
7522 typedef void (*GCInvoker)();
7523 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7525 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7526 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7527 FlagAndPersistent object;
7529 v8::HandleScope handle_scope(isolate);
7530 object.handle.Reset(isolate, v8::Object::New(isolate));
7532 object.flag = false;
7533 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7534 object.handle.MarkIndependent();
7535 invoke_gc[outer_gc]();
7542 static void RevivingCallback(
7543 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7544 data.GetParameter()->handle.ClearWeak();
7545 data.GetParameter()->flag = true;
7549 THREADED_TEST(IndependentHandleRevival) {
7550 v8::Isolate* isolate = CcTest::isolate();
7551 v8::HandleScope scope(isolate);
7552 v8::Handle<Context> context = Context::New(isolate);
7553 Context::Scope context_scope(context);
7555 FlagAndPersistent object;
7557 v8::HandleScope handle_scope(isolate);
7558 v8::Local<v8::Object> o = v8::Object::New(isolate);
7559 object.handle.Reset(isolate, o);
7560 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7561 v8::Local<String> y_str = v8_str("y");
7562 o->Set(y_str, y_str);
7564 object.flag = false;
7565 object.handle.SetWeak(&object, &RevivingCallback);
7566 object.handle.MarkIndependent();
7567 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7569 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7571 v8::HandleScope handle_scope(isolate);
7572 v8::Local<v8::Object> o =
7573 v8::Local<v8::Object>::New(isolate, object.handle);
7574 v8::Local<String> y_str = v8_str("y");
7575 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7576 CHECK(o->Get(y_str)->Equals(y_str));
7581 v8::Handle<Function> args_fun;
7584 static void ArgumentsTestCallback(
7585 const v8::FunctionCallbackInfo<v8::Value>& args) {
7586 ApiTestFuzzer::Fuzz();
7587 v8::Isolate* isolate = args.GetIsolate();
7588 CHECK_EQ(args_fun, args.Callee());
7589 CHECK_EQ(3, args.Length());
7590 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7591 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7592 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7593 CHECK_EQ(v8::Undefined(isolate), args[3]);
7594 v8::HandleScope scope(args.GetIsolate());
7595 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7599 THREADED_TEST(Arguments) {
7600 v8::Isolate* isolate = CcTest::isolate();
7601 v8::HandleScope scope(isolate);
7602 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7603 global->Set(v8_str("f"),
7604 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7605 LocalContext context(NULL, global);
7606 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7607 v8_compile("f(1, 2, 3)")->Run();
7611 static void NoBlockGetterX(Local<String> name,
7612 const v8::PropertyCallbackInfo<v8::Value>&) {
7616 static void NoBlockGetterI(uint32_t index,
7617 const v8::PropertyCallbackInfo<v8::Value>&) {
7621 static void PDeleter(Local<String> name,
7622 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7623 if (!name->Equals(v8_str("foo"))) {
7624 return; // not intercepted
7627 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7631 static void IDeleter(uint32_t index,
7632 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7634 return; // not intercepted
7637 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7641 THREADED_TEST(Deleter) {
7642 v8::Isolate* isolate = CcTest::isolate();
7643 v8::HandleScope scope(isolate);
7644 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7645 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7646 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7647 LocalContext context;
7648 context->Global()->Set(v8_str("k"), obj->NewInstance());
7654 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7655 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7657 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7658 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7660 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7661 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7663 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7664 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7668 static void GetK(Local<String> name,
7669 const v8::PropertyCallbackInfo<v8::Value>& info) {
7670 ApiTestFuzzer::Fuzz();
7671 if (name->Equals(v8_str("foo")) ||
7672 name->Equals(v8_str("bar")) ||
7673 name->Equals(v8_str("baz"))) {
7674 info.GetReturnValue().SetUndefined();
7679 static void IndexedGetK(uint32_t index,
7680 const v8::PropertyCallbackInfo<v8::Value>& info) {
7681 ApiTestFuzzer::Fuzz();
7682 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7686 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7687 ApiTestFuzzer::Fuzz();
7688 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7689 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7690 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7691 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7692 info.GetReturnValue().Set(result);
7696 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7697 ApiTestFuzzer::Fuzz();
7698 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7699 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7700 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7701 info.GetReturnValue().Set(result);
7705 THREADED_TEST(Enumerators) {
7706 v8::Isolate* isolate = CcTest::isolate();
7707 v8::HandleScope scope(isolate);
7708 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7709 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7710 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7711 LocalContext context;
7712 context->Global()->Set(v8_str("k"), obj->NewInstance());
7713 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7718 "k[4294967295] = 0;"
7720 "k[4294967296] = 0;"
7724 "k[30000000000] = 0;"
7727 "for (var prop in k) {"
7728 " result.push(prop);"
7731 // Check that we get all the property names returned including the
7732 // ones from the enumerators in the right order: indexed properties
7733 // in numerical order, indexed interceptor properties, named
7734 // properties in insertion order, named interceptor properties.
7735 // This order is not mandated by the spec, so this test is just
7736 // documenting our behavior.
7737 CHECK_EQ(17, result->Length());
7738 // Indexed properties in numerical order.
7739 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7740 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7741 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7742 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7743 // Indexed interceptor properties in the order they are returned
7744 // from the enumerator interceptor.
7745 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7746 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7747 // Named properties in insertion order.
7748 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7749 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7750 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7751 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7752 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7753 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7754 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7755 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7756 // Named interceptor properties.
7757 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7758 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7759 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7764 int p_getter_count2;
7767 static void PGetter(Local<String> name,
7768 const v8::PropertyCallbackInfo<v8::Value>& info) {
7769 ApiTestFuzzer::Fuzz();
7771 v8::Handle<v8::Object> global =
7772 info.GetIsolate()->GetCurrentContext()->Global();
7773 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7774 if (name->Equals(v8_str("p1"))) {
7775 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7776 } else if (name->Equals(v8_str("p2"))) {
7777 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7778 } else if (name->Equals(v8_str("p3"))) {
7779 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7780 } else if (name->Equals(v8_str("p4"))) {
7781 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7786 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7787 ApiTestFuzzer::Fuzz();
7788 LocalContext context;
7789 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7791 "o1.__proto__ = { };"
7792 "var o2 = { __proto__: o1 };"
7793 "var o3 = { __proto__: o2 };"
7794 "var o4 = { __proto__: o3 };"
7795 "for (var i = 0; i < 10; i++) o4.p4;"
7796 "for (var i = 0; i < 10; i++) o3.p3;"
7797 "for (var i = 0; i < 10; i++) o2.p2;"
7798 "for (var i = 0; i < 10; i++) o1.p1;");
7802 static void PGetter2(Local<String> name,
7803 const v8::PropertyCallbackInfo<v8::Value>& info) {
7804 ApiTestFuzzer::Fuzz();
7806 v8::Handle<v8::Object> global =
7807 info.GetIsolate()->GetCurrentContext()->Global();
7808 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7809 if (name->Equals(v8_str("p1"))) {
7810 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7811 } else if (name->Equals(v8_str("p2"))) {
7812 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7813 } else if (name->Equals(v8_str("p3"))) {
7814 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7815 } else if (name->Equals(v8_str("p4"))) {
7816 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7821 THREADED_TEST(GetterHolders) {
7822 v8::Isolate* isolate = CcTest::isolate();
7823 v8::HandleScope scope(isolate);
7824 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7825 obj->SetAccessor(v8_str("p1"), PGetter);
7826 obj->SetAccessor(v8_str("p2"), PGetter);
7827 obj->SetAccessor(v8_str("p3"), PGetter);
7828 obj->SetAccessor(v8_str("p4"), PGetter);
7831 CHECK_EQ(40, p_getter_count);
7835 THREADED_TEST(PreInterceptorHolders) {
7836 v8::Isolate* isolate = CcTest::isolate();
7837 v8::HandleScope scope(isolate);
7838 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7839 obj->SetNamedPropertyHandler(PGetter2);
7840 p_getter_count2 = 0;
7842 CHECK_EQ(40, p_getter_count2);
7846 THREADED_TEST(ObjectInstantiation) {
7847 v8::Isolate* isolate = CcTest::isolate();
7848 v8::HandleScope scope(isolate);
7849 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7850 templ->SetAccessor(v8_str("t"), PGetter2);
7851 LocalContext context;
7852 context->Global()->Set(v8_str("o"), templ->NewInstance());
7853 for (int i = 0; i < 100; i++) {
7854 v8::HandleScope inner_scope(CcTest::isolate());
7855 v8::Handle<v8::Object> obj = templ->NewInstance();
7856 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7857 context->Global()->Set(v8_str("o2"), obj);
7858 v8::Handle<Value> value =
7859 CompileRun("o.__proto__ === o2.__proto__");
7860 CHECK_EQ(v8::True(isolate), value);
7861 context->Global()->Set(v8_str("o"), obj);
7866 static int StrCmp16(uint16_t* a, uint16_t* b) {
7868 if (*a == 0 && *b == 0) return 0;
7869 if (*a != *b) return 0 + *a - *b;
7876 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7878 if (n-- == 0) return 0;
7879 if (*a == 0 && *b == 0) return 0;
7880 if (*a != *b) return 0 + *a - *b;
7887 int GetUtf8Length(Handle<String> str) {
7888 int len = str->Utf8Length();
7890 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7891 i::String::Flatten(istr);
7892 len = str->Utf8Length();
7898 THREADED_TEST(StringWrite) {
7899 LocalContext context;
7900 v8::HandleScope scope(context->GetIsolate());
7901 v8::Handle<String> str = v8_str("abcde");
7902 // abc<Icelandic eth><Unicode snowman>.
7903 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7904 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7905 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7906 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7907 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7908 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7909 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7910 // single lead surrogate
7911 uint16_t lead[1] = { 0xd800 };
7912 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7913 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7914 // single trail surrogate
7915 uint16_t trail[1] = { 0xdc00 };
7916 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7917 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7919 uint16_t pair[2] = { 0xd800, 0xdc00 };
7920 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7921 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7922 const int kStride = 4; // Must match stride in for loops in JS below.
7925 "for (var i = 0; i < 0xd800; i += 4) {"
7926 " left = left + String.fromCharCode(i);"
7930 "for (var i = 0; i < 0xd800; i += 4) {"
7931 " right = String.fromCharCode(i) + right;"
7933 v8::Handle<v8::Object> global = context->Global();
7934 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7935 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7937 CHECK_EQ(5, str2->Length());
7938 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7939 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7942 char utf8buf[0xd800 * 3];
7947 memset(utf8buf, 0x1, 1000);
7948 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7950 CHECK_EQ(5, charlen);
7951 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7953 memset(utf8buf, 0x1, 1000);
7954 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7956 CHECK_EQ(5, charlen);
7957 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7959 memset(utf8buf, 0x1, 1000);
7960 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7962 CHECK_EQ(4, charlen);
7963 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7965 memset(utf8buf, 0x1, 1000);
7966 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7968 CHECK_EQ(4, charlen);
7969 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7971 memset(utf8buf, 0x1, 1000);
7972 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7974 CHECK_EQ(4, charlen);
7975 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7977 memset(utf8buf, 0x1, 1000);
7978 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7980 CHECK_EQ(3, charlen);
7981 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7983 memset(utf8buf, 0x1, 1000);
7984 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7986 CHECK_EQ(3, charlen);
7987 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7989 memset(utf8buf, 0x1, 1000);
7990 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7992 CHECK_EQ(2, charlen);
7993 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7995 // allow orphan surrogates by default
7996 memset(utf8buf, 0x1, 1000);
7997 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7999 CHECK_EQ(8, charlen);
8000 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8002 // replace orphan surrogates with unicode replacement character
8003 memset(utf8buf, 0x1, 1000);
8004 len = orphans_str->WriteUtf8(utf8buf,
8007 String::REPLACE_INVALID_UTF8);
8009 CHECK_EQ(8, charlen);
8010 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8012 // replace single lead surrogate with unicode replacement character
8013 memset(utf8buf, 0x1, 1000);
8014 len = lead_str->WriteUtf8(utf8buf,
8017 String::REPLACE_INVALID_UTF8);
8019 CHECK_EQ(1, charlen);
8020 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8022 // replace single trail surrogate with unicode replacement character
8023 memset(utf8buf, 0x1, 1000);
8024 len = trail_str->WriteUtf8(utf8buf,
8027 String::REPLACE_INVALID_UTF8);
8029 CHECK_EQ(1, charlen);
8030 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8032 // do not replace / write anything if surrogate pair does not fit the buffer
8034 memset(utf8buf, 0x1, 1000);
8035 len = pair_str->WriteUtf8(utf8buf,
8038 String::REPLACE_INVALID_UTF8);
8040 CHECK_EQ(0, charlen);
8042 memset(utf8buf, 0x1, sizeof(utf8buf));
8043 len = GetUtf8Length(left_tree);
8045 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8046 CHECK_EQ(utf8_expected, len);
8047 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8048 CHECK_EQ(utf8_expected, len);
8049 CHECK_EQ(0xd800 / kStride, charlen);
8050 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8051 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8052 CHECK_EQ(0xc0 - kStride,
8053 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8054 CHECK_EQ(1, utf8buf[utf8_expected]);
8056 memset(utf8buf, 0x1, sizeof(utf8buf));
8057 len = GetUtf8Length(right_tree);
8058 CHECK_EQ(utf8_expected, len);
8059 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8060 CHECK_EQ(utf8_expected, len);
8061 CHECK_EQ(0xd800 / kStride, charlen);
8062 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8063 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8064 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8065 CHECK_EQ(1, utf8buf[utf8_expected]);
8067 memset(buf, 0x1, sizeof(buf));
8068 memset(wbuf, 0x1, sizeof(wbuf));
8069 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8071 len = str->Write(wbuf);
8073 CHECK_EQ(0, strcmp("abcde", buf));
8074 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8075 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8077 memset(buf, 0x1, sizeof(buf));
8078 memset(wbuf, 0x1, sizeof(wbuf));
8079 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8081 len = str->Write(wbuf, 0, 4);
8083 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8084 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8085 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8087 memset(buf, 0x1, sizeof(buf));
8088 memset(wbuf, 0x1, sizeof(wbuf));
8089 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8091 len = str->Write(wbuf, 0, 5);
8093 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8094 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8095 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8097 memset(buf, 0x1, sizeof(buf));
8098 memset(wbuf, 0x1, sizeof(wbuf));
8099 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8101 len = str->Write(wbuf, 0, 6);
8103 CHECK_EQ(0, strcmp("abcde", buf));
8104 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8105 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8107 memset(buf, 0x1, sizeof(buf));
8108 memset(wbuf, 0x1, sizeof(wbuf));
8109 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8111 len = str->Write(wbuf, 4, -1);
8113 CHECK_EQ(0, strcmp("e", buf));
8114 uint16_t answer5[] = {'e', '\0'};
8115 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8117 memset(buf, 0x1, sizeof(buf));
8118 memset(wbuf, 0x1, sizeof(wbuf));
8119 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8121 len = str->Write(wbuf, 4, 6);
8123 CHECK_EQ(0, strcmp("e", buf));
8124 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8126 memset(buf, 0x1, sizeof(buf));
8127 memset(wbuf, 0x1, sizeof(wbuf));
8128 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8130 len = str->Write(wbuf, 4, 1);
8132 CHECK_EQ(0, strncmp("e\1", buf, 2));
8133 uint16_t answer6[] = {'e', 0x101};
8134 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8136 memset(buf, 0x1, sizeof(buf));
8137 memset(wbuf, 0x1, sizeof(wbuf));
8138 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8140 len = str->Write(wbuf, 3, 1);
8142 CHECK_EQ(0, strncmp("d\1", buf, 2));
8143 uint16_t answer7[] = {'d', 0x101};
8144 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8146 memset(wbuf, 0x1, sizeof(wbuf));
8148 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8150 CHECK_EQ('X', wbuf[5]);
8151 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8152 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8153 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8154 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8156 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8158 memset(buf, 0x1, sizeof(buf));
8160 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8163 String::NO_NULL_TERMINATION);
8165 CHECK_EQ('X', buf[5]);
8166 CHECK_EQ(0, strncmp("abcde", buf, 5));
8167 CHECK_NE(0, strcmp("abcde", buf));
8169 CHECK_EQ(0, strcmp("abcde", buf));
8171 memset(utf8buf, 0x1, sizeof(utf8buf));
8173 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8174 String::NO_NULL_TERMINATION);
8176 CHECK_EQ('X', utf8buf[8]);
8177 CHECK_EQ(5, charlen);
8178 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8179 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8181 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8183 memset(utf8buf, 0x1, sizeof(utf8buf));
8185 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8186 String::NO_NULL_TERMINATION);
8188 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8189 CHECK_EQ(5, charlen);
8191 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8193 memset(buf, 0x1, sizeof(buf));
8194 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8196 CHECK_EQ(0, strcmp("abc", buf));
8197 CHECK_EQ(0, buf[3]);
8198 CHECK_EQ(0, strcmp("def", buf + 4));
8200 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8201 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8202 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8206 static void Utf16Helper(
8207 LocalContext& context, // NOLINT
8209 const char* lengths_name,
8211 Local<v8::Array> a =
8212 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8213 Local<v8::Array> alens =
8214 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8215 for (int i = 0; i < len; i++) {
8216 Local<v8::String> string =
8217 Local<v8::String>::Cast(a->Get(i));
8218 Local<v8::Number> expected_len =
8219 Local<v8::Number>::Cast(alens->Get(i));
8220 int length = GetUtf8Length(string);
8221 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8226 static uint16_t StringGet(Handle<String> str, int index) {
8227 i::Handle<i::String> istring =
8228 v8::Utils::OpenHandle(String::Cast(*str));
8229 return istring->Get(index);
8233 static void WriteUtf8Helper(
8234 LocalContext& context, // NOLINT
8236 const char* lengths_name,
8238 Local<v8::Array> b =
8239 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8240 Local<v8::Array> alens =
8241 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8244 for (int i = 0; i < len; i++) {
8245 Local<v8::String> string =
8246 Local<v8::String>::Cast(b->Get(i));
8247 Local<v8::Number> expected_len =
8248 Local<v8::Number>::Cast(alens->Get(i));
8249 int utf8_length = static_cast<int>(expected_len->Value());
8250 for (int j = utf8_length + 1; j >= 0; j--) {
8251 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8252 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8255 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8257 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8258 CHECK_GE(utf8_length + 1, utf8_written);
8259 CHECK_GE(utf8_length, utf8_written2);
8260 for (int k = 0; k < utf8_written2; k++) {
8261 CHECK_EQ(buffer[k], buffer2[k]);
8263 CHECK(nchars * 3 >= utf8_written - 1);
8264 CHECK(nchars <= utf8_written);
8265 if (j == utf8_length + 1) {
8266 CHECK_EQ(utf8_written2, utf8_length);
8267 CHECK_EQ(utf8_written2 + 1, utf8_written);
8269 CHECK_EQ(buffer[utf8_written], 42);
8270 if (j > utf8_length) {
8271 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8272 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8273 Handle<String> roundtrip = v8_str(buffer);
8274 CHECK(roundtrip->Equals(string));
8276 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8278 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8280 uint16_t trail = StringGet(string, nchars - 1);
8281 uint16_t lead = StringGet(string, nchars - 2);
8282 if (((lead & 0xfc00) == 0xd800) &&
8283 ((trail & 0xfc00) == 0xdc00)) {
8284 unsigned char u1 = buffer2[utf8_written2 - 4];
8285 unsigned char u2 = buffer2[utf8_written2 - 3];
8286 unsigned char u3 = buffer2[utf8_written2 - 2];
8287 unsigned char u4 = buffer2[utf8_written2 - 1];
8288 CHECK_EQ((u1 & 0xf8), 0xf0);
8289 CHECK_EQ((u2 & 0xc0), 0x80);
8290 CHECK_EQ((u3 & 0xc0), 0x80);
8291 CHECK_EQ((u4 & 0xc0), 0x80);
8292 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8293 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8294 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8295 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8296 CHECK_EQ((u1 & 0x3), c >> 18);
8304 THREADED_TEST(Utf16) {
8305 LocalContext context;
8306 v8::HandleScope scope(context->GetIsolate());
8308 "var pad = '01234567890123456789';"
8310 "var plens = [20, 3, 3];"
8311 "p.push('01234567890123456789');"
8312 "var lead = 0xd800;"
8313 "var trail = 0xdc00;"
8314 "p.push(String.fromCharCode(0xd800));"
8315 "p.push(String.fromCharCode(0xdc00));"
8320 "for (var i = 0; i < 3; i++) {"
8321 " p[1] = String.fromCharCode(lead++);"
8322 " for (var j = 0; j < 3; j++) {"
8323 " p[2] = String.fromCharCode(trail++);"
8324 " a.push(p[i] + p[j]);"
8325 " b.push(p[i] + p[j]);"
8326 " c.push(p[i] + p[j]);"
8327 " alens.push(plens[i] + plens[j]);"
8330 "alens[5] -= 2;" // Here the surrogate pairs match up.
8335 "for (var m = 0; m < 9; m++) {"
8336 " for (var n = 0; n < 9; n++) {"
8337 " a2.push(a[m] + a[n]);"
8338 " b2.push(b[m] + b[n]);"
8339 " var newc = 'x' + c[m] + c[n] + 'y';"
8340 " c2.push(newc.substring(1, newc.length - 1));"
8341 " var utf = alens[m] + alens[n];" // And here.
8342 // The 'n's that start with 0xdc.. are 6-8
8343 // The 'm's that end with 0xd8.. are 1, 4 and 7
8344 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8345 " a2lens.push(utf);"
8348 Utf16Helper(context, "a", "alens", 9);
8349 Utf16Helper(context, "a2", "a2lens", 81);
8350 WriteUtf8Helper(context, "b", "alens", 9);
8351 WriteUtf8Helper(context, "b2", "a2lens", 81);
8352 WriteUtf8Helper(context, "c2", "a2lens", 81);
8356 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8357 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8358 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8359 return *is1 == *is2;
8362 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8364 Handle<String> symbol1 =
8365 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8366 Handle<String> symbol2 =
8367 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8368 CHECK(SameSymbol(symbol1, symbol2));
8372 THREADED_TEST(Utf16Symbol) {
8373 LocalContext context;
8374 v8::HandleScope scope(context->GetIsolate());
8376 Handle<String> symbol1 = v8::String::NewFromUtf8(
8377 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8378 Handle<String> symbol2 = v8::String::NewFromUtf8(
8379 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8380 CHECK(SameSymbol(symbol1, symbol2));
8382 SameSymbolHelper(context->GetIsolate(),
8383 "\360\220\220\205", // 4 byte encoding.
8384 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8385 SameSymbolHelper(context->GetIsolate(),
8386 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8387 "\360\220\220\206"); // 4 byte encoding.
8388 SameSymbolHelper(context->GetIsolate(),
8389 "x\360\220\220\205", // 4 byte encoding.
8390 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8391 SameSymbolHelper(context->GetIsolate(),
8392 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8393 "x\360\220\220\206"); // 4 byte encoding.
8395 "var sym0 = 'benedictus';"
8396 "var sym0b = 'S\303\270ren';"
8397 "var sym1 = '\355\240\201\355\260\207';"
8398 "var sym2 = '\360\220\220\210';"
8399 "var sym3 = 'x\355\240\201\355\260\207';"
8400 "var sym4 = 'x\360\220\220\210';"
8401 "if (sym1.length != 2) throw sym1;"
8402 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8403 "if (sym2.length != 2) throw sym2;"
8404 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8405 "if (sym3.length != 3) throw sym3;"
8406 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8407 "if (sym4.length != 3) throw sym4;"
8408 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8409 Handle<String> sym0 = v8::String::NewFromUtf8(
8410 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8411 Handle<String> sym0b = v8::String::NewFromUtf8(
8412 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8413 Handle<String> sym1 =
8414 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8415 v8::String::kInternalizedString);
8416 Handle<String> sym2 =
8417 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8418 v8::String::kInternalizedString);
8419 Handle<String> sym3 = v8::String::NewFromUtf8(
8420 context->GetIsolate(), "x\355\240\201\355\260\207",
8421 v8::String::kInternalizedString);
8422 Handle<String> sym4 =
8423 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8424 v8::String::kInternalizedString);
8425 v8::Local<v8::Object> global = context->Global();
8426 Local<Value> s0 = global->Get(v8_str("sym0"));
8427 Local<Value> s0b = global->Get(v8_str("sym0b"));
8428 Local<Value> s1 = global->Get(v8_str("sym1"));
8429 Local<Value> s2 = global->Get(v8_str("sym2"));
8430 Local<Value> s3 = global->Get(v8_str("sym3"));
8431 Local<Value> s4 = global->Get(v8_str("sym4"));
8432 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8433 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8434 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8435 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8436 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8437 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8441 THREADED_TEST(ToArrayIndex) {
8442 LocalContext context;
8443 v8::Isolate* isolate = context->GetIsolate();
8444 v8::HandleScope scope(isolate);
8446 v8::Handle<String> str = v8_str("42");
8447 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8448 CHECK(!index.IsEmpty());
8449 CHECK_EQ(42.0, index->Uint32Value());
8450 str = v8_str("42asdf");
8451 index = str->ToArrayIndex();
8452 CHECK(index.IsEmpty());
8453 str = v8_str("-42");
8454 index = str->ToArrayIndex();
8455 CHECK(index.IsEmpty());
8456 str = v8_str("4294967295");
8457 index = str->ToArrayIndex();
8458 CHECK(!index.IsEmpty());
8459 CHECK_EQ(4294967295.0, index->Uint32Value());
8460 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8461 index = num->ToArrayIndex();
8462 CHECK(!index.IsEmpty());
8463 CHECK_EQ(1.0, index->Uint32Value());
8464 num = v8::Number::New(isolate, -1);
8465 index = num->ToArrayIndex();
8466 CHECK(index.IsEmpty());
8467 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8468 index = obj->ToArrayIndex();
8469 CHECK(index.IsEmpty());
8473 THREADED_TEST(ErrorConstruction) {
8474 LocalContext context;
8475 v8::HandleScope scope(context->GetIsolate());
8477 v8::Handle<String> foo = v8_str("foo");
8478 v8::Handle<String> message = v8_str("message");
8479 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8480 CHECK(range_error->IsObject());
8481 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8482 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8483 CHECK(reference_error->IsObject());
8484 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8485 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8486 CHECK(syntax_error->IsObject());
8487 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8488 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8489 CHECK(type_error->IsObject());
8490 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8491 v8::Handle<Value> error = v8::Exception::Error(foo);
8492 CHECK(error->IsObject());
8493 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8497 static void YGetter(Local<String> name,
8498 const v8::PropertyCallbackInfo<v8::Value>& info) {
8499 ApiTestFuzzer::Fuzz();
8500 info.GetReturnValue().Set(v8_num(10));
8504 static void YSetter(Local<String> name,
8506 const v8::PropertyCallbackInfo<void>& info) {
8507 Local<Object> this_obj = Local<Object>::Cast(info.This());
8508 if (this_obj->Has(name)) this_obj->Delete(name);
8509 this_obj->Set(name, value);
8513 THREADED_TEST(DeleteAccessor) {
8514 v8::Isolate* isolate = CcTest::isolate();
8515 v8::HandleScope scope(isolate);
8516 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8517 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8518 LocalContext context;
8519 v8::Handle<v8::Object> holder = obj->NewInstance();
8520 context->Global()->Set(v8_str("holder"), holder);
8521 v8::Handle<Value> result = CompileRun(
8522 "holder.y = 11; holder.y = 12; holder.y");
8523 CHECK_EQ(12, result->Uint32Value());
8527 THREADED_TEST(TypeSwitch) {
8528 v8::Isolate* isolate = CcTest::isolate();
8529 v8::HandleScope scope(isolate);
8530 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8531 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8532 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8533 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8534 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8535 LocalContext context;
8536 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8537 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8538 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8539 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8540 for (int i = 0; i < 10; i++) {
8541 CHECK_EQ(0, type_switch->match(obj0));
8542 CHECK_EQ(1, type_switch->match(obj1));
8543 CHECK_EQ(2, type_switch->match(obj2));
8544 CHECK_EQ(3, type_switch->match(obj3));
8545 CHECK_EQ(3, type_switch->match(obj3));
8546 CHECK_EQ(2, type_switch->match(obj2));
8547 CHECK_EQ(1, type_switch->match(obj1));
8548 CHECK_EQ(0, type_switch->match(obj0));
8553 static int trouble_nesting = 0;
8554 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8555 ApiTestFuzzer::Fuzz();
8558 // Call a JS function that throws an uncaught exception.
8559 Local<v8::Object> arg_this =
8560 args.GetIsolate()->GetCurrentContext()->Global();
8561 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8562 arg_this->Get(v8_str("trouble_callee")) :
8563 arg_this->Get(v8_str("trouble_caller"));
8564 CHECK(trouble_callee->IsFunction());
8565 args.GetReturnValue().Set(
8566 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8570 static int report_count = 0;
8571 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8572 v8::Handle<Value>) {
8577 // Counts uncaught exceptions, but other tests running in parallel
8578 // also have uncaught exceptions.
8579 TEST(ApiUncaughtException) {
8582 v8::Isolate* isolate = env->GetIsolate();
8583 v8::HandleScope scope(isolate);
8584 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8586 Local<v8::FunctionTemplate> fun =
8587 v8::FunctionTemplate::New(isolate, TroubleCallback);
8588 v8::Local<v8::Object> global = env->Global();
8589 global->Set(v8_str("trouble"), fun->GetFunction());
8592 "function trouble_callee() {"
8596 "function trouble_caller() {"
8599 Local<Value> trouble = global->Get(v8_str("trouble"));
8600 CHECK(trouble->IsFunction());
8601 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8602 CHECK(trouble_callee->IsFunction());
8603 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8604 CHECK(trouble_caller->IsFunction());
8605 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8606 CHECK_EQ(1, report_count);
8607 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8610 static const char* script_resource_name = "ExceptionInNativeScript.js";
8611 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8612 v8::Handle<Value>) {
8613 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8614 CHECK(!name_val.IsEmpty() && name_val->IsString());
8615 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8616 CHECK_EQ(script_resource_name, *name);
8617 CHECK_EQ(3, message->GetLineNumber());
8618 v8::String::Utf8Value source_line(message->GetSourceLine());
8619 CHECK_EQ(" new o.foo();", *source_line);
8623 TEST(ExceptionInNativeScript) {
8625 v8::Isolate* isolate = env->GetIsolate();
8626 v8::HandleScope scope(isolate);
8627 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8629 Local<v8::FunctionTemplate> fun =
8630 v8::FunctionTemplate::New(isolate, TroubleCallback);
8631 v8::Local<v8::Object> global = env->Global();
8632 global->Set(v8_str("trouble"), fun->GetFunction());
8634 CompileRunWithOrigin(
8635 "function trouble() {\n"
8639 script_resource_name);
8640 Local<Value> trouble = global->Get(v8_str("trouble"));
8641 CHECK(trouble->IsFunction());
8642 Function::Cast(*trouble)->Call(global, 0, NULL);
8643 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8647 TEST(CompilationErrorUsingTryCatchHandler) {
8649 v8::HandleScope scope(env->GetIsolate());
8650 v8::TryCatch try_catch;
8651 v8_compile("This doesn't &*&@#$&*^ compile.");
8652 CHECK_NE(NULL, *try_catch.Exception());
8653 CHECK(try_catch.HasCaught());
8657 TEST(TryCatchFinallyUsingTryCatchHandler) {
8659 v8::HandleScope scope(env->GetIsolate());
8660 v8::TryCatch try_catch;
8661 CompileRun("try { throw ''; } catch (e) {}");
8662 CHECK(!try_catch.HasCaught());
8663 CompileRun("try { throw ''; } finally {}");
8664 CHECK(try_catch.HasCaught());
8668 "try { throw ''; } finally { return; }"
8670 CHECK(!try_catch.HasCaught());
8673 " { try { throw ''; } finally { throw 0; }"
8675 CHECK(try_catch.HasCaught());
8679 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8680 v8::HandleScope scope(args.GetIsolate());
8681 CompileRun(args[0]->ToString());
8685 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8686 v8::Isolate* isolate = CcTest::isolate();
8687 v8::HandleScope scope(isolate);
8688 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8689 templ->Set(v8_str("CEvaluate"),
8690 v8::FunctionTemplate::New(isolate, CEvaluate));
8691 LocalContext context(0, templ);
8692 v8::TryCatch try_catch;
8694 " CEvaluate('throw 1;');"
8697 CHECK(try_catch.HasCaught());
8698 CHECK(!try_catch.Message().IsEmpty());
8699 String::Utf8Value exception_value(try_catch.Exception());
8700 CHECK_EQ(*exception_value, "1");
8703 " CEvaluate('throw 1;');"
8707 CHECK(try_catch.HasCaught());
8708 CHECK(!try_catch.Message().IsEmpty());
8709 String::Utf8Value finally_exception_value(try_catch.Exception());
8710 CHECK_EQ(*finally_exception_value, "2");
8714 // For use within the TestSecurityHandler() test.
8715 static bool g_security_callback_result = false;
8716 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8718 v8::AccessType type,
8719 Local<Value> data) {
8721 // Always allow read access.
8722 if (type == v8::ACCESS_GET)
8725 // Sometimes allow other access.
8726 return g_security_callback_result;
8730 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8732 v8::AccessType type,
8733 Local<Value> data) {
8735 // Always allow read access.
8736 if (type == v8::ACCESS_GET)
8739 // Sometimes allow other access.
8740 return g_security_callback_result;
8744 // SecurityHandler can't be run twice
8745 TEST(SecurityHandler) {
8746 v8::Isolate* isolate = CcTest::isolate();
8747 v8::HandleScope scope0(isolate);
8748 v8::Handle<v8::ObjectTemplate> global_template =
8749 v8::ObjectTemplate::New(isolate);
8750 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8751 IndexedSecurityTestCallback);
8752 // Create an environment
8753 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8756 v8::Handle<v8::Object> global0 = context0->Global();
8757 v8::Handle<Script> script0 = v8_compile("foo = 111");
8759 global0->Set(v8_str("0"), v8_num(999));
8760 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8761 CHECK_EQ(111, foo0->Int32Value());
8762 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8763 CHECK_EQ(999, z0->Int32Value());
8765 // Create another environment, should fail security checks.
8766 v8::HandleScope scope1(isolate);
8768 v8::Handle<Context> context1 =
8769 Context::New(isolate, NULL, global_template);
8772 v8::Handle<v8::Object> global1 = context1->Global();
8773 global1->Set(v8_str("othercontext"), global0);
8774 // This set will fail the security check.
8775 v8::Handle<Script> script1 =
8776 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8778 // This read will pass the security check.
8779 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8780 CHECK_EQ(111, foo1->Int32Value());
8781 // This read will pass the security check.
8782 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8783 CHECK_EQ(999, z1->Int32Value());
8785 // Create another environment, should pass security checks.
8786 { g_security_callback_result = true; // allow security handler to pass.
8787 v8::HandleScope scope2(isolate);
8788 LocalContext context2;
8789 v8::Handle<v8::Object> global2 = context2->Global();
8790 global2->Set(v8_str("othercontext"), global0);
8791 v8::Handle<Script> script2 =
8792 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8794 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8795 CHECK_EQ(333, foo2->Int32Value());
8796 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8797 CHECK_EQ(888, z2->Int32Value());
8805 THREADED_TEST(SecurityChecks) {
8807 v8::HandleScope handle_scope(env1->GetIsolate());
8808 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8810 Local<Value> foo = v8_str("foo");
8811 Local<Value> bar = v8_str("bar");
8813 // Set to the same domain.
8814 env1->SetSecurityToken(foo);
8816 // Create a function in env1.
8817 CompileRun("spy=function(){return spy;}");
8818 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8819 CHECK(spy->IsFunction());
8821 // Create another function accessing global objects.
8822 CompileRun("spy2=function(){return new this.Array();}");
8823 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8824 CHECK(spy2->IsFunction());
8826 // Switch to env2 in the same domain and invoke spy on env2.
8828 env2->SetSecurityToken(foo);
8830 Context::Scope scope_env2(env2);
8831 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8832 CHECK(result->IsFunction());
8836 env2->SetSecurityToken(bar);
8837 Context::Scope scope_env2(env2);
8839 // Call cross_domain_call, it should throw an exception
8840 v8::TryCatch try_catch;
8841 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8842 CHECK(try_catch.HasCaught());
8847 // Regression test case for issue 1183439.
8848 THREADED_TEST(SecurityChecksForPrototypeChain) {
8849 LocalContext current;
8850 v8::HandleScope scope(current->GetIsolate());
8851 v8::Handle<Context> other = Context::New(current->GetIsolate());
8853 // Change context to be able to get to the Object function in the
8854 // other context without hitting the security checks.
8855 v8::Local<Value> other_object;
8856 { Context::Scope scope(other);
8857 other_object = other->Global()->Get(v8_str("Object"));
8858 other->Global()->Set(v8_num(42), v8_num(87));
8861 current->Global()->Set(v8_str("other"), other->Global());
8862 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8864 // Make sure the security check fails here and we get an undefined
8865 // result instead of getting the Object function. Repeat in a loop
8866 // to make sure to exercise the IC code.
8867 v8::Local<Script> access_other0 = v8_compile("other.Object");
8868 v8::Local<Script> access_other1 = v8_compile("other[42]");
8869 for (int i = 0; i < 5; i++) {
8870 CHECK(access_other0->Run().IsEmpty());
8871 CHECK(access_other1->Run().IsEmpty());
8874 // Create an object that has 'other' in its prototype chain and make
8875 // sure we cannot access the Object function indirectly through
8876 // that. Repeat in a loop to make sure to exercise the IC code.
8877 v8_compile("function F() { };"
8878 "F.prototype = other;"
8879 "var f = new F();")->Run();
8880 v8::Local<Script> access_f0 = v8_compile("f.Object");
8881 v8::Local<Script> access_f1 = v8_compile("f[42]");
8882 for (int j = 0; j < 5; j++) {
8883 CHECK(access_f0->Run().IsEmpty());
8884 CHECK(access_f1->Run().IsEmpty());
8887 // Now it gets hairy: Set the prototype for the other global object
8888 // to be the current global object. The prototype chain for 'f' now
8889 // goes through 'other' but ends up in the current global object.
8890 { Context::Scope scope(other);
8891 other->Global()->Set(v8_str("__proto__"), current->Global());
8893 // Set a named and an index property on the current global
8894 // object. To force the lookup to go through the other global object,
8895 // the properties must not exist in the other global object.
8896 current->Global()->Set(v8_str("foo"), v8_num(100));
8897 current->Global()->Set(v8_num(99), v8_num(101));
8898 // Try to read the properties from f and make sure that the access
8899 // gets stopped by the security checks on the other global object.
8900 Local<Script> access_f2 = v8_compile("f.foo");
8901 Local<Script> access_f3 = v8_compile("f[99]");
8902 for (int k = 0; k < 5; k++) {
8903 CHECK(access_f2->Run().IsEmpty());
8904 CHECK(access_f3->Run().IsEmpty());
8909 static bool named_security_check_with_gc_called;
8911 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8913 v8::AccessType type,
8914 Local<Value> data) {
8915 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8916 named_security_check_with_gc_called = true;
8921 static bool indexed_security_check_with_gc_called;
8923 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8925 v8::AccessType type,
8926 Local<Value> data) {
8927 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8928 indexed_security_check_with_gc_called = true;
8933 TEST(SecurityTestGCAllowed) {
8934 v8::Isolate* isolate = CcTest::isolate();
8935 v8::HandleScope handle_scope(isolate);
8936 v8::Handle<v8::ObjectTemplate> object_template =
8937 v8::ObjectTemplate::New(isolate);
8938 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8939 IndexedSecurityTestCallbackWithGC);
8941 v8::Handle<Context> context = Context::New(isolate);
8942 v8::Context::Scope context_scope(context);
8944 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8946 named_security_check_with_gc_called = false;
8947 CompileRun("obj.foo = new String(1001);");
8948 CHECK(named_security_check_with_gc_called);
8950 indexed_security_check_with_gc_called = false;
8951 CompileRun("obj[0] = new String(1002);");
8952 CHECK(indexed_security_check_with_gc_called);
8954 named_security_check_with_gc_called = false;
8955 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8956 CHECK(named_security_check_with_gc_called);
8958 indexed_security_check_with_gc_called = false;
8959 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8960 CHECK(indexed_security_check_with_gc_called);
8964 THREADED_TEST(CrossDomainDelete) {
8966 v8::HandleScope handle_scope(env1->GetIsolate());
8967 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8969 Local<Value> foo = v8_str("foo");
8970 Local<Value> bar = v8_str("bar");
8972 // Set to the same domain.
8973 env1->SetSecurityToken(foo);
8974 env2->SetSecurityToken(foo);
8976 env1->Global()->Set(v8_str("prop"), v8_num(3));
8977 env2->Global()->Set(v8_str("env1"), env1->Global());
8979 // Change env2 to a different domain and delete env1.prop.
8980 env2->SetSecurityToken(bar);
8982 Context::Scope scope_env2(env2);
8983 Local<Value> result =
8984 CompileRun("delete env1.prop");
8985 CHECK(result.IsEmpty());
8988 // Check that env1.prop still exists.
8989 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8990 CHECK(v->IsNumber());
8991 CHECK_EQ(3, v->Int32Value());
8995 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8997 v8::HandleScope handle_scope(env1->GetIsolate());
8998 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9000 Local<Value> foo = v8_str("foo");
9001 Local<Value> bar = v8_str("bar");
9003 // Set to the same domain.
9004 env1->SetSecurityToken(foo);
9005 env2->SetSecurityToken(foo);
9007 env1->Global()->Set(v8_str("prop"), v8_num(3));
9008 env2->Global()->Set(v8_str("env1"), env1->Global());
9010 // env1.prop is enumerable in env2.
9011 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9013 Context::Scope scope_env2(env2);
9014 Local<Value> result = CompileRun(test);
9015 CHECK(result->IsTrue());
9018 // Change env2 to a different domain and test again.
9019 env2->SetSecurityToken(bar);
9021 Context::Scope scope_env2(env2);
9022 Local<Value> result = CompileRun(test);
9023 CHECK(result.IsEmpty());
9028 THREADED_TEST(CrossDomainForIn) {
9030 v8::HandleScope handle_scope(env1->GetIsolate());
9031 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9033 Local<Value> foo = v8_str("foo");
9034 Local<Value> bar = v8_str("bar");
9036 // Set to the same domain.
9037 env1->SetSecurityToken(foo);
9038 env2->SetSecurityToken(foo);
9040 env1->Global()->Set(v8_str("prop"), v8_num(3));
9041 env2->Global()->Set(v8_str("env1"), env1->Global());
9043 // Change env2 to a different domain and set env1's global object
9044 // as the __proto__ of an object in env2 and enumerate properties
9045 // in for-in. It shouldn't enumerate properties on env1's global
9047 env2->SetSecurityToken(bar);
9049 Context::Scope scope_env2(env2);
9050 Local<Value> result = CompileRun(
9052 " var obj = { '__proto__': env1 };"
9054 " for (var p in obj) {"
9055 " if (p == 'prop') return false;"
9062 CHECK(result->IsTrue());
9067 TEST(ContextDetachGlobal) {
9069 v8::HandleScope handle_scope(env1->GetIsolate());
9070 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9072 Local<v8::Object> global1 = env1->Global();
9074 Local<Value> foo = v8_str("foo");
9076 // Set to the same domain.
9077 env1->SetSecurityToken(foo);
9078 env2->SetSecurityToken(foo);
9083 // Create a function in env2 and add a reference to it in env1.
9084 Local<v8::Object> global2 = env2->Global();
9085 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9086 CompileRun("function getProp() {return prop;}");
9088 env1->Global()->Set(v8_str("getProp"),
9089 global2->Get(v8_str("getProp")));
9091 // Detach env2's global, and reuse the global object of env2
9093 env2->DetachGlobal();
9095 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9097 v8::Handle<v8::ObjectTemplate>(),
9099 env3->SetSecurityToken(v8_str("bar"));
9102 Local<v8::Object> global3 = env3->Global();
9103 CHECK_EQ(global2, global3);
9104 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9105 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9106 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9107 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9110 // Call getProp in env1, and it should return the value 1
9112 Local<Value> get_prop = global1->Get(v8_str("getProp"));
9113 CHECK(get_prop->IsFunction());
9114 v8::TryCatch try_catch;
9115 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9116 CHECK(!try_catch.HasCaught());
9117 CHECK_EQ(1, r->Int32Value());
9120 // Check that env3 is not accessible from env1
9122 Local<Value> r = global3->Get(v8_str("prop2"));
9128 TEST(DetachGlobal) {
9130 v8::HandleScope scope(env1->GetIsolate());
9132 // Create second environment.
9133 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9135 Local<Value> foo = v8_str("foo");
9137 // Set same security token for env1 and env2.
9138 env1->SetSecurityToken(foo);
9139 env2->SetSecurityToken(foo);
9141 // Create a property on the global object in env2.
9143 v8::Context::Scope scope(env2);
9144 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9147 // Create a reference to env2 global from env1 global.
9148 env1->Global()->Set(v8_str("other"), env2->Global());
9150 // Check that we have access to other.p in env2 from env1.
9151 Local<Value> result = CompileRun("other.p");
9152 CHECK(result->IsInt32());
9153 CHECK_EQ(42, result->Int32Value());
9155 // Hold on to global from env2 and detach global from env2.
9156 Local<v8::Object> global2 = env2->Global();
9157 env2->DetachGlobal();
9159 // Check that the global has been detached. No other.p property can
9161 result = CompileRun("other.p");
9162 CHECK(result.IsEmpty());
9164 // Reuse global2 for env3.
9165 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9167 v8::Handle<v8::ObjectTemplate>(),
9169 CHECK_EQ(global2, env3->Global());
9171 // Start by using the same security token for env3 as for env1 and env2.
9172 env3->SetSecurityToken(foo);
9174 // Create a property on the global object in env3.
9176 v8::Context::Scope scope(env3);
9177 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9180 // Check that other.p is now the property in env3 and that we have access.
9181 result = CompileRun("other.p");
9182 CHECK(result->IsInt32());
9183 CHECK_EQ(24, result->Int32Value());
9185 // Change security token for env3 to something different from env1 and env2.
9186 env3->SetSecurityToken(v8_str("bar"));
9188 // Check that we do not have access to other.p in env1. |other| is now
9189 // the global object for env3 which has a different security token,
9190 // so access should be blocked.
9191 result = CompileRun("other.p");
9192 CHECK(result.IsEmpty());
9196 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9197 info.GetReturnValue().Set(
9198 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9202 TEST(DetachedAccesses) {
9204 v8::HandleScope scope(env1->GetIsolate());
9206 // Create second environment.
9207 Local<ObjectTemplate> inner_global_template =
9208 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9209 inner_global_template ->SetAccessorProperty(
9210 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9211 v8::Local<Context> env2 =
9212 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9214 Local<Value> foo = v8_str("foo");
9216 // Set same security token for env1 and env2.
9217 env1->SetSecurityToken(foo);
9218 env2->SetSecurityToken(foo);
9220 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9223 v8::Context::Scope scope(env2);
9224 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9226 "function bound_x() { return x; }"
9227 "function get_x() { return this.x; }"
9228 "function get_x_w() { return (function() {return this.x;})(); }");
9229 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9230 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9231 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9232 env1->Global()->Set(
9234 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9237 Local<Object> env2_global = env2->Global();
9238 env2_global->TurnOnAccessCheck();
9239 env2->DetachGlobal();
9241 Local<Value> result;
9242 result = CompileRun("bound_x()");
9243 CHECK_EQ(v8_str("env2_x"), result);
9244 result = CompileRun("get_x()");
9245 CHECK(result.IsEmpty());
9246 result = CompileRun("get_x_w()");
9247 CHECK(result.IsEmpty());
9248 result = CompileRun("this_x()");
9249 CHECK_EQ(v8_str("env2_x"), result);
9251 // Reattach env2's proxy
9252 env2 = Context::New(env1->GetIsolate(),
9254 v8::Handle<v8::ObjectTemplate>(),
9256 env2->SetSecurityToken(foo);
9258 v8::Context::Scope scope(env2);
9259 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9260 env2->Global()->Set(v8_str("env1"), env1->Global());
9261 result = CompileRun(
9263 "for (var i = 0; i < 4; i++ ) {"
9264 " results.push(env1.bound_x());"
9265 " results.push(env1.get_x());"
9266 " results.push(env1.get_x_w());"
9267 " results.push(env1.this_x());"
9270 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9271 CHECK_EQ(16, results->Length());
9272 for (int i = 0; i < 16; i += 4) {
9273 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9274 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9275 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9276 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9280 result = CompileRun(
9282 "for (var i = 0; i < 4; i++ ) {"
9283 " results.push(bound_x());"
9284 " results.push(get_x());"
9285 " results.push(get_x_w());"
9286 " results.push(this_x());"
9289 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9290 CHECK_EQ(16, results->Length());
9291 for (int i = 0; i < 16; i += 4) {
9292 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9293 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9294 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9295 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9298 result = CompileRun(
9300 "for (var i = 0; i < 4; i++ ) {"
9301 " results.push(this.bound_x());"
9302 " results.push(this.get_x());"
9303 " results.push(this.get_x_w());"
9304 " results.push(this.this_x());"
9307 results = Local<v8::Array>::Cast(result);
9308 CHECK_EQ(16, results->Length());
9309 for (int i = 0; i < 16; i += 4) {
9310 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9311 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9312 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9313 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9318 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9319 static bool NamedAccessBlocker(Local<v8::Object> global,
9321 v8::AccessType type,
9322 Local<Value> data) {
9323 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9324 allowed_access_type[type];
9328 static bool IndexedAccessBlocker(Local<v8::Object> global,
9330 v8::AccessType type,
9331 Local<Value> data) {
9332 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9333 allowed_access_type[type];
9337 static int g_echo_value = -1;
9340 static void EchoGetter(
9342 const v8::PropertyCallbackInfo<v8::Value>& info) {
9343 info.GetReturnValue().Set(v8_num(g_echo_value));
9347 static void EchoSetter(Local<String> name,
9349 const v8::PropertyCallbackInfo<void>&) {
9350 if (value->IsNumber())
9351 g_echo_value = value->Int32Value();
9355 static void UnreachableGetter(
9357 const v8::PropertyCallbackInfo<v8::Value>& info) {
9358 CHECK(false); // This function should not be called..
9362 static void UnreachableSetter(Local<String>,
9364 const v8::PropertyCallbackInfo<void>&) {
9365 CHECK(false); // This function should nto be called.
9369 static void UnreachableFunction(
9370 const v8::FunctionCallbackInfo<v8::Value>& info) {
9371 CHECK(false); // This function should not be called..
9375 TEST(AccessControl) {
9376 v8::Isolate* isolate = CcTest::isolate();
9377 v8::HandleScope handle_scope(isolate);
9378 v8::Handle<v8::ObjectTemplate> global_template =
9379 v8::ObjectTemplate::New(isolate);
9381 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9382 IndexedAccessBlocker);
9384 // Add an accessor accessible by cross-domain JS code.
9385 global_template->SetAccessor(
9386 v8_str("accessible_prop"),
9387 EchoGetter, EchoSetter,
9388 v8::Handle<Value>(),
9389 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9392 // Add an accessor that is not accessible by cross-domain JS code.
9393 global_template->SetAccessor(v8_str("blocked_prop"),
9394 UnreachableGetter, UnreachableSetter,
9395 v8::Handle<Value>(),
9398 global_template->SetAccessorProperty(
9399 v8_str("blocked_js_prop"),
9400 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9401 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9405 // Create an environment
9406 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9409 v8::Handle<v8::Object> global0 = context0->Global();
9411 // Define a property with JS getter and setter.
9413 "function getter() { return 'getter'; };\n"
9414 "function setter() { return 'setter'; }\n"
9415 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9417 Local<Value> getter = global0->Get(v8_str("getter"));
9418 Local<Value> setter = global0->Get(v8_str("setter"));
9420 // And define normal element.
9421 global0->Set(239, v8_str("239"));
9423 // Define an element with JS getter and setter.
9425 "function el_getter() { return 'el_getter'; };\n"
9426 "function el_setter() { return 'el_setter'; };\n"
9427 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9429 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9430 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9432 v8::HandleScope scope1(isolate);
9434 v8::Local<Context> context1 = Context::New(isolate);
9437 v8::Handle<v8::Object> global1 = context1->Global();
9438 global1->Set(v8_str("other"), global0);
9440 // Access blocked property.
9441 CompileRun("other.blocked_prop = 1");
9443 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9444 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9447 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9449 // Access blocked element.
9450 CHECK(CompileRun("other[239] = 1").IsEmpty());
9452 CHECK(CompileRun("other[239]").IsEmpty());
9453 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9454 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9456 // Enable ACCESS_HAS
9457 allowed_access_type[v8::ACCESS_HAS] = true;
9458 CHECK(CompileRun("other[239]").IsEmpty());
9459 // ... and now we can get the descriptor...
9460 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9462 // ... and enumerate the property.
9463 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9464 allowed_access_type[v8::ACCESS_HAS] = false;
9466 // Access a property with JS accessor.
9467 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9469 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9470 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9473 // Enable both ACCESS_HAS and ACCESS_GET.
9474 allowed_access_type[v8::ACCESS_HAS] = true;
9475 allowed_access_type[v8::ACCESS_GET] = true;
9477 ExpectString("other.js_accessor_p", "getter");
9479 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9481 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9483 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9485 allowed_access_type[v8::ACCESS_HAS] = false;
9486 allowed_access_type[v8::ACCESS_GET] = false;
9488 // Access an element with JS accessor.
9489 CHECK(CompileRun("other[42] = 2").IsEmpty());
9491 CHECK(CompileRun("other[42]").IsEmpty());
9492 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9494 // Enable both ACCESS_HAS and ACCESS_GET.
9495 allowed_access_type[v8::ACCESS_HAS] = true;
9496 allowed_access_type[v8::ACCESS_GET] = true;
9498 ExpectString("other[42]", "el_getter");
9499 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9500 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9501 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9503 allowed_access_type[v8::ACCESS_HAS] = false;
9504 allowed_access_type[v8::ACCESS_GET] = false;
9506 v8::Handle<Value> value;
9508 // Access accessible property
9509 value = CompileRun("other.accessible_prop = 3");
9510 CHECK(value->IsNumber());
9511 CHECK_EQ(3, value->Int32Value());
9512 CHECK_EQ(3, g_echo_value);
9514 value = CompileRun("other.accessible_prop");
9515 CHECK(value->IsNumber());
9516 CHECK_EQ(3, value->Int32Value());
9519 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9520 CHECK(value->IsNumber());
9521 CHECK_EQ(3, value->Int32Value());
9523 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9524 CHECK(value->IsTrue());
9526 // Enumeration doesn't enumerate accessors from inaccessible objects in
9527 // the prototype chain even if the accessors are in themselves accessible.
9530 " var obj = { '__proto__': other };"
9532 " for (var p in obj) {"
9533 " if (p == 'accessible_prop' ||"
9534 " p == 'blocked_js_prop' ||"
9535 " p == 'blocked_js_prop') {"
9544 CHECK(value->IsTrue());
9551 TEST(AccessControlES5) {
9552 v8::Isolate* isolate = CcTest::isolate();
9553 v8::HandleScope handle_scope(isolate);
9554 v8::Handle<v8::ObjectTemplate> global_template =
9555 v8::ObjectTemplate::New(isolate);
9557 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9558 IndexedAccessBlocker);
9560 // Add accessible accessor.
9561 global_template->SetAccessor(
9562 v8_str("accessible_prop"),
9563 EchoGetter, EchoSetter,
9564 v8::Handle<Value>(),
9565 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9568 // Add an accessor that is not accessible by cross-domain JS code.
9569 global_template->SetAccessor(v8_str("blocked_prop"),
9570 UnreachableGetter, UnreachableSetter,
9571 v8::Handle<Value>(),
9574 // Create an environment
9575 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9578 v8::Handle<v8::Object> global0 = context0->Global();
9580 v8::Local<Context> context1 = Context::New(isolate);
9582 v8::Handle<v8::Object> global1 = context1->Global();
9583 global1->Set(v8_str("other"), global0);
9585 // Regression test for issue 1154.
9586 CHECK(CompileRun("Object.keys(other)").IsEmpty());
9587 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9589 // Regression test for issue 1027.
9590 CompileRun("Object.defineProperty(\n"
9591 " other, 'blocked_prop', {configurable: false})");
9592 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9593 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9596 // Regression test for issue 1171.
9597 ExpectTrue("Object.isExtensible(other)");
9598 CompileRun("Object.preventExtensions(other)");
9599 ExpectTrue("Object.isExtensible(other)");
9601 // Object.seal and Object.freeze.
9602 CompileRun("Object.freeze(other)");
9603 ExpectTrue("Object.isExtensible(other)");
9605 CompileRun("Object.seal(other)");
9606 ExpectTrue("Object.isExtensible(other)");
9608 // Regression test for issue 1250.
9609 // Make sure that we can set the accessible accessors value using normal
9611 CompileRun("other.accessible_prop = 42");
9612 CHECK_EQ(42, g_echo_value);
9614 v8::Handle<Value> value;
9615 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9616 value = CompileRun("other.accessible_prop == 42");
9617 CHECK(value->IsTrue());
9621 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9622 v8::AccessType type, Local<Value> data) {
9627 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9628 v8::AccessType type, Local<Value> data) {
9633 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9634 v8::Isolate* isolate = CcTest::isolate();
9635 v8::HandleScope handle_scope(isolate);
9636 v8::Handle<v8::ObjectTemplate> obj_template =
9637 v8::ObjectTemplate::New(isolate);
9639 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9640 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9641 BlockEverythingIndexed);
9643 // Create an environment
9644 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9647 v8::Handle<v8::Object> global0 = context0->Global();
9649 v8::HandleScope scope1(CcTest::isolate());
9651 v8::Local<Context> context1 = Context::New(isolate);
9654 v8::Handle<v8::Object> global1 = context1->Global();
9655 global1->Set(v8_str("other"), global0);
9656 global1->Set(v8_str("object"), obj_template->NewInstance());
9658 v8::Handle<Value> value;
9660 // Attempt to get the property names of the other global object and
9661 // of an object that requires access checks. Accessing the other
9662 // global object should be blocked by access checks on the global
9663 // proxy object. Accessing the object that requires access checks
9664 // is blocked by the access checks on the object itself.
9665 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9666 CHECK(value.IsEmpty());
9668 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9669 CHECK(value.IsEmpty());
9676 TEST(SuperAccessControl) {
9677 i::FLAG_harmony_classes = true;
9678 v8::Isolate* isolate = CcTest::isolate();
9679 v8::HandleScope handle_scope(isolate);
9680 v8::Handle<v8::ObjectTemplate> obj_template =
9681 v8::ObjectTemplate::New(isolate);
9682 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9683 BlockEverythingIndexed);
9685 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9688 v8::TryCatch try_catch;
9690 "function f() { return super.hasOwnProperty; };"
9691 "var m = f.toMethod(prohibited);"
9693 CHECK(try_catch.HasCaught());
9697 v8::TryCatch try_catch;
9699 "function f() { super.hasOwnProperty = function () {}; };"
9700 "var m = f.toMethod(prohibited);"
9702 CHECK(try_catch.HasCaught());
9706 v8::TryCatch try_catch;
9708 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
9711 " super.x = function () {}; "
9713 "var m = f.toMethod(prohibited);"
9715 CHECK(try_catch.HasCaught());
9720 static void IndexedPropertyEnumerator(
9721 const v8::PropertyCallbackInfo<v8::Array>& info) {
9722 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9723 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9724 result->Set(1, v8::Object::New(info.GetIsolate()));
9725 info.GetReturnValue().Set(result);
9729 static void NamedPropertyEnumerator(
9730 const v8::PropertyCallbackInfo<v8::Array>& info) {
9731 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9732 result->Set(0, v8_str("x"));
9733 result->Set(1, v8::Object::New(info.GetIsolate()));
9734 info.GetReturnValue().Set(result);
9738 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9739 v8::Isolate* isolate = CcTest::isolate();
9740 v8::HandleScope handle_scope(isolate);
9741 v8::Handle<v8::ObjectTemplate> obj_template =
9742 v8::ObjectTemplate::New(isolate);
9744 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9745 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9746 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9747 IndexedPropertyEnumerator);
9748 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9749 NamedPropertyEnumerator);
9751 LocalContext context;
9752 v8::Handle<v8::Object> global = context->Global();
9753 global->Set(v8_str("object"), obj_template->NewInstance());
9755 v8::Handle<v8::Value> result =
9756 CompileRun("Object.getOwnPropertyNames(object)");
9757 CHECK(result->IsArray());
9758 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9759 CHECK_EQ(3, result_array->Length());
9760 CHECK(result_array->Get(0)->IsString());
9761 CHECK(result_array->Get(1)->IsString());
9762 CHECK(result_array->Get(2)->IsString());
9763 CHECK_EQ(v8_str("7"), result_array->Get(0));
9764 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9765 CHECK_EQ(v8_str("x"), result_array->Get(2));
9769 static void ConstTenGetter(Local<String> name,
9770 const v8::PropertyCallbackInfo<v8::Value>& info) {
9771 info.GetReturnValue().Set(v8_num(10));
9775 THREADED_TEST(CrossDomainAccessors) {
9776 v8::Isolate* isolate = CcTest::isolate();
9777 v8::HandleScope handle_scope(isolate);
9779 v8::Handle<v8::FunctionTemplate> func_template =
9780 v8::FunctionTemplate::New(isolate);
9782 v8::Handle<v8::ObjectTemplate> global_template =
9783 func_template->InstanceTemplate();
9785 v8::Handle<v8::ObjectTemplate> proto_template =
9786 func_template->PrototypeTemplate();
9788 // Add an accessor to proto that's accessible by cross-domain JS code.
9789 proto_template->SetAccessor(v8_str("accessible"),
9791 v8::Handle<Value>(),
9794 // Add an accessor that is not accessible by cross-domain JS code.
9795 global_template->SetAccessor(v8_str("unreachable"),
9796 UnreachableGetter, 0,
9797 v8::Handle<Value>(),
9800 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9803 Local<v8::Object> global = context0->Global();
9804 // Add a normal property that shadows 'accessible'
9805 global->Set(v8_str("accessible"), v8_num(11));
9807 // Enter a new context.
9808 v8::HandleScope scope1(CcTest::isolate());
9809 v8::Local<Context> context1 = Context::New(isolate);
9812 v8::Handle<v8::Object> global1 = context1->Global();
9813 global1->Set(v8_str("other"), global);
9815 // Should return 10, instead of 11
9816 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9817 CHECK(value->IsNumber());
9818 CHECK_EQ(10, value->Int32Value());
9820 value = v8_compile("other.unreachable")->Run();
9821 CHECK(value.IsEmpty());
9828 static int named_access_count = 0;
9829 static int indexed_access_count = 0;
9831 static bool NamedAccessCounter(Local<v8::Object> global,
9833 v8::AccessType type,
9834 Local<Value> data) {
9835 named_access_count++;
9840 static bool IndexedAccessCounter(Local<v8::Object> global,
9842 v8::AccessType type,
9843 Local<Value> data) {
9844 indexed_access_count++;
9849 // This one is too easily disturbed by other tests.
9850 TEST(AccessControlIC) {
9851 named_access_count = 0;
9852 indexed_access_count = 0;
9854 v8::Isolate* isolate = CcTest::isolate();
9855 v8::HandleScope handle_scope(isolate);
9857 // Create an environment.
9858 v8::Local<Context> context0 = Context::New(isolate);
9861 // Create an object that requires access-check functions to be
9862 // called for cross-domain access.
9863 v8::Handle<v8::ObjectTemplate> object_template =
9864 v8::ObjectTemplate::New(isolate);
9865 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9866 IndexedAccessCounter);
9867 Local<v8::Object> object = object_template->NewInstance();
9869 v8::HandleScope scope1(isolate);
9871 // Create another environment.
9872 v8::Local<Context> context1 = Context::New(isolate);
9875 // Make easy access to the object from the other environment.
9876 v8::Handle<v8::Object> global1 = context1->Global();
9877 global1->Set(v8_str("obj"), object);
9879 v8::Handle<Value> value;
9881 // Check that the named access-control function is called every time.
9882 CompileRun("function testProp(obj) {"
9883 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9884 " for (var j = 0; j < 10; j++) obj.prop;"
9887 value = CompileRun("testProp(obj)");
9888 CHECK(value->IsNumber());
9889 CHECK_EQ(1, value->Int32Value());
9890 CHECK_EQ(21, named_access_count);
9892 // Check that the named access-control function is called every time.
9893 CompileRun("var p = 'prop';"
9894 "function testKeyed(obj) {"
9895 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9896 " for (var j = 0; j < 10; j++) obj[p];"
9899 // Use obj which requires access checks. No inline caching is used
9901 value = CompileRun("testKeyed(obj)");
9902 CHECK(value->IsNumber());
9903 CHECK_EQ(1, value->Int32Value());
9904 CHECK_EQ(42, named_access_count);
9905 // Force the inline caches into generic state and try again.
9906 CompileRun("testKeyed({ a: 0 })");
9907 CompileRun("testKeyed({ b: 0 })");
9908 value = CompileRun("testKeyed(obj)");
9909 CHECK(value->IsNumber());
9910 CHECK_EQ(1, value->Int32Value());
9911 CHECK_EQ(63, named_access_count);
9913 // Check that the indexed access-control function is called every time.
9914 CompileRun("function testIndexed(obj) {"
9915 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9916 " for (var j = 0; j < 10; j++) obj[0];"
9919 value = CompileRun("testIndexed(obj)");
9920 CHECK(value->IsNumber());
9921 CHECK_EQ(1, value->Int32Value());
9922 CHECK_EQ(21, indexed_access_count);
9923 // Force the inline caches into generic state.
9924 CompileRun("testIndexed(new Array(1))");
9925 // Test that the indexed access check is called.
9926 value = CompileRun("testIndexed(obj)");
9927 CHECK(value->IsNumber());
9928 CHECK_EQ(1, value->Int32Value());
9929 CHECK_EQ(42, indexed_access_count);
9931 // Check that the named access check is called when invoking
9932 // functions on an object that requires access checks.
9933 CompileRun("obj.f = function() {}");
9934 CompileRun("function testCallNormal(obj) {"
9935 " for (var i = 0; i < 10; i++) obj.f();"
9937 CompileRun("testCallNormal(obj)");
9938 CHECK_EQ(74, named_access_count);
9940 // Force obj into slow case.
9941 value = CompileRun("delete obj.prop");
9942 CHECK(value->BooleanValue());
9943 // Force inline caches into dictionary probing mode.
9944 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9945 // Test that the named access check is called.
9946 value = CompileRun("testProp(obj);");
9947 CHECK(value->IsNumber());
9948 CHECK_EQ(1, value->Int32Value());
9949 CHECK_EQ(96, named_access_count);
9951 // Force the call inline cache into dictionary probing mode.
9952 CompileRun("o.f = function() {}; testCallNormal(o)");
9953 // Test that the named access check is still called for each
9954 // invocation of the function.
9955 value = CompileRun("testCallNormal(obj)");
9956 CHECK_EQ(106, named_access_count);
9963 static bool NamedAccessFlatten(Local<v8::Object> global,
9965 v8::AccessType type,
9966 Local<Value> data) {
9970 CHECK(name->IsString());
9972 memset(buf, 0x1, sizeof(buf));
9973 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9978 memset(buf, 0x1, sizeof(buf));
9979 len = name.As<String>()->Write(buf2);
9986 static bool IndexedAccessFlatten(Local<v8::Object> global,
9988 v8::AccessType type,
9989 Local<Value> data) {
9994 // Regression test. In access checks, operations that may cause
9995 // garbage collection are not allowed. It used to be the case that
9996 // using the Write operation on a string could cause a garbage
9997 // collection due to flattening of the string. This is no longer the
9999 THREADED_TEST(AccessControlFlatten) {
10000 named_access_count = 0;
10001 indexed_access_count = 0;
10003 v8::Isolate* isolate = CcTest::isolate();
10004 v8::HandleScope handle_scope(isolate);
10006 // Create an environment.
10007 v8::Local<Context> context0 = Context::New(isolate);
10010 // Create an object that requires access-check functions to be
10011 // called for cross-domain access.
10012 v8::Handle<v8::ObjectTemplate> object_template =
10013 v8::ObjectTemplate::New(isolate);
10014 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10015 IndexedAccessFlatten);
10016 Local<v8::Object> object = object_template->NewInstance();
10018 v8::HandleScope scope1(isolate);
10020 // Create another environment.
10021 v8::Local<Context> context1 = Context::New(isolate);
10024 // Make easy access to the object from the other environment.
10025 v8::Handle<v8::Object> global1 = context1->Global();
10026 global1->Set(v8_str("obj"), object);
10028 v8::Handle<Value> value;
10030 value = v8_compile("var p = 'as' + 'df';")->Run();
10031 value = v8_compile("obj[p];")->Run();
10038 static void AccessControlNamedGetter(
10040 const v8::PropertyCallbackInfo<v8::Value>& info) {
10041 info.GetReturnValue().Set(42);
10045 static void AccessControlNamedSetter(
10047 Local<Value> value,
10048 const v8::PropertyCallbackInfo<v8::Value>& info) {
10049 info.GetReturnValue().Set(value);
10053 static void AccessControlIndexedGetter(
10055 const v8::PropertyCallbackInfo<v8::Value>& info) {
10056 info.GetReturnValue().Set(v8_num(42));
10060 static void AccessControlIndexedSetter(
10062 Local<Value> value,
10063 const v8::PropertyCallbackInfo<v8::Value>& info) {
10064 info.GetReturnValue().Set(value);
10068 THREADED_TEST(AccessControlInterceptorIC) {
10069 named_access_count = 0;
10070 indexed_access_count = 0;
10072 v8::Isolate* isolate = CcTest::isolate();
10073 v8::HandleScope handle_scope(isolate);
10075 // Create an environment.
10076 v8::Local<Context> context0 = Context::New(isolate);
10079 // Create an object that requires access-check functions to be
10080 // called for cross-domain access. The object also has interceptors
10082 v8::Handle<v8::ObjectTemplate> object_template =
10083 v8::ObjectTemplate::New(isolate);
10084 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10085 IndexedAccessCounter);
10086 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
10087 AccessControlNamedSetter);
10088 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
10089 AccessControlIndexedSetter);
10090 Local<v8::Object> object = object_template->NewInstance();
10092 v8::HandleScope scope1(isolate);
10094 // Create another environment.
10095 v8::Local<Context> context1 = Context::New(isolate);
10098 // Make easy access to the object from the other environment.
10099 v8::Handle<v8::Object> global1 = context1->Global();
10100 global1->Set(v8_str("obj"), object);
10102 v8::Handle<Value> value;
10104 // Check that the named access-control function is called every time
10105 // eventhough there is an interceptor on the object.
10106 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10107 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10109 CHECK(value->IsNumber());
10110 CHECK_EQ(42, value->Int32Value());
10111 CHECK_EQ(21, named_access_count);
10113 value = v8_compile("var p = 'x';")->Run();
10114 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10115 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10117 CHECK(value->IsNumber());
10118 CHECK_EQ(42, value->Int32Value());
10119 CHECK_EQ(42, named_access_count);
10121 // Check that the indexed access-control function is called every
10122 // time eventhough there is an interceptor on the object.
10123 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10124 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10126 CHECK(value->IsNumber());
10127 CHECK_EQ(42, value->Int32Value());
10128 CHECK_EQ(21, indexed_access_count);
10135 THREADED_TEST(Version) {
10136 v8::V8::GetVersion();
10140 static void InstanceFunctionCallback(
10141 const v8::FunctionCallbackInfo<v8::Value>& args) {
10142 ApiTestFuzzer::Fuzz();
10143 args.GetReturnValue().Set(v8_num(12));
10147 THREADED_TEST(InstanceProperties) {
10148 LocalContext context;
10149 v8::Isolate* isolate = context->GetIsolate();
10150 v8::HandleScope handle_scope(isolate);
10152 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10153 Local<ObjectTemplate> instance = t->InstanceTemplate();
10155 instance->Set(v8_str("x"), v8_num(42));
10156 instance->Set(v8_str("f"),
10157 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10159 Local<Value> o = t->GetFunction()->NewInstance();
10161 context->Global()->Set(v8_str("i"), o);
10162 Local<Value> value = CompileRun("i.x");
10163 CHECK_EQ(42, value->Int32Value());
10165 value = CompileRun("i.f()");
10166 CHECK_EQ(12, value->Int32Value());
10170 static void GlobalObjectInstancePropertiesGet(
10172 const v8::PropertyCallbackInfo<v8::Value>&) {
10173 ApiTestFuzzer::Fuzz();
10177 THREADED_TEST(GlobalObjectInstanceProperties) {
10178 v8::Isolate* isolate = CcTest::isolate();
10179 v8::HandleScope handle_scope(isolate);
10181 Local<Value> global_object;
10183 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10184 t->InstanceTemplate()->SetNamedPropertyHandler(
10185 GlobalObjectInstancePropertiesGet);
10186 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10187 instance_template->Set(v8_str("x"), v8_num(42));
10188 instance_template->Set(v8_str("f"),
10189 v8::FunctionTemplate::New(isolate,
10190 InstanceFunctionCallback));
10192 // The script to check how Crankshaft compiles missing global function
10193 // invocations. function g is not defined and should throw on call.
10194 const char* script =
10195 "function wrapper(call) {"
10196 " var x = 0, y = 1;"
10197 " for (var i = 0; i < 1000; i++) {"
10203 "for (var i = 0; i < 17; i++) wrapper(false);"
10205 "try { wrapper(true); } catch (e) { thrown = 1; };"
10209 LocalContext env(NULL, instance_template);
10210 // Hold on to the global object so it can be used again in another
10211 // environment initialization.
10212 global_object = env->Global();
10214 Local<Value> value = CompileRun("x");
10215 CHECK_EQ(42, value->Int32Value());
10216 value = CompileRun("f()");
10217 CHECK_EQ(12, value->Int32Value());
10218 value = CompileRun(script);
10219 CHECK_EQ(1, value->Int32Value());
10223 // Create new environment reusing the global object.
10224 LocalContext env(NULL, instance_template, global_object);
10225 Local<Value> value = CompileRun("x");
10226 CHECK_EQ(42, value->Int32Value());
10227 value = CompileRun("f()");
10228 CHECK_EQ(12, value->Int32Value());
10229 value = CompileRun(script);
10230 CHECK_EQ(1, value->Int32Value());
10235 THREADED_TEST(CallKnownGlobalReceiver) {
10236 v8::Isolate* isolate = CcTest::isolate();
10237 v8::HandleScope handle_scope(isolate);
10239 Local<Value> global_object;
10241 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10242 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10244 // The script to check that we leave global object not
10245 // global object proxy on stack when we deoptimize from inside
10246 // arguments evaluation.
10247 // To provoke error we need to both force deoptimization
10248 // from arguments evaluation and to force CallIC to take
10249 // CallIC_Miss code path that can't cope with global proxy.
10250 const char* script =
10251 "function bar(x, y) { try { } finally { } }"
10252 "function baz(x) { try { } finally { } }"
10253 "function bom(x) { try { } finally { } }"
10254 "function foo(x) { bar([x], bom(2)); }"
10255 "for (var i = 0; i < 10000; i++) foo(1);"
10260 LocalContext env(NULL, instance_template);
10261 // Hold on to the global object so it can be used again in another
10262 // environment initialization.
10263 global_object = env->Global();
10264 foo = CompileRun(script);
10268 // Create new environment reusing the global object.
10269 LocalContext env(NULL, instance_template, global_object);
10270 env->Global()->Set(v8_str("foo"), foo);
10271 CompileRun("foo()");
10276 static void ShadowFunctionCallback(
10277 const v8::FunctionCallbackInfo<v8::Value>& args) {
10278 ApiTestFuzzer::Fuzz();
10279 args.GetReturnValue().Set(v8_num(42));
10283 static int shadow_y;
10284 static int shadow_y_setter_call_count;
10285 static int shadow_y_getter_call_count;
10288 static void ShadowYSetter(Local<String>,
10290 const v8::PropertyCallbackInfo<void>&) {
10291 shadow_y_setter_call_count++;
10296 static void ShadowYGetter(Local<String> name,
10297 const v8::PropertyCallbackInfo<v8::Value>& info) {
10298 ApiTestFuzzer::Fuzz();
10299 shadow_y_getter_call_count++;
10300 info.GetReturnValue().Set(v8_num(shadow_y));
10304 static void ShadowIndexedGet(uint32_t index,
10305 const v8::PropertyCallbackInfo<v8::Value>&) {
10309 static void ShadowNamedGet(Local<String> key,
10310 const v8::PropertyCallbackInfo<v8::Value>&) {
10314 THREADED_TEST(ShadowObject) {
10315 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10316 v8::Isolate* isolate = CcTest::isolate();
10317 v8::HandleScope handle_scope(isolate);
10319 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10320 LocalContext context(NULL, global_template);
10322 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10323 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10324 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10325 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10326 Local<ObjectTemplate> instance = t->InstanceTemplate();
10328 proto->Set(v8_str("f"),
10329 v8::FunctionTemplate::New(isolate,
10330 ShadowFunctionCallback,
10332 proto->Set(v8_str("x"), v8_num(12));
10334 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10336 Local<Value> o = t->GetFunction()->NewInstance();
10337 context->Global()->Set(v8_str("__proto__"), o);
10339 Local<Value> value =
10340 CompileRun("this.propertyIsEnumerable(0)");
10341 CHECK(value->IsBoolean());
10342 CHECK(!value->BooleanValue());
10344 value = CompileRun("x");
10345 CHECK_EQ(12, value->Int32Value());
10347 value = CompileRun("f()");
10348 CHECK_EQ(42, value->Int32Value());
10350 CompileRun("y = 43");
10351 CHECK_EQ(1, shadow_y_setter_call_count);
10352 value = CompileRun("y");
10353 CHECK_EQ(1, shadow_y_getter_call_count);
10354 CHECK_EQ(42, value->Int32Value());
10358 THREADED_TEST(HiddenPrototype) {
10359 LocalContext context;
10360 v8::Isolate* isolate = context->GetIsolate();
10361 v8::HandleScope handle_scope(isolate);
10363 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10364 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10365 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10366 t1->SetHiddenPrototype(true);
10367 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10368 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10369 t2->SetHiddenPrototype(true);
10370 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10371 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10372 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10374 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10375 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10376 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10377 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10379 // Setting the prototype on an object skips hidden prototypes.
10380 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10381 o0->Set(v8_str("__proto__"), o1);
10382 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10383 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10384 o0->Set(v8_str("__proto__"), o2);
10385 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10386 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10387 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10388 o0->Set(v8_str("__proto__"), o3);
10389 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10390 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10391 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10392 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10394 // Getting the prototype of o0 should get the first visible one
10395 // which is o3. Therefore, z should not be defined on the prototype
10397 Local<Value> proto = o0->Get(v8_str("__proto__"));
10398 CHECK(proto->IsObject());
10399 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10403 THREADED_TEST(HiddenPrototypeSet) {
10404 LocalContext context;
10405 v8::Isolate* isolate = context->GetIsolate();
10406 v8::HandleScope handle_scope(isolate);
10408 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10409 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10410 ht->SetHiddenPrototype(true);
10411 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10412 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10414 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10415 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10416 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10417 o->Set(v8_str("__proto__"), h);
10418 h->Set(v8_str("__proto__"), p);
10420 // Setting a property that exists on the hidden prototype goes there.
10421 o->Set(v8_str("x"), v8_num(7));
10422 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10423 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10424 CHECK(p->Get(v8_str("x"))->IsUndefined());
10426 // Setting a new property should not be forwarded to the hidden prototype.
10427 o->Set(v8_str("y"), v8_num(6));
10428 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10429 CHECK(h->Get(v8_str("y"))->IsUndefined());
10430 CHECK(p->Get(v8_str("y"))->IsUndefined());
10432 // Setting a property that only exists on a prototype of the hidden prototype
10433 // is treated normally again.
10434 p->Set(v8_str("z"), v8_num(8));
10435 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10436 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10437 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10438 o->Set(v8_str("z"), v8_num(9));
10439 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10440 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10441 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10445 // Regression test for issue 2457.
10446 THREADED_TEST(HiddenPrototypeIdentityHash) {
10447 LocalContext context;
10448 v8::HandleScope handle_scope(context->GetIsolate());
10450 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10451 t->SetHiddenPrototype(true);
10452 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10453 Handle<Object> p = t->GetFunction()->NewInstance();
10454 Handle<Object> o = Object::New(context->GetIsolate());
10455 o->SetPrototype(p);
10457 int hash = o->GetIdentityHash();
10459 o->Set(v8_str("foo"), v8_num(42));
10460 DCHECK_EQ(hash, o->GetIdentityHash());
10464 THREADED_TEST(SetPrototype) {
10465 LocalContext context;
10466 v8::Isolate* isolate = context->GetIsolate();
10467 v8::HandleScope handle_scope(isolate);
10469 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10470 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10471 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10472 t1->SetHiddenPrototype(true);
10473 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10474 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10475 t2->SetHiddenPrototype(true);
10476 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10477 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10478 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10480 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10481 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10482 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10483 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10485 // Setting the prototype on an object does not skip hidden prototypes.
10486 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10487 CHECK(o0->SetPrototype(o1));
10488 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10489 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10490 CHECK(o1->SetPrototype(o2));
10491 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10492 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10493 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10494 CHECK(o2->SetPrototype(o3));
10495 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10496 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10497 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10498 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10500 // Getting the prototype of o0 should get the first visible one
10501 // which is o3. Therefore, z should not be defined on the prototype
10503 Local<Value> proto = o0->Get(v8_str("__proto__"));
10504 CHECK(proto->IsObject());
10505 CHECK_EQ(proto.As<v8::Object>(), o3);
10507 // However, Object::GetPrototype ignores hidden prototype.
10508 Local<Value> proto0 = o0->GetPrototype();
10509 CHECK(proto0->IsObject());
10510 CHECK_EQ(proto0.As<v8::Object>(), o1);
10512 Local<Value> proto1 = o1->GetPrototype();
10513 CHECK(proto1->IsObject());
10514 CHECK_EQ(proto1.As<v8::Object>(), o2);
10516 Local<Value> proto2 = o2->GetPrototype();
10517 CHECK(proto2->IsObject());
10518 CHECK_EQ(proto2.As<v8::Object>(), o3);
10522 // Getting property names of an object with a prototype chain that
10523 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10524 // crash the runtime.
10525 THREADED_TEST(Regress91517) {
10526 i::FLAG_allow_natives_syntax = true;
10527 LocalContext context;
10528 v8::Isolate* isolate = context->GetIsolate();
10529 v8::HandleScope handle_scope(isolate);
10531 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10532 t1->SetHiddenPrototype(true);
10533 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10534 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10535 t2->SetHiddenPrototype(true);
10536 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10537 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10538 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10539 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10540 t3->SetHiddenPrototype(true);
10541 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10542 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10543 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10545 // Force dictionary-based properties.
10546 i::ScopedVector<char> name_buf(1024);
10547 for (int i = 1; i <= 1000; i++) {
10548 i::SNPrintF(name_buf, "sdf%d", i);
10549 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10552 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10553 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10554 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10555 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10557 // Create prototype chain of hidden prototypes.
10558 CHECK(o4->SetPrototype(o3));
10559 CHECK(o3->SetPrototype(o2));
10560 CHECK(o2->SetPrototype(o1));
10562 // Call the runtime version of GetOwnPropertyNames() on the natively
10563 // created object through JavaScript.
10564 context->Global()->Set(v8_str("obj"), o4);
10565 // PROPERTY_ATTRIBUTES_NONE = 0
10566 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10568 ExpectInt32("names.length", 1006);
10569 ExpectTrue("names.indexOf(\"baz\") >= 0");
10570 ExpectTrue("names.indexOf(\"boo\") >= 0");
10571 ExpectTrue("names.indexOf(\"foo\") >= 0");
10572 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10573 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10574 ExpectFalse("names[1005] == undefined");
10578 // Getting property names of an object with a hidden and inherited
10579 // prototype should not duplicate the accessor properties inherited.
10580 THREADED_TEST(Regress269562) {
10581 i::FLAG_allow_natives_syntax = true;
10582 LocalContext context;
10583 v8::HandleScope handle_scope(context->GetIsolate());
10585 Local<v8::FunctionTemplate> t1 =
10586 v8::FunctionTemplate::New(context->GetIsolate());
10587 t1->SetHiddenPrototype(true);
10589 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10590 i1->SetAccessor(v8_str("foo"),
10591 SimpleAccessorGetter, SimpleAccessorSetter);
10592 i1->SetAccessor(v8_str("bar"),
10593 SimpleAccessorGetter, SimpleAccessorSetter);
10594 i1->SetAccessor(v8_str("baz"),
10595 SimpleAccessorGetter, SimpleAccessorSetter);
10596 i1->Set(v8_str("n1"), v8_num(1));
10597 i1->Set(v8_str("n2"), v8_num(2));
10599 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10600 Local<v8::FunctionTemplate> t2 =
10601 v8::FunctionTemplate::New(context->GetIsolate());
10602 t2->SetHiddenPrototype(true);
10604 // Inherit from t1 and mark prototype as hidden.
10606 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10608 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10609 CHECK(o2->SetPrototype(o1));
10611 v8::Local<v8::Symbol> sym =
10612 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10613 o1->Set(sym, v8_num(3));
10614 o1->SetHiddenValue(
10615 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10617 // Call the runtime version of GetOwnPropertyNames() on
10618 // the natively created object through JavaScript.
10619 context->Global()->Set(v8_str("obj"), o2);
10620 context->Global()->Set(v8_str("sym"), sym);
10621 // PROPERTY_ATTRIBUTES_NONE = 0
10622 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10624 ExpectInt32("names.length", 7);
10625 ExpectTrue("names.indexOf(\"foo\") >= 0");
10626 ExpectTrue("names.indexOf(\"bar\") >= 0");
10627 ExpectTrue("names.indexOf(\"baz\") >= 0");
10628 ExpectTrue("names.indexOf(\"n1\") >= 0");
10629 ExpectTrue("names.indexOf(\"n2\") >= 0");
10630 ExpectTrue("names.indexOf(sym) >= 0");
10631 ExpectTrue("names.indexOf(\"mine\") >= 0");
10635 THREADED_TEST(FunctionReadOnlyPrototype) {
10636 LocalContext context;
10637 v8::Isolate* isolate = context->GetIsolate();
10638 v8::HandleScope handle_scope(isolate);
10640 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10641 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10642 t1->ReadOnlyPrototype();
10643 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10644 // Configured value of ReadOnly flag.
10647 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10648 " return (descriptor['writable'] == false);"
10649 "})()")->BooleanValue());
10650 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10652 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10654 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10655 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10656 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10657 // Default value of ReadOnly flag.
10660 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10661 " return (descriptor['writable'] == true);"
10662 "})()")->BooleanValue());
10663 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10667 THREADED_TEST(SetPrototypeThrows) {
10668 LocalContext context;
10669 v8::Isolate* isolate = context->GetIsolate();
10670 v8::HandleScope handle_scope(isolate);
10672 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10674 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10675 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10677 CHECK(o0->SetPrototype(o1));
10678 // If setting the prototype leads to the cycle, SetPrototype should
10679 // return false and keep VM in sane state.
10680 v8::TryCatch try_catch;
10681 CHECK(!o1->SetPrototype(o0));
10682 CHECK(!try_catch.HasCaught());
10683 DCHECK(!CcTest::i_isolate()->has_pending_exception());
10685 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10689 THREADED_TEST(FunctionRemovePrototype) {
10690 LocalContext context;
10691 v8::Isolate* isolate = context->GetIsolate();
10692 v8::HandleScope handle_scope(isolate);
10694 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10695 t1->RemovePrototype();
10696 Local<v8::Function> fun = t1->GetFunction();
10697 context->Global()->Set(v8_str("fun"), fun);
10698 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10700 v8::TryCatch try_catch;
10701 CompileRun("new fun()");
10702 CHECK(try_catch.HasCaught());
10705 fun->NewInstance();
10706 CHECK(try_catch.HasCaught());
10710 THREADED_TEST(GetterSetterExceptions) {
10711 LocalContext context;
10712 v8::Isolate* isolate = context->GetIsolate();
10713 v8::HandleScope handle_scope(isolate);
10715 "function Foo() { };"
10716 "function Throw() { throw 5; };"
10718 "x.__defineSetter__('set', Throw);"
10719 "x.__defineGetter__('get', Throw);");
10720 Local<v8::Object> x =
10721 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10722 v8::TryCatch try_catch;
10723 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10724 x->Get(v8_str("get"));
10725 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10726 x->Get(v8_str("get"));
10727 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10728 x->Get(v8_str("get"));
10729 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10730 x->Get(v8_str("get"));
10734 THREADED_TEST(Constructor) {
10735 LocalContext context;
10736 v8::Isolate* isolate = context->GetIsolate();
10737 v8::HandleScope handle_scope(isolate);
10738 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10739 templ->SetClassName(v8_str("Fun"));
10740 Local<Function> cons = templ->GetFunction();
10741 context->Global()->Set(v8_str("Fun"), cons);
10742 Local<v8::Object> inst = cons->NewInstance();
10743 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10744 CHECK(obj->IsJSObject());
10745 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10746 CHECK(value->BooleanValue());
10750 static void ConstructorCallback(
10751 const v8::FunctionCallbackInfo<v8::Value>& args) {
10752 ApiTestFuzzer::Fuzz();
10753 Local<Object> This;
10755 if (args.IsConstructCall()) {
10756 Local<Object> Holder = args.Holder();
10757 This = Object::New(args.GetIsolate());
10758 Local<Value> proto = Holder->GetPrototype();
10759 if (proto->IsObject()) {
10760 This->SetPrototype(proto);
10763 This = args.This();
10766 This->Set(v8_str("a"), args[0]);
10767 args.GetReturnValue().Set(This);
10771 static void FakeConstructorCallback(
10772 const v8::FunctionCallbackInfo<v8::Value>& args) {
10773 ApiTestFuzzer::Fuzz();
10774 args.GetReturnValue().Set(args[0]);
10778 THREADED_TEST(ConstructorForObject) {
10779 LocalContext context;
10780 v8::Isolate* isolate = context->GetIsolate();
10781 v8::HandleScope handle_scope(isolate);
10783 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10784 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10785 Local<Object> instance = instance_template->NewInstance();
10786 context->Global()->Set(v8_str("obj"), instance);
10787 v8::TryCatch try_catch;
10788 Local<Value> value;
10789 CHECK(!try_catch.HasCaught());
10791 // Call the Object's constructor with a 32-bit signed integer.
10792 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10793 CHECK(!try_catch.HasCaught());
10794 CHECK(value->IsInt32());
10795 CHECK_EQ(28, value->Int32Value());
10797 Local<Value> args1[] = { v8_num(28) };
10798 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10799 CHECK(value_obj1->IsObject());
10800 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10801 value = object1->Get(v8_str("a"));
10802 CHECK(value->IsInt32());
10803 CHECK(!try_catch.HasCaught());
10804 CHECK_EQ(28, value->Int32Value());
10806 // Call the Object's constructor with a String.
10807 value = CompileRun(
10808 "(function() { var o = new obj('tipli'); return o.a; })()");
10809 CHECK(!try_catch.HasCaught());
10810 CHECK(value->IsString());
10811 String::Utf8Value string_value1(value->ToString());
10812 CHECK_EQ("tipli", *string_value1);
10814 Local<Value> args2[] = { v8_str("tipli") };
10815 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10816 CHECK(value_obj2->IsObject());
10817 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10818 value = object2->Get(v8_str("a"));
10819 CHECK(!try_catch.HasCaught());
10820 CHECK(value->IsString());
10821 String::Utf8Value string_value2(value->ToString());
10822 CHECK_EQ("tipli", *string_value2);
10824 // Call the Object's constructor with a Boolean.
10825 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10826 CHECK(!try_catch.HasCaught());
10827 CHECK(value->IsBoolean());
10828 CHECK_EQ(true, value->BooleanValue());
10830 Handle<Value> args3[] = { v8::True(isolate) };
10831 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10832 CHECK(value_obj3->IsObject());
10833 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10834 value = object3->Get(v8_str("a"));
10835 CHECK(!try_catch.HasCaught());
10836 CHECK(value->IsBoolean());
10837 CHECK_EQ(true, value->BooleanValue());
10839 // Call the Object's constructor with undefined.
10840 Handle<Value> args4[] = { v8::Undefined(isolate) };
10841 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10842 CHECK(value_obj4->IsObject());
10843 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10844 value = object4->Get(v8_str("a"));
10845 CHECK(!try_catch.HasCaught());
10846 CHECK(value->IsUndefined());
10848 // Call the Object's constructor with null.
10849 Handle<Value> args5[] = { v8::Null(isolate) };
10850 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10851 CHECK(value_obj5->IsObject());
10852 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10853 value = object5->Get(v8_str("a"));
10854 CHECK(!try_catch.HasCaught());
10855 CHECK(value->IsNull());
10858 // Check exception handling when there is no constructor set for the Object.
10859 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10860 Local<Object> instance = instance_template->NewInstance();
10861 context->Global()->Set(v8_str("obj2"), instance);
10862 v8::TryCatch try_catch;
10863 Local<Value> value;
10864 CHECK(!try_catch.HasCaught());
10866 value = CompileRun("new obj2(28)");
10867 CHECK(try_catch.HasCaught());
10868 String::Utf8Value exception_value1(try_catch.Exception());
10869 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10872 Local<Value> args[] = { v8_num(29) };
10873 value = instance->CallAsConstructor(1, args);
10874 CHECK(try_catch.HasCaught());
10875 String::Utf8Value exception_value2(try_catch.Exception());
10876 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10880 // Check the case when constructor throws exception.
10881 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10882 instance_template->SetCallAsFunctionHandler(ThrowValue);
10883 Local<Object> instance = instance_template->NewInstance();
10884 context->Global()->Set(v8_str("obj3"), instance);
10885 v8::TryCatch try_catch;
10886 Local<Value> value;
10887 CHECK(!try_catch.HasCaught());
10889 value = CompileRun("new obj3(22)");
10890 CHECK(try_catch.HasCaught());
10891 String::Utf8Value exception_value1(try_catch.Exception());
10892 CHECK_EQ("22", *exception_value1);
10895 Local<Value> args[] = { v8_num(23) };
10896 value = instance->CallAsConstructor(1, args);
10897 CHECK(try_catch.HasCaught());
10898 String::Utf8Value exception_value2(try_catch.Exception());
10899 CHECK_EQ("23", *exception_value2);
10903 // Check whether constructor returns with an object or non-object.
10904 { Local<FunctionTemplate> function_template =
10905 FunctionTemplate::New(isolate, FakeConstructorCallback);
10906 Local<Function> function = function_template->GetFunction();
10907 Local<Object> instance1 = function;
10908 context->Global()->Set(v8_str("obj4"), instance1);
10909 v8::TryCatch try_catch;
10910 Local<Value> value;
10911 CHECK(!try_catch.HasCaught());
10913 CHECK(instance1->IsObject());
10914 CHECK(instance1->IsFunction());
10916 value = CompileRun("new obj4(28)");
10917 CHECK(!try_catch.HasCaught());
10918 CHECK(value->IsObject());
10920 Local<Value> args1[] = { v8_num(28) };
10921 value = instance1->CallAsConstructor(1, args1);
10922 CHECK(!try_catch.HasCaught());
10923 CHECK(value->IsObject());
10925 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10926 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10927 Local<Object> instance2 = instance_template->NewInstance();
10928 context->Global()->Set(v8_str("obj5"), instance2);
10929 CHECK(!try_catch.HasCaught());
10931 CHECK(instance2->IsObject());
10932 CHECK(!instance2->IsFunction());
10934 value = CompileRun("new obj5(28)");
10935 CHECK(!try_catch.HasCaught());
10936 CHECK(!value->IsObject());
10938 Local<Value> args2[] = { v8_num(28) };
10939 value = instance2->CallAsConstructor(1, args2);
10940 CHECK(!try_catch.HasCaught());
10941 CHECK(!value->IsObject());
10946 THREADED_TEST(FunctionDescriptorException) {
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<Value> value = CompileRun(
10955 "function test() {"
10957 " (new Fun()).blah()"
10959 " var str = String(e);"
10960 // " if (str.indexOf('TypeError') == -1) return 1;"
10961 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10962 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10968 CHECK_EQ(0, value->Int32Value());
10972 THREADED_TEST(EvalAliasedDynamic) {
10973 LocalContext current;
10974 v8::HandleScope scope(current->GetIsolate());
10976 // Tests where aliased eval can only be resolved dynamically.
10977 Local<Script> script = v8_compile(
10980 " with (x) { return eval('foo'); }"
10983 "result1 = f(new Object());"
10984 "result2 = f(this);"
10985 "var x = new Object();"
10986 "x.eval = function(x) { return 1; };"
10987 "result3 = f(x);");
10989 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10990 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10991 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10993 v8::TryCatch try_catch;
10994 script = v8_compile(
10997 " with (x) { return eval('bar'); }"
10999 "result4 = f(this)");
11001 CHECK(!try_catch.HasCaught());
11002 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11008 THREADED_TEST(CrossEval) {
11009 v8::HandleScope scope(CcTest::isolate());
11010 LocalContext other;
11011 LocalContext current;
11013 Local<String> token = v8_str("<security token>");
11014 other->SetSecurityToken(token);
11015 current->SetSecurityToken(token);
11017 // Set up reference from current to other.
11018 current->Global()->Set(v8_str("other"), other->Global());
11020 // Check that new variables are introduced in other context.
11021 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11023 Local<Value> foo = other->Global()->Get(v8_str("foo"));
11024 CHECK_EQ(1234, foo->Int32Value());
11025 CHECK(!current->Global()->Has(v8_str("foo")));
11027 // Check that writing to non-existing properties introduces them in
11028 // the other context.
11029 script = v8_compile("other.eval('na = 1234')");
11031 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11032 CHECK(!current->Global()->Has(v8_str("na")));
11034 // Check that global variables in current context are not visible in other
11036 v8::TryCatch try_catch;
11037 script = v8_compile("var bar = 42; other.eval('bar');");
11038 Local<Value> result = script->Run();
11039 CHECK(try_catch.HasCaught());
11042 // Check that local variables in current context are not visible in other
11044 script = v8_compile(
11047 " return other.eval('baz');"
11049 result = script->Run();
11050 CHECK(try_catch.HasCaught());
11053 // Check that global variables in the other environment are visible
11054 // when evaluting code.
11055 other->Global()->Set(v8_str("bis"), v8_num(1234));
11056 script = v8_compile("other.eval('bis')");
11057 CHECK_EQ(1234, script->Run()->Int32Value());
11058 CHECK(!try_catch.HasCaught());
11060 // Check that the 'this' pointer points to the global object evaluating
11062 other->Global()->Set(v8_str("t"), other->Global());
11063 script = v8_compile("other.eval('this == t')");
11064 result = script->Run();
11065 CHECK(result->IsTrue());
11066 CHECK(!try_catch.HasCaught());
11068 // Check that variables introduced in with-statement are not visible in
11070 script = v8_compile("with({x:2}){other.eval('x')}");
11071 result = script->Run();
11072 CHECK(try_catch.HasCaught());
11075 // Check that you cannot use 'eval.call' with another object than the
11076 // current global object.
11077 script = v8_compile("other.y = 1; eval.call(other, 'y')");
11078 result = script->Run();
11079 CHECK(try_catch.HasCaught());
11083 // Test that calling eval in a context which has been detached from
11084 // its global throws an exception. This behavior is consistent with
11085 // other JavaScript implementations.
11086 THREADED_TEST(EvalInDetachedGlobal) {
11087 v8::Isolate* isolate = CcTest::isolate();
11088 v8::HandleScope scope(isolate);
11090 v8::Local<Context> context0 = Context::New(isolate);
11091 v8::Local<Context> context1 = Context::New(isolate);
11093 // Set up function in context0 that uses eval from context0.
11095 v8::Handle<v8::Value> fun =
11096 CompileRun("var x = 42;"
11099 " return function(s) { return e(s); }"
11103 // Put the function into context1 and call it before and after
11104 // detaching the global. Before detaching, the call succeeds and
11105 // after detaching and exception is thrown.
11107 context1->Global()->Set(v8_str("fun"), fun);
11108 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11109 CHECK_EQ(42, x_value->Int32Value());
11110 context0->DetachGlobal();
11111 v8::TryCatch catcher;
11112 x_value = CompileRun("fun('x')");
11113 CHECK(x_value.IsEmpty());
11114 CHECK(catcher.HasCaught());
11119 THREADED_TEST(CrossLazyLoad) {
11120 v8::HandleScope scope(CcTest::isolate());
11121 LocalContext other;
11122 LocalContext current;
11124 Local<String> token = v8_str("<security token>");
11125 other->SetSecurityToken(token);
11126 current->SetSecurityToken(token);
11128 // Set up reference from current to other.
11129 current->Global()->Set(v8_str("other"), other->Global());
11131 // Trigger lazy loading in other context.
11132 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11133 Local<Value> value = script->Run();
11134 CHECK_EQ(42.0, value->NumberValue());
11138 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11139 ApiTestFuzzer::Fuzz();
11140 if (args.IsConstructCall()) {
11141 if (args[0]->IsInt32()) {
11142 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11147 args.GetReturnValue().Set(args[0]);
11151 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11152 args.GetReturnValue().Set(args.This());
11156 // Test that a call handler can be set for objects which will allow
11157 // non-function objects created through the API to be called as
11159 THREADED_TEST(CallAsFunction) {
11160 LocalContext context;
11161 v8::Isolate* isolate = context->GetIsolate();
11162 v8::HandleScope scope(isolate);
11164 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11165 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11166 instance_template->SetCallAsFunctionHandler(call_as_function);
11167 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11168 context->Global()->Set(v8_str("obj"), instance);
11169 v8::TryCatch try_catch;
11170 Local<Value> value;
11171 CHECK(!try_catch.HasCaught());
11173 value = CompileRun("obj(42)");
11174 CHECK(!try_catch.HasCaught());
11175 CHECK_EQ(42, value->Int32Value());
11177 value = CompileRun("(function(o){return o(49)})(obj)");
11178 CHECK(!try_catch.HasCaught());
11179 CHECK_EQ(49, value->Int32Value());
11181 // test special case of call as function
11182 value = CompileRun("[obj]['0'](45)");
11183 CHECK(!try_catch.HasCaught());
11184 CHECK_EQ(45, value->Int32Value());
11186 value = CompileRun("obj.call = Function.prototype.call;"
11187 "obj.call(null, 87)");
11188 CHECK(!try_catch.HasCaught());
11189 CHECK_EQ(87, value->Int32Value());
11191 // Regression tests for bug #1116356: Calling call through call/apply
11192 // must work for non-function receivers.
11193 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11194 value = CompileRun(apply_99);
11195 CHECK(!try_catch.HasCaught());
11196 CHECK_EQ(99, value->Int32Value());
11198 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11199 value = CompileRun(call_17);
11200 CHECK(!try_catch.HasCaught());
11201 CHECK_EQ(17, value->Int32Value());
11203 // Check that the call-as-function handler can be called through
11205 value = CompileRun("new obj(43)");
11206 CHECK(!try_catch.HasCaught());
11207 CHECK_EQ(-43, value->Int32Value());
11209 // Check that the call-as-function handler can be called through
11211 v8::Handle<Value> args[] = { v8_num(28) };
11212 value = instance->CallAsFunction(instance, 1, args);
11213 CHECK(!try_catch.HasCaught());
11214 CHECK_EQ(28, value->Int32Value());
11217 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11218 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11219 USE(instance_template);
11220 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11221 context->Global()->Set(v8_str("obj2"), instance);
11222 v8::TryCatch try_catch;
11223 Local<Value> value;
11224 CHECK(!try_catch.HasCaught());
11226 // Call an object without call-as-function handler through the JS
11227 value = CompileRun("obj2(28)");
11228 CHECK(value.IsEmpty());
11229 CHECK(try_catch.HasCaught());
11230 String::Utf8Value exception_value1(try_catch.Exception());
11231 // TODO(verwaest): Better message
11232 CHECK_EQ("TypeError: object is not a function",
11233 *exception_value1);
11236 // Call an object without call-as-function handler through the API
11237 value = CompileRun("obj2(28)");
11238 v8::Handle<Value> args[] = { v8_num(28) };
11239 value = instance->CallAsFunction(instance, 1, args);
11240 CHECK(value.IsEmpty());
11241 CHECK(try_catch.HasCaught());
11242 String::Utf8Value exception_value2(try_catch.Exception());
11243 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11247 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11248 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11249 instance_template->SetCallAsFunctionHandler(ThrowValue);
11250 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11251 context->Global()->Set(v8_str("obj3"), instance);
11252 v8::TryCatch try_catch;
11253 Local<Value> value;
11254 CHECK(!try_catch.HasCaught());
11256 // Catch the exception which is thrown by call-as-function handler
11257 value = CompileRun("obj3(22)");
11258 CHECK(try_catch.HasCaught());
11259 String::Utf8Value exception_value1(try_catch.Exception());
11260 CHECK_EQ("22", *exception_value1);
11263 v8::Handle<Value> args[] = { v8_num(23) };
11264 value = instance->CallAsFunction(instance, 1, args);
11265 CHECK(try_catch.HasCaught());
11266 String::Utf8Value exception_value2(try_catch.Exception());
11267 CHECK_EQ("23", *exception_value2);
11271 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11272 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11273 instance_template->SetCallAsFunctionHandler(ReturnThis);
11274 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11276 Local<v8::Value> a1 =
11277 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11278 CHECK(a1->StrictEquals(instance));
11279 Local<v8::Value> a2 =
11280 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11281 CHECK(a2->StrictEquals(instance));
11282 Local<v8::Value> a3 =
11283 instance->CallAsFunction(v8_num(42), 0, NULL);
11284 CHECK(a3->StrictEquals(instance));
11285 Local<v8::Value> a4 =
11286 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11287 CHECK(a4->StrictEquals(instance));
11288 Local<v8::Value> a5 =
11289 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11290 CHECK(a5->StrictEquals(instance));
11294 "function ReturnThisSloppy() {"
11297 "function ReturnThisStrict() {"
11301 Local<Function> ReturnThisSloppy =
11302 Local<Function>::Cast(
11303 context->Global()->Get(v8_str("ReturnThisSloppy")));
11304 Local<Function> ReturnThisStrict =
11305 Local<Function>::Cast(
11306 context->Global()->Get(v8_str("ReturnThisStrict")));
11308 Local<v8::Value> a1 =
11309 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11310 CHECK(a1->StrictEquals(context->Global()));
11311 Local<v8::Value> a2 =
11312 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11313 CHECK(a2->StrictEquals(context->Global()));
11314 Local<v8::Value> a3 =
11315 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11316 CHECK(a3->IsNumberObject());
11317 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11318 Local<v8::Value> a4 =
11319 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11320 CHECK(a4->IsStringObject());
11321 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11322 Local<v8::Value> a5 =
11323 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11324 CHECK(a5->IsBooleanObject());
11325 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11327 Local<v8::Value> a6 =
11328 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11329 CHECK(a6->IsUndefined());
11330 Local<v8::Value> a7 =
11331 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11332 CHECK(a7->IsNull());
11333 Local<v8::Value> a8 =
11334 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11335 CHECK(a8->StrictEquals(v8_num(42)));
11336 Local<v8::Value> a9 =
11337 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11338 CHECK(a9->StrictEquals(v8_str("hello")));
11339 Local<v8::Value> a10 =
11340 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11341 CHECK(a10->StrictEquals(v8::True(isolate)));
11346 // Check whether a non-function object is callable.
11347 THREADED_TEST(CallableObject) {
11348 LocalContext context;
11349 v8::Isolate* isolate = context->GetIsolate();
11350 v8::HandleScope scope(isolate);
11352 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11353 instance_template->SetCallAsFunctionHandler(call_as_function);
11354 Local<Object> instance = instance_template->NewInstance();
11355 v8::TryCatch try_catch;
11357 CHECK(instance->IsCallable());
11358 CHECK(!try_catch.HasCaught());
11361 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11362 Local<Object> instance = instance_template->NewInstance();
11363 v8::TryCatch try_catch;
11365 CHECK(!instance->IsCallable());
11366 CHECK(!try_catch.HasCaught());
11369 { Local<FunctionTemplate> function_template =
11370 FunctionTemplate::New(isolate, call_as_function);
11371 Local<Function> function = function_template->GetFunction();
11372 Local<Object> instance = function;
11373 v8::TryCatch try_catch;
11375 CHECK(instance->IsCallable());
11376 CHECK(!try_catch.HasCaught());
11379 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11380 Local<Function> function = function_template->GetFunction();
11381 Local<Object> instance = function;
11382 v8::TryCatch try_catch;
11384 CHECK(instance->IsCallable());
11385 CHECK(!try_catch.HasCaught());
11390 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11391 v8::HandleScope scope(isolate);
11392 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11393 for (int i = 0; i < iterations; i++) {
11394 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11396 return Recurse(isolate, depth - 1, iterations);
11400 THREADED_TEST(HandleIteration) {
11401 static const int kIterations = 500;
11402 static const int kNesting = 200;
11403 LocalContext context;
11404 v8::Isolate* isolate = context->GetIsolate();
11405 v8::HandleScope scope0(isolate);
11406 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11408 v8::HandleScope scope1(isolate);
11409 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11410 for (int i = 0; i < kIterations; i++) {
11411 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11412 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11415 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11417 v8::HandleScope scope2(CcTest::isolate());
11418 for (int j = 0; j < kIterations; j++) {
11419 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11420 CHECK_EQ(j + 1 + kIterations,
11421 v8::HandleScope::NumberOfHandles(isolate));
11424 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11426 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11427 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11431 static void InterceptorHasOwnPropertyGetter(
11432 Local<String> name,
11433 const v8::PropertyCallbackInfo<v8::Value>& info) {
11434 ApiTestFuzzer::Fuzz();
11438 THREADED_TEST(InterceptorHasOwnProperty) {
11439 LocalContext context;
11440 v8::Isolate* isolate = context->GetIsolate();
11441 v8::HandleScope scope(isolate);
11442 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11443 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11444 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11445 Local<Function> function = fun_templ->GetFunction();
11446 context->Global()->Set(v8_str("constructor"), function);
11447 v8::Handle<Value> value = CompileRun(
11448 "var o = new constructor();"
11449 "o.hasOwnProperty('ostehaps');");
11450 CHECK_EQ(false, value->BooleanValue());
11451 value = CompileRun(
11453 "o.hasOwnProperty('ostehaps');");
11454 CHECK_EQ(true, value->BooleanValue());
11455 value = CompileRun(
11456 "var p = new constructor();"
11457 "p.hasOwnProperty('ostehaps');");
11458 CHECK_EQ(false, value->BooleanValue());
11462 static void InterceptorHasOwnPropertyGetterGC(
11463 Local<String> name,
11464 const v8::PropertyCallbackInfo<v8::Value>& info) {
11465 ApiTestFuzzer::Fuzz();
11466 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11470 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11471 LocalContext context;
11472 v8::Isolate* isolate = context->GetIsolate();
11473 v8::HandleScope scope(isolate);
11474 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11475 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11476 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11477 Local<Function> function = fun_templ->GetFunction();
11478 context->Global()->Set(v8_str("constructor"), function);
11479 // Let's first make some stuff so we can be sure to get a good GC.
11481 "function makestr(size) {"
11483 " case 1: return 'f';"
11484 " case 2: return 'fo';"
11485 " case 3: return 'foo';"
11487 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11489 "var x = makestr(12345);"
11490 "x = makestr(31415);"
11491 "x = makestr(23456);");
11492 v8::Handle<Value> value = CompileRun(
11493 "var o = new constructor();"
11494 "o.__proto__ = new String(x);"
11495 "o.hasOwnProperty('ostehaps');");
11496 CHECK_EQ(false, value->BooleanValue());
11500 typedef void (*NamedPropertyGetter)(
11501 Local<String> property,
11502 const v8::PropertyCallbackInfo<v8::Value>& info);
11505 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11506 const char* source,
11508 v8::Isolate* isolate = CcTest::isolate();
11509 v8::HandleScope scope(isolate);
11510 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11511 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11512 LocalContext context;
11513 context->Global()->Set(v8_str("o"), templ->NewInstance());
11514 v8::Handle<Value> value = CompileRun(source);
11515 CHECK_EQ(expected, value->Int32Value());
11519 static void InterceptorLoadICGetter(
11520 Local<String> name,
11521 const v8::PropertyCallbackInfo<v8::Value>& info) {
11522 ApiTestFuzzer::Fuzz();
11523 v8::Isolate* isolate = CcTest::isolate();
11524 CHECK_EQ(isolate, info.GetIsolate());
11525 CHECK_EQ(v8_str("data"), info.Data());
11526 CHECK_EQ(v8_str("x"), name);
11527 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11531 // This test should hit the load IC for the interceptor case.
11532 THREADED_TEST(InterceptorLoadIC) {
11533 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11535 "for (var i = 0; i < 1000; i++) {"
11542 // Below go several tests which verify that JITing for various
11543 // configurations of interceptor and explicit fields works fine
11544 // (those cases are special cased to get better performance).
11546 static void InterceptorLoadXICGetter(
11547 Local<String> name,
11548 const v8::PropertyCallbackInfo<v8::Value>& info) {
11549 ApiTestFuzzer::Fuzz();
11550 info.GetReturnValue().Set(
11551 v8_str("x")->Equals(name) ?
11552 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11553 v8::Handle<v8::Value>());
11557 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11558 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11561 "for (var i = 0; i < 1000; i++) {"
11568 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11569 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11571 "o.__proto__ = { 'y': 239 };"
11572 "for (var i = 0; i < 1000; i++) {"
11573 " result = o.y + o.x;"
11579 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11580 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11582 "o.__proto__.y = 239;"
11583 "for (var i = 0; i < 1000; i++) {"
11584 " result = o.y + o.x;"
11590 THREADED_TEST(InterceptorLoadICUndefined) {
11591 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11593 "for (var i = 0; i < 1000; i++) {"
11594 " result = (o.y == undefined) ? 239 : 42;"
11600 THREADED_TEST(InterceptorLoadICWithOverride) {
11601 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11602 "fst = new Object(); fst.__proto__ = o;"
11603 "snd = new Object(); snd.__proto__ = fst;"
11605 "for (var i = 0; i < 1000; i++) {"
11606 " result1 = snd.x;"
11610 "for (var i = 0; i < 1000; i++) {"
11613 "result + result1",
11618 // Test the case when we stored field into
11619 // a stub, but interceptor produced value on its own.
11620 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11621 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11622 "proto = new Object();"
11623 "o.__proto__ = proto;"
11625 "for (var i = 0; i < 1000; i++) {"
11627 // Now it should be ICed and keep a reference to x defined on proto
11630 "for (var i = 0; i < 1000; i++) {"
11638 // Test the case when we stored field into
11639 // a stub, but it got invalidated later on.
11640 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11641 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11642 "proto1 = new Object();"
11643 "proto2 = new Object();"
11644 "o.__proto__ = proto1;"
11645 "proto1.__proto__ = proto2;"
11647 "for (var i = 0; i < 1000; i++) {"
11649 // Now it should be ICed and keep a reference to y defined on proto2
11653 "for (var i = 0; i < 1000; i++) {"
11661 static int interceptor_load_not_handled_calls = 0;
11662 static void InterceptorLoadNotHandled(
11663 Local<String> name,
11664 const v8::PropertyCallbackInfo<v8::Value>& info) {
11665 ++interceptor_load_not_handled_calls;
11669 // Test how post-interceptor lookups are done in the non-cacheable
11670 // case: the interceptor should not be invoked during this lookup.
11671 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11672 interceptor_load_not_handled_calls = 0;
11673 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11674 "receiver = new Object();"
11675 "receiver.__proto__ = o;"
11676 "proto = new Object();"
11677 "/* Make proto a slow-case object. */"
11678 "for (var i = 0; i < 1000; i++) {"
11679 " proto[\"xxxxxxxx\" + i] = [];"
11682 "o.__proto__ = proto;"
11684 "for (var i = 0; i < 1000; i++) {"
11685 " result += receiver.x;"
11689 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11693 // Test the case when we stored field into
11694 // a stub, but it got invalidated later on due to override on
11695 // global object which is between interceptor and fields' holders.
11696 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11697 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11698 "o.__proto__ = this;" // set a global to be a proto of o.
11699 "this.__proto__.y = 239;"
11700 "for (var i = 0; i < 10; i++) {"
11701 " if (o.y != 239) throw 'oops: ' + o.y;"
11702 // Now it should be ICed and keep a reference to y defined on field_holder.
11704 "this.y = 42;" // Assign on a global.
11706 "for (var i = 0; i < 10; i++) {"
11714 static void SetOnThis(Local<String> name,
11715 Local<Value> value,
11716 const v8::PropertyCallbackInfo<void>& info) {
11717 Local<Object>::Cast(info.This())->ForceSet(name, value);
11721 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11722 v8::Isolate* isolate = CcTest::isolate();
11723 v8::HandleScope scope(isolate);
11724 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11725 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11726 templ->SetAccessor(v8_str("y"), Return239Callback);
11727 LocalContext context;
11728 context->Global()->Set(v8_str("o"), templ->NewInstance());
11730 // Check the case when receiver and interceptor's holder
11731 // are the same objects.
11732 v8::Handle<Value> value = CompileRun(
11734 "for (var i = 0; i < 7; i++) {"
11737 CHECK_EQ(239, value->Int32Value());
11739 // Check the case when interceptor's holder is in proto chain
11741 value = CompileRun(
11742 "r = { __proto__: o };"
11744 "for (var i = 0; i < 7; i++) {"
11747 CHECK_EQ(239, value->Int32Value());
11751 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11752 v8::Isolate* isolate = CcTest::isolate();
11753 v8::HandleScope scope(isolate);
11754 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11755 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11756 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11757 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11759 LocalContext context;
11760 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11761 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11763 // Check the case when receiver and interceptor's holder
11764 // are the same objects.
11765 v8::Handle<Value> value = CompileRun(
11768 "for (var i = 0; i < 7; i++) {"
11769 " result = o.x + o.y;"
11771 CHECK_EQ(239 + 42, value->Int32Value());
11773 // Check the case when interceptor's holder is in proto chain
11775 value = CompileRun(
11776 "r = { __proto__: o };"
11778 "for (var i = 0; i < 7; i++) {"
11779 " result = r.x + r.y;"
11781 CHECK_EQ(239 + 42, value->Int32Value());
11785 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11786 v8::Isolate* isolate = CcTest::isolate();
11787 v8::HandleScope scope(isolate);
11788 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11789 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11790 templ->SetAccessor(v8_str("y"), Return239Callback);
11792 LocalContext context;
11793 context->Global()->Set(v8_str("o"), templ->NewInstance());
11795 v8::Handle<Value> value = CompileRun(
11796 "fst = new Object(); fst.__proto__ = o;"
11797 "snd = new Object(); snd.__proto__ = fst;"
11799 "for (var i = 0; i < 7; i++) {"
11800 " result1 = snd.x;"
11804 "for (var i = 0; i < 7; i++) {"
11807 "result + result1");
11808 CHECK_EQ(239 + 42, value->Int32Value());
11812 // Test the case when we stored callback into
11813 // a stub, but interceptor produced value on its own.
11814 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11815 v8::Isolate* isolate = CcTest::isolate();
11816 v8::HandleScope scope(isolate);
11817 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11818 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11819 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11820 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11822 LocalContext context;
11823 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11824 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11826 v8::Handle<Value> value = CompileRun(
11828 "for (var i = 0; i < 7; i++) {"
11830 // Now it should be ICed and keep a reference to x defined on p
11833 "for (var i = 0; i < 7; i++) {"
11837 CHECK_EQ(42 * 7, value->Int32Value());
11841 // Test the case when we stored callback into
11842 // a stub, but it got invalidated later on.
11843 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11844 v8::Isolate* isolate = CcTest::isolate();
11845 v8::HandleScope scope(isolate);
11846 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11847 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11848 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11849 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11851 LocalContext context;
11852 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11853 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11855 v8::Handle<Value> value = CompileRun(
11856 "inbetween = new Object();"
11857 "o.__proto__ = inbetween;"
11858 "inbetween.__proto__ = p;"
11859 "for (var i = 0; i < 10; i++) {"
11861 // Now it should be ICed and keep a reference to y defined on p
11863 "inbetween.y = 42;"
11865 "for (var i = 0; i < 10; i++) {"
11869 CHECK_EQ(42 * 10, value->Int32Value());
11873 // Test the case when we stored callback into
11874 // a stub, but it got invalidated later on due to override on
11875 // global object which is between interceptor and callbacks' holders.
11876 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11877 v8::Isolate* isolate = CcTest::isolate();
11878 v8::HandleScope scope(isolate);
11879 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11880 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11881 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11882 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11884 LocalContext context;
11885 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11886 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11888 v8::Handle<Value> value = CompileRun(
11889 "o.__proto__ = this;"
11890 "this.__proto__ = p;"
11891 "for (var i = 0; i < 10; i++) {"
11892 " if (o.y != 239) throw 'oops: ' + o.y;"
11893 // Now it should be ICed and keep a reference to y defined on p
11897 "for (var i = 0; i < 10; i++) {"
11901 CHECK_EQ(42 * 10, value->Int32Value());
11905 static void InterceptorLoadICGetter0(
11906 Local<String> name,
11907 const v8::PropertyCallbackInfo<v8::Value>& info) {
11908 ApiTestFuzzer::Fuzz();
11909 CHECK(v8_str("x")->Equals(name));
11910 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11914 THREADED_TEST(InterceptorReturningZero) {
11915 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11916 "o.x == undefined ? 1 : 0",
11921 static void InterceptorStoreICSetter(
11923 Local<Value> value,
11924 const v8::PropertyCallbackInfo<v8::Value>& info) {
11925 CHECK(v8_str("x")->Equals(key));
11926 CHECK_EQ(42, value->Int32Value());
11927 info.GetReturnValue().Set(value);
11931 // This test should hit the store IC for the interceptor case.
11932 THREADED_TEST(InterceptorStoreIC) {
11933 v8::Isolate* isolate = CcTest::isolate();
11934 v8::HandleScope scope(isolate);
11935 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11936 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11937 InterceptorStoreICSetter,
11938 0, 0, 0, v8_str("data"));
11939 LocalContext context;
11940 context->Global()->Set(v8_str("o"), templ->NewInstance());
11942 "for (var i = 0; i < 1000; i++) {"
11948 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11949 v8::Isolate* isolate = CcTest::isolate();
11950 v8::HandleScope scope(isolate);
11951 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11952 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11953 LocalContext context;
11954 context->Global()->Set(v8_str("o"), templ->NewInstance());
11955 v8::Handle<Value> value = CompileRun(
11956 "for (var i = 0; i < 1000; i++) {"
11960 CHECK_EQ(239 + 42, value->Int32Value());
11966 v8::Handle<Value> call_ic_function;
11967 v8::Handle<Value> call_ic_function2;
11968 v8::Handle<Value> call_ic_function3;
11970 static void InterceptorCallICGetter(
11971 Local<String> name,
11972 const v8::PropertyCallbackInfo<v8::Value>& info) {
11973 ApiTestFuzzer::Fuzz();
11974 CHECK(v8_str("x")->Equals(name));
11975 info.GetReturnValue().Set(call_ic_function);
11979 // This test should hit the call IC for the interceptor case.
11980 THREADED_TEST(InterceptorCallIC) {
11981 v8::Isolate* isolate = CcTest::isolate();
11982 v8::HandleScope scope(isolate);
11983 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11984 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11985 LocalContext context;
11986 context->Global()->Set(v8_str("o"), templ->NewInstance());
11988 v8_compile("function f(x) { return x + 1; }; f")->Run();
11989 v8::Handle<Value> value = CompileRun(
11991 "for (var i = 0; i < 1000; i++) {"
11992 " result = o.x(41);"
11994 CHECK_EQ(42, value->Int32Value());
11998 // This test checks that if interceptor doesn't provide
11999 // a value, we can fetch regular value.
12000 THREADED_TEST(InterceptorCallICSeesOthers) {
12001 v8::Isolate* isolate = CcTest::isolate();
12002 v8::HandleScope scope(isolate);
12003 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12004 templ->SetNamedPropertyHandler(NoBlockGetterX);
12005 LocalContext context;
12006 context->Global()->Set(v8_str("o"), templ->NewInstance());
12007 v8::Handle<Value> value = CompileRun(
12008 "o.x = function f(x) { return x + 1; };"
12010 "for (var i = 0; i < 7; i++) {"
12011 " result = o.x(41);"
12013 CHECK_EQ(42, value->Int32Value());
12017 static v8::Handle<Value> call_ic_function4;
12018 static void InterceptorCallICGetter4(
12019 Local<String> name,
12020 const v8::PropertyCallbackInfo<v8::Value>& info) {
12021 ApiTestFuzzer::Fuzz();
12022 CHECK(v8_str("x")->Equals(name));
12023 info.GetReturnValue().Set(call_ic_function4);
12027 // This test checks that if interceptor provides a function,
12028 // even if we cached shadowed variant, interceptor's function
12030 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12031 v8::Isolate* isolate = CcTest::isolate();
12032 v8::HandleScope scope(isolate);
12033 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12034 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
12035 LocalContext context;
12036 context->Global()->Set(v8_str("o"), templ->NewInstance());
12037 call_ic_function4 =
12038 v8_compile("function f(x) { return x - 1; }; f")->Run();
12039 v8::Handle<Value> value = CompileRun(
12040 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12042 "for (var i = 0; i < 1000; i++) {"
12043 " result = o.x(42);"
12045 CHECK_EQ(41, value->Int32Value());
12049 // Test the case when we stored cacheable lookup into
12050 // a stub, but it got invalidated later on
12051 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12052 v8::Isolate* isolate = CcTest::isolate();
12053 v8::HandleScope scope(isolate);
12054 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12055 templ->SetNamedPropertyHandler(NoBlockGetterX);
12056 LocalContext context;
12057 context->Global()->Set(v8_str("o"), templ->NewInstance());
12058 v8::Handle<Value> value = CompileRun(
12059 "proto1 = new Object();"
12060 "proto2 = new Object();"
12061 "o.__proto__ = proto1;"
12062 "proto1.__proto__ = proto2;"
12063 "proto2.y = function(x) { return x + 1; };"
12064 // Invoke it many times to compile a stub
12065 "for (var i = 0; i < 7; i++) {"
12068 "proto1.y = function(x) { return x - 1; };"
12070 "for (var i = 0; i < 7; i++) {"
12071 " result += o.y(42);"
12073 CHECK_EQ(41 * 7, value->Int32Value());
12077 // This test checks that if interceptor doesn't provide a function,
12078 // cached constant function is used
12079 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12080 v8::Isolate* isolate = CcTest::isolate();
12081 v8::HandleScope scope(isolate);
12082 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12083 templ->SetNamedPropertyHandler(NoBlockGetterX);
12084 LocalContext context;
12085 context->Global()->Set(v8_str("o"), templ->NewInstance());
12086 v8::Handle<Value> value = CompileRun(
12087 "function inc(x) { return x + 1; };"
12091 "for (var i = 0; i < 1000; i++) {"
12092 " result = o.x(42);"
12094 CHECK_EQ(43, value->Int32Value());
12098 static v8::Handle<Value> call_ic_function5;
12099 static void InterceptorCallICGetter5(
12100 Local<String> name,
12101 const v8::PropertyCallbackInfo<v8::Value>& info) {
12102 ApiTestFuzzer::Fuzz();
12103 if (v8_str("x")->Equals(name))
12104 info.GetReturnValue().Set(call_ic_function5);
12108 // This test checks that if interceptor provides a function,
12109 // even if we cached constant function, interceptor's function
12111 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12112 v8::Isolate* isolate = CcTest::isolate();
12113 v8::HandleScope scope(isolate);
12114 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12115 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12116 LocalContext context;
12117 context->Global()->Set(v8_str("o"), templ->NewInstance());
12118 call_ic_function5 =
12119 v8_compile("function f(x) { return x - 1; }; f")->Run();
12120 v8::Handle<Value> value = CompileRun(
12121 "function inc(x) { return x + 1; };"
12125 "for (var i = 0; i < 1000; i++) {"
12126 " result = o.x(42);"
12128 CHECK_EQ(41, value->Int32Value());
12132 static v8::Handle<Value> call_ic_function6;
12133 static void InterceptorCallICGetter6(
12134 Local<String> name,
12135 const v8::PropertyCallbackInfo<v8::Value>& info) {
12136 ApiTestFuzzer::Fuzz();
12137 if (v8_str("x")->Equals(name))
12138 info.GetReturnValue().Set(call_ic_function6);
12142 // Same test as above, except the code is wrapped in a function
12143 // to test the optimized compiler.
12144 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12145 i::FLAG_allow_natives_syntax = true;
12146 v8::Isolate* isolate = CcTest::isolate();
12147 v8::HandleScope scope(isolate);
12148 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12149 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12150 LocalContext context;
12151 context->Global()->Set(v8_str("o"), templ->NewInstance());
12152 call_ic_function6 =
12153 v8_compile("function f(x) { return x - 1; }; f")->Run();
12154 v8::Handle<Value> value = CompileRun(
12155 "function inc(x) { return x + 1; };"
12158 "function test() {"
12160 " for (var i = 0; i < 1000; i++) {"
12161 " result = o.x(42);"
12168 "%OptimizeFunctionOnNextCall(test);"
12170 CHECK_EQ(41, value->Int32Value());
12174 // Test the case when we stored constant function into
12175 // a stub, but it got invalidated later on
12176 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12177 v8::Isolate* isolate = CcTest::isolate();
12178 v8::HandleScope scope(isolate);
12179 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12180 templ->SetNamedPropertyHandler(NoBlockGetterX);
12181 LocalContext context;
12182 context->Global()->Set(v8_str("o"), templ->NewInstance());
12183 v8::Handle<Value> value = CompileRun(
12184 "function inc(x) { return x + 1; };"
12186 "proto1 = new Object();"
12187 "proto2 = new Object();"
12188 "o.__proto__ = proto1;"
12189 "proto1.__proto__ = proto2;"
12191 // Invoke it many times to compile a stub
12192 "for (var i = 0; i < 7; i++) {"
12195 "proto1.y = function(x) { return x - 1; };"
12197 "for (var i = 0; i < 7; i++) {"
12198 " result += o.y(42);"
12200 CHECK_EQ(41 * 7, value->Int32Value());
12204 // Test the case when we stored constant function into
12205 // a stub, but it got invalidated later on due to override on
12206 // global object which is between interceptor and constant function' holders.
12207 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12208 v8::Isolate* isolate = CcTest::isolate();
12209 v8::HandleScope scope(isolate);
12210 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12211 templ->SetNamedPropertyHandler(NoBlockGetterX);
12212 LocalContext context;
12213 context->Global()->Set(v8_str("o"), templ->NewInstance());
12214 v8::Handle<Value> value = CompileRun(
12215 "function inc(x) { return x + 1; };"
12217 "o.__proto__ = this;"
12218 "this.__proto__.y = inc;"
12219 // Invoke it many times to compile a stub
12220 "for (var i = 0; i < 7; i++) {"
12221 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12223 "this.y = function(x) { return x - 1; };"
12225 "for (var i = 0; i < 7; i++) {"
12226 " result += o.y(42);"
12228 CHECK_EQ(41 * 7, value->Int32Value());
12232 // Test the case when actual function to call sits on global object.
12233 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12234 v8::Isolate* isolate = CcTest::isolate();
12235 v8::HandleScope scope(isolate);
12236 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12237 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12239 LocalContext context;
12240 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12242 v8::Handle<Value> value = CompileRun(
12244 " o.__proto__ = this;"
12245 " for (var i = 0; i < 10; i++) {"
12246 " var v = o.parseFloat('239');"
12247 " if (v != 239) throw v;"
12248 // Now it should be ICed and keep a reference to parseFloat.
12251 " for (var i = 0; i < 10; i++) {"
12252 " result += o.parseFloat('239');"
12258 CHECK_EQ(239 * 10, value->Int32Value());
12261 static void InterceptorCallICFastApi(
12262 Local<String> name,
12263 const v8::PropertyCallbackInfo<v8::Value>& info) {
12264 ApiTestFuzzer::Fuzz();
12265 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12267 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12269 if ((*call_count) % 20 == 0) {
12270 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12274 static void FastApiCallback_TrivialSignature(
12275 const v8::FunctionCallbackInfo<v8::Value>& args) {
12276 ApiTestFuzzer::Fuzz();
12277 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12278 v8::Isolate* isolate = CcTest::isolate();
12279 CHECK_EQ(isolate, args.GetIsolate());
12280 CHECK_EQ(args.This(), args.Holder());
12281 CHECK(args.Data()->Equals(v8_str("method_data")));
12282 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12285 static void FastApiCallback_SimpleSignature(
12286 const v8::FunctionCallbackInfo<v8::Value>& args) {
12287 ApiTestFuzzer::Fuzz();
12288 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12289 v8::Isolate* isolate = CcTest::isolate();
12290 CHECK_EQ(isolate, args.GetIsolate());
12291 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12292 CHECK(args.Data()->Equals(v8_str("method_data")));
12293 // Note, we're using HasRealNamedProperty instead of Has to avoid
12294 // invoking the interceptor again.
12295 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12296 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12300 // Helper to maximize the odds of object moving.
12301 static void GenerateSomeGarbage() {
12304 "for (var i = 0; i < 1000; i++) {"
12305 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12307 "garbage = undefined;");
12311 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12312 static int count = 0;
12313 if (count++ % 3 == 0) {
12314 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12315 // This should move the stub
12316 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12321 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12322 LocalContext context;
12323 v8::Isolate* isolate = context->GetIsolate();
12324 v8::HandleScope scope(isolate);
12325 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12326 v8::ObjectTemplate::New(isolate);
12327 nativeobject_templ->Set(isolate, "callback",
12328 v8::FunctionTemplate::New(isolate,
12329 DirectApiCallback));
12330 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12331 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12332 // call the api function multiple times to ensure direct call stub creation.
12335 " for (var i = 1; i <= 30; i++) {"
12336 " nativeobject.callback();"
12343 void ThrowingDirectApiCallback(
12344 const v8::FunctionCallbackInfo<v8::Value>& args) {
12345 args.GetIsolate()->ThrowException(v8_str("g"));
12349 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12350 LocalContext context;
12351 v8::Isolate* isolate = context->GetIsolate();
12352 v8::HandleScope scope(isolate);
12353 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12354 v8::ObjectTemplate::New(isolate);
12355 nativeobject_templ->Set(isolate, "callback",
12356 v8::FunctionTemplate::New(isolate,
12357 ThrowingDirectApiCallback));
12358 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12359 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12360 // call the api function multiple times to ensure direct call stub creation.
12361 v8::Handle<Value> result = CompileRun(
12364 " for (var i = 1; i <= 5; i++) {"
12365 " try { nativeobject.callback(); } catch (e) { result += e; }"
12369 CHECK_EQ(v8_str("ggggg"), result);
12373 static Handle<Value> DoDirectGetter() {
12374 if (++p_getter_count % 3 == 0) {
12375 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12376 GenerateSomeGarbage();
12378 return v8_str("Direct Getter Result");
12381 static void DirectGetterCallback(
12382 Local<String> name,
12383 const v8::PropertyCallbackInfo<v8::Value>& info) {
12384 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12385 info.GetReturnValue().Set(DoDirectGetter());
12389 template<typename Accessor>
12390 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12391 LocalContext context;
12392 v8::Isolate* isolate = context->GetIsolate();
12393 v8::HandleScope scope(isolate);
12394 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12395 obj->SetAccessor(v8_str("p1"), accessor);
12396 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12397 p_getter_count = 0;
12398 v8::Handle<v8::Value> result = CompileRun(
12400 " for (var i = 0; i < 30; i++) o1.p1;"
12404 CHECK_EQ(v8_str("Direct Getter Result"), result);
12405 CHECK_EQ(31, p_getter_count);
12409 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12410 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12414 void ThrowingDirectGetterCallback(
12415 Local<String> name,
12416 const v8::PropertyCallbackInfo<v8::Value>& info) {
12417 info.GetIsolate()->ThrowException(v8_str("g"));
12421 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12422 LocalContext context;
12423 v8::Isolate* isolate = context->GetIsolate();
12424 v8::HandleScope scope(isolate);
12425 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12426 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12427 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12428 v8::Handle<Value> result = CompileRun(
12430 "for (var i = 0; i < 5; i++) {"
12431 " try { o1.p1; } catch (e) { result += e; }"
12434 CHECK_EQ(v8_str("ggggg"), result);
12438 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12439 int interceptor_call_count = 0;
12440 v8::Isolate* isolate = CcTest::isolate();
12441 v8::HandleScope scope(isolate);
12442 v8::Handle<v8::FunctionTemplate> fun_templ =
12443 v8::FunctionTemplate::New(isolate);
12444 v8::Handle<v8::FunctionTemplate> method_templ =
12445 v8::FunctionTemplate::New(isolate,
12446 FastApiCallback_TrivialSignature,
12447 v8_str("method_data"),
12448 v8::Handle<v8::Signature>());
12449 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12450 proto_templ->Set(v8_str("method"), method_templ);
12451 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12452 templ->SetNamedPropertyHandler(
12453 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12454 v8::External::New(isolate, &interceptor_call_count));
12455 LocalContext context;
12456 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12457 GenerateSomeGarbage();
12458 context->Global()->Set(v8_str("o"), fun->NewInstance());
12461 "for (var i = 0; i < 100; i++) {"
12462 " result = o.method(41);"
12464 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12465 CHECK_EQ(100, interceptor_call_count);
12469 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12470 int interceptor_call_count = 0;
12471 v8::Isolate* isolate = CcTest::isolate();
12472 v8::HandleScope scope(isolate);
12473 v8::Handle<v8::FunctionTemplate> fun_templ =
12474 v8::FunctionTemplate::New(isolate);
12475 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12476 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12477 v8::Signature::New(isolate, fun_templ));
12478 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12479 proto_templ->Set(v8_str("method"), method_templ);
12480 fun_templ->SetHiddenPrototype(true);
12481 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12482 templ->SetNamedPropertyHandler(
12483 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12484 v8::External::New(isolate, &interceptor_call_count));
12485 LocalContext context;
12486 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12487 GenerateSomeGarbage();
12488 context->Global()->Set(v8_str("o"), fun->NewInstance());
12491 "var receiver = {};"
12492 "receiver.__proto__ = o;"
12494 "for (var i = 0; i < 100; i++) {"
12495 " result = receiver.method(41);"
12497 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12498 CHECK_EQ(100, interceptor_call_count);
12502 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12503 int interceptor_call_count = 0;
12504 v8::Isolate* isolate = CcTest::isolate();
12505 v8::HandleScope scope(isolate);
12506 v8::Handle<v8::FunctionTemplate> fun_templ =
12507 v8::FunctionTemplate::New(isolate);
12508 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12509 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12510 v8::Signature::New(isolate, fun_templ));
12511 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12512 proto_templ->Set(v8_str("method"), method_templ);
12513 fun_templ->SetHiddenPrototype(true);
12514 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12515 templ->SetNamedPropertyHandler(
12516 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12517 v8::External::New(isolate, &interceptor_call_count));
12518 LocalContext context;
12519 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12520 GenerateSomeGarbage();
12521 context->Global()->Set(v8_str("o"), fun->NewInstance());
12524 "var receiver = {};"
12525 "receiver.__proto__ = o;"
12527 "var saved_result = 0;"
12528 "for (var i = 0; i < 100; i++) {"
12529 " result = receiver.method(41);"
12531 " saved_result = result;"
12532 " receiver = {method: function(x) { return x - 1 }};"
12535 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12536 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12537 CHECK_GE(interceptor_call_count, 50);
12541 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12542 int interceptor_call_count = 0;
12543 v8::Isolate* isolate = CcTest::isolate();
12544 v8::HandleScope scope(isolate);
12545 v8::Handle<v8::FunctionTemplate> fun_templ =
12546 v8::FunctionTemplate::New(isolate);
12547 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12548 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12549 v8::Signature::New(isolate, fun_templ));
12550 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12551 proto_templ->Set(v8_str("method"), method_templ);
12552 fun_templ->SetHiddenPrototype(true);
12553 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12554 templ->SetNamedPropertyHandler(
12555 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12556 v8::External::New(isolate, &interceptor_call_count));
12557 LocalContext context;
12558 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12559 GenerateSomeGarbage();
12560 context->Global()->Set(v8_str("o"), fun->NewInstance());
12563 "var receiver = {};"
12564 "receiver.__proto__ = o;"
12566 "var saved_result = 0;"
12567 "for (var i = 0; i < 100; i++) {"
12568 " result = receiver.method(41);"
12570 " saved_result = result;"
12571 " o.method = function(x) { return x - 1 };"
12574 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12575 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12576 CHECK_GE(interceptor_call_count, 50);
12580 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12581 int interceptor_call_count = 0;
12582 v8::Isolate* isolate = CcTest::isolate();
12583 v8::HandleScope scope(isolate);
12584 v8::Handle<v8::FunctionTemplate> fun_templ =
12585 v8::FunctionTemplate::New(isolate);
12586 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12587 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12588 v8::Signature::New(isolate, fun_templ));
12589 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12590 proto_templ->Set(v8_str("method"), method_templ);
12591 fun_templ->SetHiddenPrototype(true);
12592 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12593 templ->SetNamedPropertyHandler(
12594 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12595 v8::External::New(isolate, &interceptor_call_count));
12596 LocalContext context;
12597 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12598 GenerateSomeGarbage();
12599 context->Global()->Set(v8_str("o"), fun->NewInstance());
12600 v8::TryCatch try_catch;
12603 "var receiver = {};"
12604 "receiver.__proto__ = o;"
12606 "var saved_result = 0;"
12607 "for (var i = 0; i < 100; i++) {"
12608 " result = receiver.method(41);"
12610 " saved_result = result;"
12614 CHECK(try_catch.HasCaught());
12615 // TODO(verwaest): Adjust message.
12616 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12617 try_catch.Exception()->ToString());
12618 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12619 CHECK_GE(interceptor_call_count, 50);
12623 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12624 int interceptor_call_count = 0;
12625 v8::Isolate* isolate = CcTest::isolate();
12626 v8::HandleScope scope(isolate);
12627 v8::Handle<v8::FunctionTemplate> fun_templ =
12628 v8::FunctionTemplate::New(isolate);
12629 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12630 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12631 v8::Signature::New(isolate, fun_templ));
12632 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12633 proto_templ->Set(v8_str("method"), method_templ);
12634 fun_templ->SetHiddenPrototype(true);
12635 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12636 templ->SetNamedPropertyHandler(
12637 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12638 v8::External::New(isolate, &interceptor_call_count));
12639 LocalContext context;
12640 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12641 GenerateSomeGarbage();
12642 context->Global()->Set(v8_str("o"), fun->NewInstance());
12643 v8::TryCatch try_catch;
12646 "var receiver = {};"
12647 "receiver.__proto__ = o;"
12649 "var saved_result = 0;"
12650 "for (var i = 0; i < 100; i++) {"
12651 " result = receiver.method(41);"
12653 " saved_result = result;"
12654 " receiver = {method: receiver.method};"
12657 CHECK(try_catch.HasCaught());
12658 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12659 try_catch.Exception()->ToString());
12660 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12661 CHECK_GE(interceptor_call_count, 50);
12665 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12666 v8::Isolate* isolate = CcTest::isolate();
12667 v8::HandleScope scope(isolate);
12668 v8::Handle<v8::FunctionTemplate> fun_templ =
12669 v8::FunctionTemplate::New(isolate);
12670 v8::Handle<v8::FunctionTemplate> method_templ =
12671 v8::FunctionTemplate::New(isolate,
12672 FastApiCallback_TrivialSignature,
12673 v8_str("method_data"),
12674 v8::Handle<v8::Signature>());
12675 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12676 proto_templ->Set(v8_str("method"), method_templ);
12677 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12679 LocalContext context;
12680 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12681 GenerateSomeGarbage();
12682 context->Global()->Set(v8_str("o"), fun->NewInstance());
12685 "for (var i = 0; i < 100; i++) {"
12686 " result = o.method(41);"
12689 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12693 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12694 v8::Isolate* isolate = CcTest::isolate();
12695 v8::HandleScope scope(isolate);
12696 v8::Handle<v8::FunctionTemplate> fun_templ =
12697 v8::FunctionTemplate::New(isolate);
12698 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12699 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12700 v8::Signature::New(isolate, fun_templ));
12701 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12702 proto_templ->Set(v8_str("method"), method_templ);
12703 fun_templ->SetHiddenPrototype(true);
12704 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12705 CHECK(!templ.IsEmpty());
12706 LocalContext context;
12707 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12708 GenerateSomeGarbage();
12709 context->Global()->Set(v8_str("o"), fun->NewInstance());
12712 "var receiver = {};"
12713 "receiver.__proto__ = o;"
12715 "for (var i = 0; i < 100; i++) {"
12716 " result = receiver.method(41);"
12719 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12723 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12724 v8::Isolate* isolate = CcTest::isolate();
12725 v8::HandleScope scope(isolate);
12726 v8::Handle<v8::FunctionTemplate> fun_templ =
12727 v8::FunctionTemplate::New(isolate);
12728 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12729 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12730 v8::Signature::New(isolate, fun_templ));
12731 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12732 proto_templ->Set(v8_str("method"), method_templ);
12733 fun_templ->SetHiddenPrototype(true);
12734 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12735 CHECK(!templ.IsEmpty());
12736 LocalContext context;
12737 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12738 GenerateSomeGarbage();
12739 context->Global()->Set(v8_str("o"), fun->NewInstance());
12742 "var receiver = {};"
12743 "receiver.__proto__ = o;"
12745 "var saved_result = 0;"
12746 "for (var i = 0; i < 100; i++) {"
12747 " result = receiver.method(41);"
12749 " saved_result = result;"
12750 " receiver = {method: function(x) { return x - 1 }};"
12753 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12754 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12758 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12759 v8::Isolate* isolate = CcTest::isolate();
12760 v8::HandleScope scope(isolate);
12761 v8::Handle<v8::FunctionTemplate> fun_templ =
12762 v8::FunctionTemplate::New(isolate);
12763 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12764 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12765 v8::Signature::New(isolate, fun_templ));
12766 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12767 proto_templ->Set(v8_str("method"), method_templ);
12768 fun_templ->SetHiddenPrototype(true);
12769 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12770 CHECK(!templ.IsEmpty());
12771 LocalContext context;
12772 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12773 GenerateSomeGarbage();
12774 context->Global()->Set(v8_str("o"), fun->NewInstance());
12775 v8::TryCatch try_catch;
12778 "var receiver = {};"
12779 "receiver.__proto__ = o;"
12781 "var saved_result = 0;"
12782 "for (var i = 0; i < 100; i++) {"
12783 " result = receiver.method(41);"
12785 " saved_result = result;"
12789 CHECK(try_catch.HasCaught());
12790 // TODO(verwaest): Adjust message.
12791 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12792 try_catch.Exception()->ToString());
12793 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12797 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12798 v8::Isolate* isolate = CcTest::isolate();
12799 v8::HandleScope scope(isolate);
12800 v8::Handle<v8::FunctionTemplate> fun_templ =
12801 v8::FunctionTemplate::New(isolate);
12802 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12803 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12804 v8::Signature::New(isolate, fun_templ));
12805 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12806 proto_templ->Set(v8_str("method"), method_templ);
12807 fun_templ->SetHiddenPrototype(true);
12808 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12809 CHECK(!templ.IsEmpty());
12810 LocalContext context;
12811 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12812 GenerateSomeGarbage();
12813 context->Global()->Set(v8_str("o"), fun->NewInstance());
12814 v8::TryCatch try_catch;
12817 "var receiver = {};"
12818 "receiver.__proto__ = o;"
12820 "var saved_result = 0;"
12821 "for (var i = 0; i < 100; i++) {"
12822 " result = receiver.method(41);"
12824 " saved_result = result;"
12825 " receiver = Object.create(receiver);"
12828 CHECK(try_catch.HasCaught());
12829 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12830 try_catch.Exception()->ToString());
12831 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12835 v8::Handle<Value> keyed_call_ic_function;
12837 static void InterceptorKeyedCallICGetter(
12838 Local<String> name,
12839 const v8::PropertyCallbackInfo<v8::Value>& info) {
12840 ApiTestFuzzer::Fuzz();
12841 if (v8_str("x")->Equals(name)) {
12842 info.GetReturnValue().Set(keyed_call_ic_function);
12847 // Test the case when we stored cacheable lookup into
12848 // a stub, but the function name changed (to another cacheable function).
12849 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12850 v8::Isolate* isolate = CcTest::isolate();
12851 v8::HandleScope scope(isolate);
12852 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12853 templ->SetNamedPropertyHandler(NoBlockGetterX);
12854 LocalContext context;
12855 context->Global()->Set(v8_str("o"), templ->NewInstance());
12857 "proto = new Object();"
12858 "proto.y = function(x) { return x + 1; };"
12859 "proto.z = function(x) { return x - 1; };"
12860 "o.__proto__ = proto;"
12862 "var method = 'y';"
12863 "for (var i = 0; i < 10; i++) {"
12864 " if (i == 5) { method = 'z'; };"
12865 " result += o[method](41);"
12867 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12871 // Test the case when we stored cacheable lookup into
12872 // a stub, but the function name changed (and the new function is present
12873 // both before and after the interceptor in the prototype chain).
12874 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12875 v8::Isolate* isolate = CcTest::isolate();
12876 v8::HandleScope scope(isolate);
12877 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12878 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12879 LocalContext context;
12880 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12881 keyed_call_ic_function =
12882 v8_compile("function f(x) { return x - 1; }; f")->Run();
12884 "o = new Object();"
12885 "proto2 = new Object();"
12886 "o.y = function(x) { return x + 1; };"
12887 "proto2.y = function(x) { return x + 2; };"
12888 "o.__proto__ = proto1;"
12889 "proto1.__proto__ = proto2;"
12891 "var method = 'x';"
12892 "for (var i = 0; i < 10; i++) {"
12893 " if (i == 5) { method = 'y'; };"
12894 " result += o[method](41);"
12896 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12900 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12901 // on the global object.
12902 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12903 v8::Isolate* isolate = CcTest::isolate();
12904 v8::HandleScope scope(isolate);
12905 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12906 templ->SetNamedPropertyHandler(NoBlockGetterX);
12907 LocalContext context;
12908 context->Global()->Set(v8_str("o"), templ->NewInstance());
12910 "function inc(x) { return x + 1; };"
12912 "function dec(x) { return x - 1; };"
12914 "o.__proto__ = this;"
12915 "this.__proto__.x = inc;"
12916 "this.__proto__.y = dec;"
12918 "var method = 'x';"
12919 "for (var i = 0; i < 10; i++) {"
12920 " if (i == 5) { method = 'y'; };"
12921 " result += o[method](41);"
12923 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12927 // Test the case when actual function to call sits on global object.
12928 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12929 v8::Isolate* isolate = CcTest::isolate();
12930 v8::HandleScope scope(isolate);
12931 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12932 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12933 LocalContext context;
12934 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12937 "function len(x) { return x.length; };"
12938 "o.__proto__ = this;"
12939 "var m = 'parseFloat';"
12941 "for (var i = 0; i < 10; i++) {"
12944 " saved_result = result;"
12946 " result = o[m]('239');"
12948 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12949 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12953 // Test the map transition before the interceptor.
12954 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12955 v8::Isolate* isolate = CcTest::isolate();
12956 v8::HandleScope scope(isolate);
12957 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12958 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12959 LocalContext context;
12960 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12963 "var o = new Object();"
12964 "o.__proto__ = proto;"
12965 "o.method = function(x) { return x + 1; };"
12966 "var m = 'method';"
12968 "for (var i = 0; i < 10; i++) {"
12969 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12970 " result += o[m](41);"
12972 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12976 // Test the map transition after the interceptor.
12977 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12978 v8::Isolate* isolate = CcTest::isolate();
12979 v8::HandleScope scope(isolate);
12980 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12981 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12982 LocalContext context;
12983 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12986 "var proto = new Object();"
12987 "o.__proto__ = proto;"
12988 "proto.method = function(x) { return x + 1; };"
12989 "var m = 'method';"
12991 "for (var i = 0; i < 10; i++) {"
12992 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12993 " result += o[m](41);"
12995 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12999 static int interceptor_call_count = 0;
13001 static void InterceptorICRefErrorGetter(
13002 Local<String> name,
13003 const v8::PropertyCallbackInfo<v8::Value>& info) {
13004 ApiTestFuzzer::Fuzz();
13005 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13006 info.GetReturnValue().Set(call_ic_function2);
13011 // This test should hit load and call ICs for the interceptor case.
13012 // Once in a while, the interceptor will reply that a property was not
13013 // found in which case we should get a reference error.
13014 THREADED_TEST(InterceptorICReferenceErrors) {
13015 v8::Isolate* isolate = CcTest::isolate();
13016 v8::HandleScope scope(isolate);
13017 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13018 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
13019 LocalContext context(0, templ, v8::Handle<Value>());
13020 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13021 v8::Handle<Value> value = CompileRun(
13023 " for (var i = 0; i < 1000; i++) {"
13024 " try { x; } catch(e) { return true; }"
13029 CHECK_EQ(true, value->BooleanValue());
13030 interceptor_call_count = 0;
13031 value = CompileRun(
13033 " for (var i = 0; i < 1000; i++) {"
13034 " try { x(42); } catch(e) { return true; }"
13039 CHECK_EQ(true, value->BooleanValue());
13043 static int interceptor_ic_exception_get_count = 0;
13045 static void InterceptorICExceptionGetter(
13046 Local<String> name,
13047 const v8::PropertyCallbackInfo<v8::Value>& info) {
13048 ApiTestFuzzer::Fuzz();
13049 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13050 info.GetReturnValue().Set(call_ic_function3);
13052 if (interceptor_ic_exception_get_count == 20) {
13053 info.GetIsolate()->ThrowException(v8_num(42));
13059 // Test interceptor load/call IC where the interceptor throws an
13060 // exception once in a while.
13061 THREADED_TEST(InterceptorICGetterExceptions) {
13062 interceptor_ic_exception_get_count = 0;
13063 v8::Isolate* isolate = CcTest::isolate();
13064 v8::HandleScope scope(isolate);
13065 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13066 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
13067 LocalContext context(0, templ, v8::Handle<Value>());
13068 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13069 v8::Handle<Value> value = CompileRun(
13071 " for (var i = 0; i < 100; i++) {"
13072 " try { x; } catch(e) { return true; }"
13077 CHECK_EQ(true, value->BooleanValue());
13078 interceptor_ic_exception_get_count = 0;
13079 value = CompileRun(
13081 " for (var i = 0; i < 100; i++) {"
13082 " try { x(42); } catch(e) { return true; }"
13087 CHECK_EQ(true, value->BooleanValue());
13091 static int interceptor_ic_exception_set_count = 0;
13093 static void InterceptorICExceptionSetter(
13095 Local<Value> value,
13096 const v8::PropertyCallbackInfo<v8::Value>& info) {
13097 ApiTestFuzzer::Fuzz();
13098 if (++interceptor_ic_exception_set_count > 20) {
13099 info.GetIsolate()->ThrowException(v8_num(42));
13104 // Test interceptor store IC where the interceptor throws an exception
13105 // once in a while.
13106 THREADED_TEST(InterceptorICSetterExceptions) {
13107 interceptor_ic_exception_set_count = 0;
13108 v8::Isolate* isolate = CcTest::isolate();
13109 v8::HandleScope scope(isolate);
13110 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13111 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13112 LocalContext context(0, templ, v8::Handle<Value>());
13113 v8::Handle<Value> value = CompileRun(
13115 " for (var i = 0; i < 100; i++) {"
13116 " try { x = 42; } catch(e) { return true; }"
13121 CHECK_EQ(true, value->BooleanValue());
13125 // Test that we ignore null interceptors.
13126 THREADED_TEST(NullNamedInterceptor) {
13127 v8::Isolate* isolate = CcTest::isolate();
13128 v8::HandleScope scope(isolate);
13129 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13130 templ->SetNamedPropertyHandler(
13131 static_cast<v8::NamedPropertyGetterCallback>(0));
13132 LocalContext context;
13133 templ->Set(CcTest::isolate(), "x", v8_num(42));
13134 v8::Handle<v8::Object> obj = templ->NewInstance();
13135 context->Global()->Set(v8_str("obj"), obj);
13136 v8::Handle<Value> value = CompileRun("obj.x");
13137 CHECK(value->IsInt32());
13138 CHECK_EQ(42, value->Int32Value());
13142 // Test that we ignore null interceptors.
13143 THREADED_TEST(NullIndexedInterceptor) {
13144 v8::Isolate* isolate = CcTest::isolate();
13145 v8::HandleScope scope(isolate);
13146 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13147 templ->SetIndexedPropertyHandler(
13148 static_cast<v8::IndexedPropertyGetterCallback>(0));
13149 LocalContext context;
13150 templ->Set(CcTest::isolate(), "42", v8_num(42));
13151 v8::Handle<v8::Object> obj = templ->NewInstance();
13152 context->Global()->Set(v8_str("obj"), obj);
13153 v8::Handle<Value> value = CompileRun("obj[42]");
13154 CHECK(value->IsInt32());
13155 CHECK_EQ(42, value->Int32Value());
13159 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13160 v8::Isolate* isolate = CcTest::isolate();
13161 v8::HandleScope scope(isolate);
13162 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13163 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13165 env->Global()->Set(v8_str("obj"),
13166 templ->GetFunction()->NewInstance());
13167 ExpectTrue("obj.x === 42");
13168 ExpectTrue("!obj.propertyIsEnumerable('x')");
13172 static void ThrowingGetter(Local<String> name,
13173 const v8::PropertyCallbackInfo<v8::Value>& info) {
13174 ApiTestFuzzer::Fuzz();
13175 info.GetIsolate()->ThrowException(Handle<Value>());
13176 info.GetReturnValue().SetUndefined();
13180 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13181 LocalContext context;
13182 HandleScope scope(context->GetIsolate());
13184 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13185 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13186 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13188 Local<Object> instance = templ->GetFunction()->NewInstance();
13190 Local<Object> another = Object::New(context->GetIsolate());
13191 another->SetPrototype(instance);
13193 Local<Object> with_js_getter = CompileRun(
13195 "o.__defineGetter__('f', function() { throw undefined; });\n"
13196 "o\n").As<Object>();
13197 CHECK(!with_js_getter.IsEmpty());
13199 TryCatch try_catch;
13201 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13202 CHECK(try_catch.HasCaught());
13204 CHECK(result.IsEmpty());
13206 result = another->GetRealNamedProperty(v8_str("f"));
13207 CHECK(try_catch.HasCaught());
13209 CHECK(result.IsEmpty());
13211 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13212 CHECK(try_catch.HasCaught());
13214 CHECK(result.IsEmpty());
13216 result = another->Get(v8_str("f"));
13217 CHECK(try_catch.HasCaught());
13219 CHECK(result.IsEmpty());
13221 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13222 CHECK(try_catch.HasCaught());
13224 CHECK(result.IsEmpty());
13226 result = with_js_getter->Get(v8_str("f"));
13227 CHECK(try_catch.HasCaught());
13229 CHECK(result.IsEmpty());
13233 static void ThrowingCallbackWithTryCatch(
13234 const v8::FunctionCallbackInfo<v8::Value>& args) {
13235 TryCatch try_catch;
13236 // Verboseness is important: it triggers message delivery which can call into
13238 try_catch.SetVerbose(true);
13239 CompileRun("throw 'from JS';");
13240 CHECK(try_catch.HasCaught());
13241 CHECK(!CcTest::i_isolate()->has_pending_exception());
13242 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13246 static int call_depth;
13249 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13250 TryCatch try_catch;
13254 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13255 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13259 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13260 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13264 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13265 Handle<String> errorMessageString = message->Get();
13266 CHECK(!errorMessageString.IsEmpty());
13267 message->GetStackTrace();
13268 message->GetScriptOrigin().ResourceName();
13272 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13273 LocalContext context;
13274 v8::Isolate* isolate = context->GetIsolate();
13275 HandleScope scope(isolate);
13277 Local<Function> func =
13278 FunctionTemplate::New(isolate,
13279 ThrowingCallbackWithTryCatch)->GetFunction();
13280 context->Global()->Set(v8_str("func"), func);
13282 MessageCallback callbacks[] =
13283 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13284 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13285 MessageCallback callback = callbacks[i];
13286 if (callback != NULL) {
13287 V8::AddMessageListener(callback);
13289 // Some small number to control number of times message handler should
13290 // throw an exception.
13293 "var thrown = false;\n"
13294 "try { func(); } catch(e) { thrown = true; }\n"
13296 if (callback != NULL) {
13297 V8::RemoveMessageListeners(callback);
13303 static void ParentGetter(Local<String> name,
13304 const v8::PropertyCallbackInfo<v8::Value>& info) {
13305 ApiTestFuzzer::Fuzz();
13306 info.GetReturnValue().Set(v8_num(1));
13310 static void ChildGetter(Local<String> name,
13311 const v8::PropertyCallbackInfo<v8::Value>& info) {
13312 ApiTestFuzzer::Fuzz();
13313 info.GetReturnValue().Set(v8_num(42));
13317 THREADED_TEST(Overriding) {
13318 LocalContext context;
13319 v8::Isolate* isolate = context->GetIsolate();
13320 v8::HandleScope scope(isolate);
13322 // Parent template.
13323 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13324 Local<ObjectTemplate> parent_instance_templ =
13325 parent_templ->InstanceTemplate();
13326 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13328 // Template that inherits from the parent template.
13329 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13330 Local<ObjectTemplate> child_instance_templ =
13331 child_templ->InstanceTemplate();
13332 child_templ->Inherit(parent_templ);
13333 // Override 'f'. The child version of 'f' should get called for child
13335 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13336 // Add 'g' twice. The 'g' added last should get called for instances.
13337 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13338 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13340 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13341 // so 'h' can be shadowed on the instance object.
13342 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13343 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13344 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13346 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13347 // but the attribute does not have effect because it is duplicated with
13349 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13350 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13354 // Instantiate the child template.
13355 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13357 // Check that the child function overrides the parent one.
13358 context->Global()->Set(v8_str("o"), instance);
13359 Local<Value> value = v8_compile("o.f")->Run();
13360 // Check that the 'g' that was added last is hit.
13361 CHECK_EQ(42, value->Int32Value());
13362 value = v8_compile("o.g")->Run();
13363 CHECK_EQ(42, value->Int32Value());
13365 // Check that 'h' cannot be shadowed.
13366 value = v8_compile("o.h = 3; o.h")->Run();
13367 CHECK_EQ(1, value->Int32Value());
13369 // Check that 'i' cannot be shadowed or changed.
13370 value = v8_compile("o.i = 3; o.i")->Run();
13371 CHECK_EQ(42, value->Int32Value());
13375 static void IsConstructHandler(
13376 const v8::FunctionCallbackInfo<v8::Value>& args) {
13377 ApiTestFuzzer::Fuzz();
13378 args.GetReturnValue().Set(args.IsConstructCall());
13382 THREADED_TEST(IsConstructCall) {
13383 v8::Isolate* isolate = CcTest::isolate();
13384 v8::HandleScope scope(isolate);
13386 // Function template with call handler.
13387 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13388 templ->SetCallHandler(IsConstructHandler);
13390 LocalContext context;
13392 context->Global()->Set(v8_str("f"), templ->GetFunction());
13393 Local<Value> value = v8_compile("f()")->Run();
13394 CHECK(!value->BooleanValue());
13395 value = v8_compile("new f()")->Run();
13396 CHECK(value->BooleanValue());
13400 THREADED_TEST(ObjectProtoToString) {
13401 v8::Isolate* isolate = CcTest::isolate();
13402 v8::HandleScope scope(isolate);
13403 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13404 templ->SetClassName(v8_str("MyClass"));
13406 LocalContext context;
13408 Local<String> customized_tostring = v8_str("customized toString");
13410 // Replace Object.prototype.toString
13411 v8_compile("Object.prototype.toString = function() {"
13412 " return 'customized toString';"
13415 // Normal ToString call should call replaced Object.prototype.toString
13416 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13417 Local<String> value = instance->ToString();
13418 CHECK(value->IsString() && value->Equals(customized_tostring));
13420 // ObjectProtoToString should not call replace toString function.
13421 value = instance->ObjectProtoToString();
13422 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13425 value = context->Global()->ObjectProtoToString();
13426 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13428 // Check ordinary object
13429 Local<Value> object = v8_compile("new Object()")->Run();
13430 value = object.As<v8::Object>()->ObjectProtoToString();
13431 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13435 THREADED_TEST(ObjectGetConstructorName) {
13436 LocalContext context;
13437 v8::HandleScope scope(context->GetIsolate());
13438 v8_compile("function Parent() {};"
13439 "function Child() {};"
13440 "Child.prototype = new Parent();"
13441 "var outer = { inner: function() { } };"
13442 "var p = new Parent();"
13443 "var c = new Child();"
13444 "var x = new outer.inner();")->Run();
13446 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13447 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13448 v8_str("Parent")));
13450 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13451 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13454 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13455 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13456 v8_str("outer.inner")));
13460 bool ApiTestFuzzer::fuzzing_ = false;
13461 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13462 int ApiTestFuzzer::active_tests_;
13463 int ApiTestFuzzer::tests_being_run_;
13464 int ApiTestFuzzer::current_;
13467 // We are in a callback and want to switch to another thread (if we
13468 // are currently running the thread fuzzing test).
13469 void ApiTestFuzzer::Fuzz() {
13470 if (!fuzzing_) return;
13471 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13472 test->ContextSwitch();
13476 // Let the next thread go. Since it is also waiting on the V8 lock it may
13477 // not start immediately.
13478 bool ApiTestFuzzer::NextThread() {
13479 int test_position = GetNextTestNumber();
13480 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13481 if (test_position == current_) {
13483 printf("Stay with %s\n", test_name);
13486 if (kLogThreading) {
13487 printf("Switch from %s to %s\n",
13489 RegisterThreadedTest::nth(test_position)->name());
13491 current_ = test_position;
13492 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13497 void ApiTestFuzzer::Run() {
13498 // When it is our turn...
13501 // ... get the V8 lock and start running the test.
13502 v8::Locker locker(CcTest::isolate());
13505 // This test finished.
13508 // If it was the last then signal that fact.
13509 if (active_tests_ == 0) {
13510 all_tests_done_.Signal();
13512 // Otherwise select a new test and start that.
13518 static unsigned linear_congruential_generator;
13521 void ApiTestFuzzer::SetUp(PartOfTest part) {
13522 linear_congruential_generator = i::FLAG_testing_prng_seed;
13524 int count = RegisterThreadedTest::count();
13525 int start = count * part / (LAST_PART + 1);
13526 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13527 active_tests_ = tests_being_run_ = end - start + 1;
13528 for (int i = 0; i < tests_being_run_; i++) {
13529 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13531 for (int i = 0; i < active_tests_; i++) {
13532 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13537 static void CallTestNumber(int test_number) {
13538 (RegisterThreadedTest::nth(test_number)->callback())();
13542 void ApiTestFuzzer::RunAllTests() {
13543 // Set off the first test.
13546 // Wait till they are all done.
13547 all_tests_done_.Wait();
13551 int ApiTestFuzzer::GetNextTestNumber() {
13554 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13555 linear_congruential_generator *= 1664525u;
13556 linear_congruential_generator += 1013904223u;
13557 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13562 void ApiTestFuzzer::ContextSwitch() {
13563 // If the new thread is the same as the current thread there is nothing to do.
13564 if (NextThread()) {
13565 // Now it can start.
13566 v8::Unlocker unlocker(CcTest::isolate());
13567 // Wait till someone starts us again.
13574 void ApiTestFuzzer::TearDown() {
13576 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13577 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13578 if (fuzzer != NULL) fuzzer->Join();
13583 // Lets not be needlessly self-referential.
13585 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13586 ApiTestFuzzer::RunAllTests();
13587 ApiTestFuzzer::TearDown();
13592 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13593 ApiTestFuzzer::RunAllTests();
13594 ApiTestFuzzer::TearDown();
13599 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13600 ApiTestFuzzer::RunAllTests();
13601 ApiTestFuzzer::TearDown();
13606 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13607 ApiTestFuzzer::RunAllTests();
13608 ApiTestFuzzer::TearDown();
13612 void ApiTestFuzzer::CallTest() {
13613 v8::Isolate::Scope scope(CcTest::isolate());
13615 printf("Start test %d\n", test_number_);
13616 CallTestNumber(test_number_);
13618 printf("End test %d\n", test_number_);
13622 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13623 v8::Isolate* isolate = args.GetIsolate();
13624 CHECK(v8::Locker::IsLocked(isolate));
13625 ApiTestFuzzer::Fuzz();
13626 v8::Unlocker unlocker(isolate);
13627 const char* code = "throw 7;";
13629 v8::Locker nested_locker(isolate);
13630 v8::HandleScope scope(isolate);
13631 v8::Handle<Value> exception;
13632 { v8::TryCatch try_catch;
13633 v8::Handle<Value> value = CompileRun(code);
13634 CHECK(value.IsEmpty());
13635 CHECK(try_catch.HasCaught());
13636 // Make sure to wrap the exception in a new handle because
13637 // the handle returned from the TryCatch is destroyed
13638 // when the TryCatch is destroyed.
13639 exception = Local<Value>::New(isolate, try_catch.Exception());
13641 args.GetIsolate()->ThrowException(exception);
13646 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13647 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13648 ApiTestFuzzer::Fuzz();
13649 v8::Unlocker unlocker(CcTest::isolate());
13650 const char* code = "throw 7;";
13652 v8::Locker nested_locker(CcTest::isolate());
13653 v8::HandleScope scope(args.GetIsolate());
13654 v8::Handle<Value> value = CompileRun(code);
13655 CHECK(value.IsEmpty());
13656 args.GetReturnValue().Set(v8_str("foo"));
13661 // These are locking tests that don't need to be run again
13662 // as part of the locking aggregation tests.
13663 TEST(NestedLockers) {
13664 v8::Isolate* isolate = CcTest::isolate();
13665 v8::Locker locker(isolate);
13666 CHECK(v8::Locker::IsLocked(isolate));
13668 v8::HandleScope scope(env->GetIsolate());
13669 Local<v8::FunctionTemplate> fun_templ =
13670 v8::FunctionTemplate::New(isolate, ThrowInJS);
13671 Local<Function> fun = fun_templ->GetFunction();
13672 env->Global()->Set(v8_str("throw_in_js"), fun);
13673 Local<Script> script = v8_compile("(function () {"
13681 CHECK_EQ(91, script->Run()->Int32Value());
13685 // These are locking tests that don't need to be run again
13686 // as part of the locking aggregation tests.
13687 TEST(NestedLockersNoTryCatch) {
13688 v8::Locker locker(CcTest::isolate());
13690 v8::HandleScope scope(env->GetIsolate());
13691 Local<v8::FunctionTemplate> fun_templ =
13692 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13693 Local<Function> fun = fun_templ->GetFunction();
13694 env->Global()->Set(v8_str("throw_in_js"), fun);
13695 Local<Script> script = v8_compile("(function () {"
13703 CHECK_EQ(91, script->Run()->Int32Value());
13707 THREADED_TEST(RecursiveLocking) {
13708 v8::Locker locker(CcTest::isolate());
13710 v8::Locker locker2(CcTest::isolate());
13711 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13716 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13717 ApiTestFuzzer::Fuzz();
13718 v8::Unlocker unlocker(CcTest::isolate());
13722 THREADED_TEST(LockUnlockLock) {
13724 v8::Locker locker(CcTest::isolate());
13725 v8::HandleScope scope(CcTest::isolate());
13727 Local<v8::FunctionTemplate> fun_templ =
13728 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13729 Local<Function> fun = fun_templ->GetFunction();
13730 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13731 Local<Script> script = v8_compile("(function () {"
13732 " unlock_for_a_moment();"
13735 CHECK_EQ(42, script->Run()->Int32Value());
13738 v8::Locker locker(CcTest::isolate());
13739 v8::HandleScope scope(CcTest::isolate());
13741 Local<v8::FunctionTemplate> fun_templ =
13742 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13743 Local<Function> fun = fun_templ->GetFunction();
13744 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13745 Local<Script> script = v8_compile("(function () {"
13746 " unlock_for_a_moment();"
13749 CHECK_EQ(42, script->Run()->Int32Value());
13754 static int GetGlobalObjectsCount() {
13756 i::HeapIterator it(CcTest::heap());
13757 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13758 if (object->IsJSGlobalObject()) count++;
13763 static void CheckSurvivingGlobalObjectsCount(int expected) {
13764 // We need to collect all garbage twice to be sure that everything
13765 // has been collected. This is because inline caches are cleared in
13766 // the first garbage collection but some of the maps have already
13767 // been marked at that point. Therefore some of the maps are not
13768 // collected until the second garbage collection.
13769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13770 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13771 int count = GetGlobalObjectsCount();
13773 if (count != expected) CcTest::heap()->TracePathToGlobal();
13775 CHECK_EQ(expected, count);
13779 TEST(DontLeakGlobalObjects) {
13780 // Regression test for issues 1139850 and 1174891.
13782 i::FLAG_expose_gc = true;
13783 v8::V8::Initialize();
13785 for (int i = 0; i < 5; i++) {
13786 { v8::HandleScope scope(CcTest::isolate());
13787 LocalContext context;
13789 CcTest::isolate()->ContextDisposedNotification();
13790 CheckSurvivingGlobalObjectsCount(0);
13792 { v8::HandleScope scope(CcTest::isolate());
13793 LocalContext context;
13794 v8_compile("Date")->Run();
13796 CcTest::isolate()->ContextDisposedNotification();
13797 CheckSurvivingGlobalObjectsCount(0);
13799 { v8::HandleScope scope(CcTest::isolate());
13800 LocalContext context;
13801 v8_compile("/aaa/")->Run();
13803 CcTest::isolate()->ContextDisposedNotification();
13804 CheckSurvivingGlobalObjectsCount(0);
13806 { v8::HandleScope scope(CcTest::isolate());
13807 const char* extension_list[] = { "v8/gc" };
13808 v8::ExtensionConfiguration extensions(1, extension_list);
13809 LocalContext context(&extensions);
13810 v8_compile("gc();")->Run();
13812 CcTest::isolate()->ContextDisposedNotification();
13813 CheckSurvivingGlobalObjectsCount(0);
13818 TEST(CopyablePersistent) {
13819 LocalContext context;
13820 v8::Isolate* isolate = context->GetIsolate();
13821 i::GlobalHandles* globals =
13822 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13823 int initial_handles = globals->global_handles_count();
13824 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13827 CopyableObject handle1;
13829 v8::HandleScope scope(isolate);
13830 handle1.Reset(isolate, v8::Object::New(isolate));
13832 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13833 CopyableObject handle2;
13835 CHECK(handle1 == handle2);
13836 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13837 CopyableObject handle3(handle2);
13838 CHECK(handle1 == handle3);
13839 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13841 // Verify autodispose
13842 CHECK_EQ(initial_handles, globals->global_handles_count());
13846 static void WeakApiCallback(
13847 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13848 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13849 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13850 data.GetParameter()->Reset();
13851 delete data.GetParameter();
13855 TEST(WeakCallbackApi) {
13856 LocalContext context;
13857 v8::Isolate* isolate = context->GetIsolate();
13858 i::GlobalHandles* globals =
13859 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13860 int initial_handles = globals->global_handles_count();
13862 v8::HandleScope scope(isolate);
13863 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13864 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13865 v8::Persistent<v8::Object>* handle =
13866 new v8::Persistent<v8::Object>(isolate, obj);
13867 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13870 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13871 CollectAllGarbage(i::Heap::kNoGCFlags);
13872 // Verify disposed.
13873 CHECK_EQ(initial_handles, globals->global_handles_count());
13877 v8::Persistent<v8::Object> some_object;
13878 v8::Persistent<v8::Object> bad_handle;
13880 void NewPersistentHandleCallback(
13881 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13882 v8::HandleScope scope(data.GetIsolate());
13883 bad_handle.Reset(data.GetIsolate(), some_object);
13884 data.GetParameter()->Reset();
13888 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13889 LocalContext context;
13890 v8::Isolate* isolate = context->GetIsolate();
13892 v8::Persistent<v8::Object> handle1, handle2;
13894 v8::HandleScope scope(isolate);
13895 some_object.Reset(isolate, v8::Object::New(isolate));
13896 handle1.Reset(isolate, v8::Object::New(isolate));
13897 handle2.Reset(isolate, v8::Object::New(isolate));
13899 // Note: order is implementation dependent alas: currently
13900 // global handle nodes are processed by PostGarbageCollectionProcessing
13901 // in reverse allocation order, so if second allocated handle is deleted,
13902 // weak callback of the first handle would be able to 'reallocate' it.
13903 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13905 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13909 v8::Persistent<v8::Object> to_be_disposed;
13911 void DisposeAndForceGcCallback(
13912 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13913 to_be_disposed.Reset();
13914 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13915 data.GetParameter()->Reset();
13919 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13920 LocalContext context;
13921 v8::Isolate* isolate = context->GetIsolate();
13923 v8::Persistent<v8::Object> handle1, handle2;
13925 v8::HandleScope scope(isolate);
13926 handle1.Reset(isolate, v8::Object::New(isolate));
13927 handle2.Reset(isolate, v8::Object::New(isolate));
13929 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13930 to_be_disposed.Reset(isolate, handle2);
13931 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13934 void DisposingCallback(
13935 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13936 data.GetParameter()->Reset();
13939 void HandleCreatingCallback(
13940 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13941 v8::HandleScope scope(data.GetIsolate());
13942 v8::Persistent<v8::Object>(data.GetIsolate(),
13943 v8::Object::New(data.GetIsolate()));
13944 data.GetParameter()->Reset();
13948 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13949 LocalContext context;
13950 v8::Isolate* isolate = context->GetIsolate();
13952 v8::Persistent<v8::Object> handle1, handle2, handle3;
13954 v8::HandleScope scope(isolate);
13955 handle3.Reset(isolate, v8::Object::New(isolate));
13956 handle2.Reset(isolate, v8::Object::New(isolate));
13957 handle1.Reset(isolate, v8::Object::New(isolate));
13959 handle2.SetWeak(&handle2, DisposingCallback);
13960 handle3.SetWeak(&handle3, HandleCreatingCallback);
13961 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13965 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13966 v8::V8::Initialize();
13969 const char* sources[nof] = {
13970 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13974 for (int i = 0; i < nof; i++) {
13975 const char* source = sources[i];
13976 { v8::HandleScope scope(CcTest::isolate());
13977 LocalContext context;
13978 CompileRun(source);
13980 { v8::HandleScope scope(CcTest::isolate());
13981 LocalContext context;
13982 CompileRun(source);
13988 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13989 v8::EscapableHandleScope inner(env->GetIsolate());
13991 v8::Local<Value> three = v8_num(3);
13992 v8::Local<Value> value = inner.Escape(three);
13998 THREADED_TEST(NestedHandleScopeAndContexts) {
13999 v8::Isolate* isolate = CcTest::isolate();
14000 v8::HandleScope outer(isolate);
14001 v8::Local<Context> env = Context::New(isolate);
14003 v8::Handle<Value> value = NestedScope(env);
14004 v8::Handle<String> str(value->ToString());
14005 CHECK(!str.IsEmpty());
14010 static bool MatchPointers(void* key1, void* key2) {
14011 return key1 == key2;
14015 struct SymbolInfo {
14022 class SetFunctionEntryHookTest {
14024 SetFunctionEntryHookTest() {
14025 CHECK(instance_ == NULL);
14028 ~SetFunctionEntryHookTest() {
14029 CHECK(instance_ == this);
14034 symbol_locations_.clear();
14035 invocations_.clear();
14038 void OnJitEvent(const v8::JitCodeEvent* event);
14039 static void JitEvent(const v8::JitCodeEvent* event) {
14040 CHECK(instance_ != NULL);
14041 instance_->OnJitEvent(event);
14044 void OnEntryHook(uintptr_t function,
14045 uintptr_t return_addr_location);
14046 static void EntryHook(uintptr_t function,
14047 uintptr_t return_addr_location) {
14048 CHECK(instance_ != NULL);
14049 instance_->OnEntryHook(function, return_addr_location);
14052 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14053 CHECK(instance_ != NULL);
14054 args.GetReturnValue().Set(v8_num(42));
14056 void RunLoopInNewEnv(v8::Isolate* isolate);
14058 // Records addr as location of symbol.
14059 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14061 // Finds the symbol containing addr
14062 SymbolInfo* FindSymbolForAddr(i::Address addr);
14063 // Returns the number of invocations where the caller name contains
14064 // \p caller_name and the function name contains \p function_name.
14065 int CountInvocations(const char* caller_name,
14066 const char* function_name);
14068 i::Handle<i::JSFunction> foo_func_;
14069 i::Handle<i::JSFunction> bar_func_;
14071 typedef std::map<size_t, SymbolInfo> SymbolMap;
14072 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14073 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14074 SymbolMap symbols_;
14075 SymbolLocationMap symbol_locations_;
14076 InvocationMap invocations_;
14078 static SetFunctionEntryHookTest* instance_;
14080 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14083 // Returns true if addr is in the range [start, start+len).
14084 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14085 if (start <= addr && start + len > addr)
14091 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14092 SymbolInfo* symbol) {
14093 // Insert the symbol at the new location.
14094 SymbolLocationMap::iterator it =
14095 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14096 // Now erase symbols to the left and right that overlap this one.
14097 while (it != symbol_locations_.begin()) {
14098 SymbolLocationMap::iterator left = it;
14100 if (!Overlaps(left->first, left->second->size, addr))
14102 symbol_locations_.erase(left);
14105 // Now erase symbols to the left and right that overlap this one.
14107 SymbolLocationMap::iterator right = it;
14109 if (right == symbol_locations_.end())
14111 if (!Overlaps(addr, symbol->size, right->first))
14113 symbol_locations_.erase(right);
14118 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14119 switch (event->type) {
14120 case v8::JitCodeEvent::CODE_ADDED: {
14121 CHECK(event->code_start != NULL);
14122 CHECK_NE(0, static_cast<int>(event->code_len));
14123 CHECK(event->name.str != NULL);
14124 size_t symbol_id = symbols_.size();
14126 // Record the new symbol.
14127 SymbolInfo& info = symbols_[symbol_id];
14128 info.id = symbol_id;
14129 info.size = event->code_len;
14130 info.name.assign(event->name.str, event->name.str + event->name.len);
14132 // And record it's location.
14133 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14137 case v8::JitCodeEvent::CODE_MOVED: {
14138 // We would like to never see code move that we haven't seen before,
14139 // but the code creation event does not happen until the line endings
14140 // have been calculated (this is so that we can report the line in the
14141 // script at which the function source is found, see
14142 // Compiler::RecordFunctionCompilation) and the line endings
14143 // calculations can cause a GC, which can move the newly created code
14144 // before its existence can be logged.
14145 SymbolLocationMap::iterator it(
14146 symbol_locations_.find(
14147 reinterpret_cast<i::Address>(event->code_start)));
14148 if (it != symbol_locations_.end()) {
14149 // Found a symbol at this location, move it.
14150 SymbolInfo* info = it->second;
14151 symbol_locations_.erase(it);
14152 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14161 void SetFunctionEntryHookTest::OnEntryHook(
14162 uintptr_t function, uintptr_t return_addr_location) {
14163 // Get the function's code object.
14164 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14165 reinterpret_cast<i::Address>(function));
14166 CHECK(function_code != NULL);
14168 // Then try and look up the caller's code object.
14169 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14171 // Count the invocation.
14172 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14173 SymbolInfo* function_symbol =
14174 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14175 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14177 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14178 // Check that we have a symbol for the "bar" function at the right location.
14179 SymbolLocationMap::iterator it(
14180 symbol_locations_.find(function_code->instruction_start()));
14181 CHECK(it != symbol_locations_.end());
14184 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14185 // Check that we have a symbol for "foo" at the right location.
14186 SymbolLocationMap::iterator it(
14187 symbol_locations_.find(function_code->instruction_start()));
14188 CHECK(it != symbol_locations_.end());
14193 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14194 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14195 // Do we have a direct hit on a symbol?
14196 if (it != symbol_locations_.end()) {
14197 if (it->first == addr)
14201 // If not a direct hit, it'll have to be the previous symbol.
14202 if (it == symbol_locations_.begin())
14206 size_t offs = addr - it->first;
14207 if (offs < it->second->size)
14214 int SetFunctionEntryHookTest::CountInvocations(
14215 const char* caller_name, const char* function_name) {
14216 InvocationMap::iterator it(invocations_.begin());
14217 int invocations = 0;
14218 for (; it != invocations_.end(); ++it) {
14219 SymbolInfo* caller = it->first.first;
14220 SymbolInfo* function = it->first.second;
14222 // Filter out non-matching functions.
14223 if (function_name != NULL) {
14224 if (function->name.find(function_name) == std::string::npos)
14228 // Filter out non-matching callers.
14229 if (caller_name != NULL) {
14230 if (caller == NULL)
14232 if (caller->name.find(caller_name) == std::string::npos)
14236 // It matches add the invocation count to the tally.
14237 invocations += it->second;
14240 return invocations;
14244 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14245 v8::HandleScope outer(isolate);
14246 v8::Local<Context> env = Context::New(isolate);
14249 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14250 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14251 env->Global()->Set(v8_str("obj"), t->NewInstance());
14253 const char* script =
14254 "function bar() {\n"
14256 " for (i = 0; i < 100; ++i)\n"
14260 "function foo(i) { return i * i; }\n"
14261 "// Invoke on the runtime function.\n"
14263 CompileRun(script);
14264 bar_func_ = i::Handle<i::JSFunction>::cast(
14265 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14266 DCHECK(!bar_func_.is_null());
14269 i::Handle<i::JSFunction>::cast(
14270 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14271 DCHECK(!foo_func_.is_null());
14273 v8::Handle<v8::Value> value = CompileRun("bar();");
14274 CHECK(value->IsNumber());
14275 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14277 // Test the optimized codegen path.
14278 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14280 CHECK(value->IsNumber());
14281 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14287 void SetFunctionEntryHookTest::RunTest() {
14288 // Work in a new isolate throughout.
14289 v8::Isolate::CreateParams create_params;
14290 create_params.entry_hook = EntryHook;
14291 create_params.code_event_handler = JitEvent;
14292 v8::Isolate* isolate = v8::Isolate::New(create_params);
14295 v8::Isolate::Scope scope(isolate);
14297 RunLoopInNewEnv(isolate);
14299 // Check the exepected invocation counts.
14300 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14301 CHECK_EQ(200, CountInvocations("bar", "foo"));
14302 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14304 // Verify that we have an entry hook on some specific stubs.
14305 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14306 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14307 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14309 isolate->Dispose();
14313 // Make sure a second isolate is unaffected by the previous entry hook.
14314 isolate = v8::Isolate::New();
14316 v8::Isolate::Scope scope(isolate);
14318 // Reset the entry count to zero and set the entry hook.
14319 RunLoopInNewEnv(isolate);
14321 // We should record no invocations in this isolate.
14322 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14325 isolate->Dispose();
14329 TEST(SetFunctionEntryHook) {
14330 // FunctionEntryHook does not work well with experimental natives.
14331 // Experimental natives are compiled during snapshot deserialization.
14332 // This test breaks because InstallGetter (function from snapshot that
14333 // only gets called from experimental natives) is compiled with entry hooks.
14334 i::FLAG_allow_natives_syntax = true;
14335 i::FLAG_use_inlining = false;
14337 SetFunctionEntryHookTest test;
14342 static i::HashMap* code_map = NULL;
14343 static i::HashMap* jitcode_line_info = NULL;
14344 static int saw_bar = 0;
14345 static int move_events = 0;
14348 static bool FunctionNameIs(const char* expected,
14349 const v8::JitCodeEvent* event) {
14350 // Log lines for functions are of the general form:
14351 // "LazyCompile:<type><function_name>", where the type is one of
14353 static const char kPreamble[] = "LazyCompile:";
14354 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14356 if (event->name.len < sizeof(kPreamble) - 1 ||
14357 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14361 const char* tail = event->name.str + kPreambleLen;
14362 size_t tail_len = event->name.len - kPreambleLen;
14363 size_t expected_len = strlen(expected);
14364 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14369 // Check for tails like 'bar :1'.
14370 if (tail_len > expected_len + 2 &&
14371 tail[expected_len] == ' ' &&
14372 tail[expected_len + 1] == ':' &&
14373 tail[expected_len + 2] &&
14374 !strncmp(tail, expected, expected_len)) {
14378 if (tail_len != expected_len)
14381 return strncmp(tail, expected, expected_len) == 0;
14385 static void event_handler(const v8::JitCodeEvent* event) {
14386 CHECK(event != NULL);
14387 CHECK(code_map != NULL);
14388 CHECK(jitcode_line_info != NULL);
14390 class DummyJitCodeLineInfo {
14393 switch (event->type) {
14394 case v8::JitCodeEvent::CODE_ADDED: {
14395 CHECK(event->code_start != NULL);
14396 CHECK_NE(0, static_cast<int>(event->code_len));
14397 CHECK(event->name.str != NULL);
14398 i::HashMap::Entry* entry =
14399 code_map->Lookup(event->code_start,
14400 i::ComputePointerHash(event->code_start),
14402 entry->value = reinterpret_cast<void*>(event->code_len);
14404 if (FunctionNameIs("bar", event)) {
14410 case v8::JitCodeEvent::CODE_MOVED: {
14411 uint32_t hash = i::ComputePointerHash(event->code_start);
14412 // We would like to never see code move that we haven't seen before,
14413 // but the code creation event does not happen until the line endings
14414 // have been calculated (this is so that we can report the line in the
14415 // script at which the function source is found, see
14416 // Compiler::RecordFunctionCompilation) and the line endings
14417 // calculations can cause a GC, which can move the newly created code
14418 // before its existence can be logged.
14419 i::HashMap::Entry* entry =
14420 code_map->Lookup(event->code_start, hash, false);
14421 if (entry != NULL) {
14424 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14425 code_map->Remove(event->code_start, hash);
14427 entry = code_map->Lookup(event->new_code_start,
14428 i::ComputePointerHash(event->new_code_start),
14430 CHECK(entry != NULL);
14431 entry->value = reinterpret_cast<void*>(event->code_len);
14436 case v8::JitCodeEvent::CODE_REMOVED:
14437 // Object/code removal events are currently not dispatched from the GC.
14441 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14442 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14443 // record it in jitcode_line_info.
14444 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14445 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14446 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14447 temp_event->user_data = line_info;
14448 i::HashMap::Entry* entry =
14449 jitcode_line_info->Lookup(line_info,
14450 i::ComputePointerHash(line_info),
14452 entry->value = reinterpret_cast<void*>(line_info);
14455 // For these two events, we will check whether the event->user_data
14456 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14457 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14458 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14459 CHECK(event->user_data != NULL);
14460 uint32_t hash = i::ComputePointerHash(event->user_data);
14461 i::HashMap::Entry* entry =
14462 jitcode_line_info->Lookup(event->user_data, hash, false);
14463 CHECK(entry != NULL);
14464 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14468 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14469 CHECK(event->user_data != NULL);
14470 uint32_t hash = i::ComputePointerHash(event->user_data);
14471 i::HashMap::Entry* entry =
14472 jitcode_line_info->Lookup(event->user_data, hash, false);
14473 CHECK(entry != NULL);
14478 // Impossible event.
14485 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14486 i::FLAG_stress_compaction = true;
14487 i::FLAG_incremental_marking = false;
14488 if (i::FLAG_never_compact) return;
14489 const char* script =
14492 " for (i = 0; i < 100; ++i)"
14496 "function foo(i) { return i * i; };"
14499 // Run this test in a new isolate to make sure we don't
14500 // have remnants of state from other code.
14501 v8::Isolate* isolate = v8::Isolate::New();
14503 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14504 i::Heap* heap = i_isolate->heap();
14507 v8::HandleScope scope(isolate);
14508 i::HashMap code(MatchPointers);
14511 i::HashMap lineinfo(MatchPointers);
14512 jitcode_line_info = &lineinfo;
14517 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14519 // Generate new code objects sparsely distributed across several
14520 // different fragmented code-space pages.
14521 const int kIterations = 10;
14522 for (int i = 0; i < kIterations; ++i) {
14523 LocalContext env(isolate);
14524 i::AlwaysAllocateScope always_allocate(i_isolate);
14525 SimulateFullSpace(heap->code_space());
14526 CompileRun(script);
14528 // Keep a strong reference to the code object in the handle scope.
14529 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14530 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14531 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14532 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14534 // Clear the compilation cache to get more wastage.
14535 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14538 // Force code movement.
14539 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14541 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14543 CHECK_LE(kIterations, saw_bar);
14544 CHECK_LT(0, move_events);
14547 jitcode_line_info = NULL;
14551 isolate->Dispose();
14553 // Do this in a new isolate.
14554 isolate = v8::Isolate::New();
14557 // Verify that we get callbacks for existing code objects when we
14558 // request enumeration of existing code.
14560 v8::HandleScope scope(isolate);
14561 LocalContext env(isolate);
14562 CompileRun(script);
14564 // Now get code through initial iteration.
14565 i::HashMap code(MatchPointers);
14568 i::HashMap lineinfo(MatchPointers);
14569 jitcode_line_info = &lineinfo;
14571 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14573 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14575 jitcode_line_info = NULL;
14576 // We expect that we got some events. Note that if we could get code removal
14577 // notifications, we could compare two collections, one created by listening
14578 // from the time of creation of an isolate, and the other by subscribing
14579 // with EnumExisting.
14580 CHECK_LT(0, code.occupancy());
14586 isolate->Dispose();
14590 THREADED_TEST(ExternalAllocatedMemory) {
14591 v8::Isolate* isolate = CcTest::isolate();
14592 v8::HandleScope outer(isolate);
14593 v8::Local<Context> env(Context::New(isolate));
14594 CHECK(!env.IsEmpty());
14595 const int64_t kSize = 1024*1024;
14596 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14597 CHECK_EQ(baseline + kSize,
14598 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14600 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14604 // Regression test for issue 54, object templates with internal fields
14605 // but no accessors or interceptors did not get their internal field
14606 // count set on instances.
14607 THREADED_TEST(Regress54) {
14608 LocalContext context;
14609 v8::Isolate* isolate = context->GetIsolate();
14610 v8::HandleScope outer(isolate);
14611 static v8::Persistent<v8::ObjectTemplate> templ;
14612 if (templ.IsEmpty()) {
14613 v8::EscapableHandleScope inner(isolate);
14614 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14615 local->SetInternalFieldCount(1);
14616 templ.Reset(isolate, inner.Escape(local));
14618 v8::Handle<v8::Object> result =
14619 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14620 CHECK_EQ(1, result->InternalFieldCount());
14624 // If part of the threaded tests, this test makes ThreadingTest fail
14626 TEST(CatchStackOverflow) {
14627 LocalContext context;
14628 v8::HandleScope scope(context->GetIsolate());
14629 v8::TryCatch try_catch;
14630 v8::Handle<v8::Value> result = CompileRun(
14636 CHECK(result.IsEmpty());
14640 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14641 const char* resource_name,
14643 v8::HandleScope scope(CcTest::isolate());
14644 v8::TryCatch try_catch;
14645 v8::Handle<v8::Value> result = script->Run();
14646 CHECK(result.IsEmpty());
14647 CHECK(try_catch.HasCaught());
14648 v8::Handle<v8::Message> message = try_catch.Message();
14649 CHECK(!message.IsEmpty());
14650 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14651 CHECK_EQ(91, message->GetStartPosition());
14652 CHECK_EQ(92, message->GetEndPosition());
14653 CHECK_EQ(2, message->GetStartColumn());
14654 CHECK_EQ(3, message->GetEndColumn());
14655 v8::String::Utf8Value line(message->GetSourceLine());
14656 CHECK_EQ(" throw 'nirk';", *line);
14657 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14658 CHECK_EQ(resource_name, *name);
14662 THREADED_TEST(TryCatchSourceInfo) {
14663 LocalContext context;
14664 v8::HandleScope scope(context->GetIsolate());
14665 v8::Local<v8::String> source = v8_str(
14666 "function Foo() {\n"
14670 "function Bar() {\n"
14674 "function Baz() {\n"
14680 const char* resource_name;
14681 v8::Handle<v8::Script> script;
14682 resource_name = "test.js";
14683 script = CompileWithOrigin(source, resource_name);
14684 CheckTryCatchSourceInfo(script, resource_name, 0);
14686 resource_name = "test1.js";
14687 v8::ScriptOrigin origin1(
14688 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14689 script = v8::Script::Compile(source, &origin1);
14690 CheckTryCatchSourceInfo(script, resource_name, 0);
14692 resource_name = "test2.js";
14693 v8::ScriptOrigin origin2(
14694 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14695 v8::Integer::New(context->GetIsolate(), 7));
14696 script = v8::Script::Compile(source, &origin2);
14697 CheckTryCatchSourceInfo(script, resource_name, 7);
14701 THREADED_TEST(CompilationCache) {
14702 LocalContext context;
14703 v8::HandleScope scope(context->GetIsolate());
14704 v8::Handle<v8::String> source0 =
14705 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14706 v8::Handle<v8::String> source1 =
14707 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14708 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14709 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14710 v8::Handle<v8::Script> script2 =
14711 v8::Script::Compile(source0); // different origin
14712 CHECK_EQ(1234, script0->Run()->Int32Value());
14713 CHECK_EQ(1234, script1->Run()->Int32Value());
14714 CHECK_EQ(1234, script2->Run()->Int32Value());
14718 static void FunctionNameCallback(
14719 const v8::FunctionCallbackInfo<v8::Value>& args) {
14720 ApiTestFuzzer::Fuzz();
14721 args.GetReturnValue().Set(v8_num(42));
14725 THREADED_TEST(CallbackFunctionName) {
14726 LocalContext context;
14727 v8::Isolate* isolate = context->GetIsolate();
14728 v8::HandleScope scope(isolate);
14729 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14730 t->Set(v8_str("asdf"),
14731 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14732 context->Global()->Set(v8_str("obj"), t->NewInstance());
14733 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14734 CHECK(value->IsString());
14735 v8::String::Utf8Value name(value);
14736 CHECK_EQ("asdf", *name);
14740 THREADED_TEST(DateAccess) {
14741 LocalContext context;
14742 v8::HandleScope scope(context->GetIsolate());
14743 v8::Handle<v8::Value> date =
14744 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14745 CHECK(date->IsDate());
14746 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14750 void CheckProperties(v8::Isolate* isolate,
14751 v8::Handle<v8::Value> val,
14753 const char* elmv[]) {
14754 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14755 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14756 CHECK_EQ(elmc, props->Length());
14757 for (int i = 0; i < elmc; i++) {
14758 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14759 CHECK_EQ(elmv[i], *elm);
14764 void CheckOwnProperties(v8::Isolate* isolate,
14765 v8::Handle<v8::Value> val,
14767 const char* elmv[]) {
14768 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14769 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14770 CHECK_EQ(elmc, props->Length());
14771 for (int i = 0; i < elmc; i++) {
14772 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14773 CHECK_EQ(elmv[i], *elm);
14778 THREADED_TEST(PropertyEnumeration) {
14779 LocalContext context;
14780 v8::Isolate* isolate = context->GetIsolate();
14781 v8::HandleScope scope(isolate);
14782 v8::Handle<v8::Value> obj = CompileRun(
14785 "result[1] = {a: 1, b: 2};"
14786 "result[2] = [1, 2, 3];"
14787 "var proto = {x: 1, y: 2, z: 3};"
14788 "var x = { __proto__: proto, w: 0, z: 1 };"
14791 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14792 CHECK_EQ(4, elms->Length());
14794 const char** elmv0 = NULL;
14796 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14797 CheckOwnProperties(
14798 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14800 const char* elmv1[] = {"a", "b"};
14802 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14803 CheckOwnProperties(
14804 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14806 const char* elmv2[] = {"0", "1", "2"};
14808 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14809 CheckOwnProperties(
14810 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14812 const char* elmv3[] = {"w", "z", "x", "y"};
14814 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14816 const char* elmv4[] = {"w", "z"};
14817 CheckOwnProperties(
14818 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14822 THREADED_TEST(PropertyEnumeration2) {
14823 LocalContext context;
14824 v8::Isolate* isolate = context->GetIsolate();
14825 v8::HandleScope scope(isolate);
14826 v8::Handle<v8::Value> obj = CompileRun(
14829 "result[1] = {a: 1, b: 2};"
14830 "result[2] = [1, 2, 3];"
14831 "var proto = {x: 1, y: 2, z: 3};"
14832 "var x = { __proto__: proto, w: 0, z: 1 };"
14835 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14836 CHECK_EQ(4, elms->Length());
14838 const char** elmv0 = NULL;
14839 CheckProperties(isolate,
14840 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14842 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14843 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14844 CHECK_EQ(0, props->Length());
14845 for (uint32_t i = 0; i < props->Length(); i++) {
14846 printf("p[%d]\n", i);
14850 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14852 v8::AccessType type,
14853 Local<Value> data) {
14854 return type != v8::ACCESS_SET;
14858 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14860 v8::AccessType type,
14861 Local<Value> data) {
14862 return type != v8::ACCESS_SET;
14866 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14867 LocalContext context;
14868 v8::Isolate* isolate = context->GetIsolate();
14869 v8::HandleScope scope(isolate);
14870 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14871 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14872 IndexedSetAccessBlocker);
14873 templ->Set(v8_str("x"), v8::True(isolate));
14874 Local<v8::Object> instance = templ->NewInstance();
14875 context->Global()->Set(v8_str("obj"), instance);
14876 Local<Value> value = CompileRun("obj.x");
14877 CHECK(value->BooleanValue());
14881 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14883 v8::AccessType type,
14884 Local<Value> data) {
14889 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14891 v8::AccessType type,
14892 Local<Value> data) {
14898 THREADED_TEST(AccessChecksReenabledCorrectly) {
14899 LocalContext context;
14900 v8::Isolate* isolate = context->GetIsolate();
14901 v8::HandleScope scope(isolate);
14902 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14903 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14904 IndexedGetAccessBlocker);
14905 templ->Set(v8_str("a"), v8_str("a"));
14906 // Add more than 8 (see kMaxFastProperties) properties
14907 // so that the constructor will force copying map.
14908 // Cannot sprintf, gcc complains unsafety.
14910 for (char i = '0'; i <= '9' ; i++) {
14912 for (char j = '0'; j <= '9'; j++) {
14914 for (char k = '0'; k <= '9'; k++) {
14917 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14922 Local<v8::Object> instance_1 = templ->NewInstance();
14923 context->Global()->Set(v8_str("obj_1"), instance_1);
14925 Local<Value> value_1 = CompileRun("obj_1.a");
14926 CHECK(value_1.IsEmpty());
14928 Local<v8::Object> instance_2 = templ->NewInstance();
14929 context->Global()->Set(v8_str("obj_2"), instance_2);
14931 Local<Value> value_2 = CompileRun("obj_2.a");
14932 CHECK(value_2.IsEmpty());
14936 // This tests that access check information remains on the global
14937 // object template when creating contexts.
14938 THREADED_TEST(AccessControlRepeatedContextCreation) {
14939 v8::Isolate* isolate = CcTest::isolate();
14940 v8::HandleScope handle_scope(isolate);
14941 v8::Handle<v8::ObjectTemplate> global_template =
14942 v8::ObjectTemplate::New(isolate);
14943 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14944 IndexedSetAccessBlocker);
14945 i::Handle<i::ObjectTemplateInfo> internal_template =
14946 v8::Utils::OpenHandle(*global_template);
14947 CHECK(!internal_template->constructor()->IsUndefined());
14948 i::Handle<i::FunctionTemplateInfo> constructor(
14949 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14950 CHECK(!constructor->access_check_info()->IsUndefined());
14951 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14952 CHECK(!context0.IsEmpty());
14953 CHECK(!constructor->access_check_info()->IsUndefined());
14957 THREADED_TEST(TurnOnAccessCheck) {
14958 v8::Isolate* isolate = CcTest::isolate();
14959 v8::HandleScope handle_scope(isolate);
14961 // Create an environment with access check to the global object disabled by
14963 v8::Handle<v8::ObjectTemplate> global_template =
14964 v8::ObjectTemplate::New(isolate);
14965 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14966 IndexedGetAccessBlocker,
14967 v8::Handle<v8::Value>(),
14969 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14970 Context::Scope context_scope(context);
14972 // Set up a property and a number of functions.
14973 context->Global()->Set(v8_str("a"), v8_num(1));
14974 CompileRun("function f1() {return a;}"
14975 "function f2() {return a;}"
14976 "function g1() {return h();}"
14977 "function g2() {return h();}"
14978 "function h() {return 1;}");
14979 Local<Function> f1 =
14980 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14981 Local<Function> f2 =
14982 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14983 Local<Function> g1 =
14984 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14985 Local<Function> g2 =
14986 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14987 Local<Function> h =
14988 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14990 // Get the global object.
14991 v8::Handle<v8::Object> global = context->Global();
14993 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14994 // uses the runtime system to retreive property a whereas f2 uses global load
14996 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14997 for (int i = 0; i < 4; i++) {
14998 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15001 // Same for g1 and g2.
15002 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15003 for (int i = 0; i < 4; i++) {
15004 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15007 // Detach the global and turn on access check.
15008 Local<Object> hidden_global = Local<Object>::Cast(
15009 context->Global()->GetPrototype());
15010 context->DetachGlobal();
15011 hidden_global->TurnOnAccessCheck();
15013 // Failing access check results in exception.
15014 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15015 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15016 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15017 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15019 // No failing access check when just returning a constant.
15020 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15024 static const char* kPropertyA = "a";
15025 static const char* kPropertyH = "h";
15027 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15029 v8::AccessType type,
15030 Local<Value> data) {
15031 if (!name->IsString()) return false;
15032 i::Handle<i::String> name_handle =
15033 v8::Utils::OpenHandle(String::Cast(*name));
15034 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15035 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15039 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15040 v8::Isolate* isolate = CcTest::isolate();
15041 v8::HandleScope handle_scope(isolate);
15043 // Create an environment with access check to the global object disabled by
15044 // default. When the registered access checker will block access to properties
15046 v8::Handle<v8::ObjectTemplate> global_template =
15047 v8::ObjectTemplate::New(isolate);
15048 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15049 IndexedGetAccessBlocker,
15050 v8::Handle<v8::Value>(),
15052 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15053 Context::Scope context_scope(context);
15055 // Set up a property and a number of functions.
15056 context->Global()->Set(v8_str("a"), v8_num(1));
15057 static const char* source = "function f1() {return a;}"
15058 "function f2() {return a;}"
15059 "function g1() {return h();}"
15060 "function g2() {return h();}"
15061 "function h() {return 1;}";
15063 CompileRun(source);
15064 Local<Function> f1;
15065 Local<Function> f2;
15066 Local<Function> g1;
15067 Local<Function> g2;
15069 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15070 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15071 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15072 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15073 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15075 // Get the global object.
15076 v8::Handle<v8::Object> global = context->Global();
15078 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15079 // uses the runtime system to retreive property a whereas f2 uses global load
15081 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15082 for (int i = 0; i < 4; i++) {
15083 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15086 // Same for g1 and g2.
15087 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15088 for (int i = 0; i < 4; i++) {
15089 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15092 // Detach the global and turn on access check now blocking access to property
15093 // a and function h.
15094 Local<Object> hidden_global = Local<Object>::Cast(
15095 context->Global()->GetPrototype());
15096 context->DetachGlobal();
15097 hidden_global->TurnOnAccessCheck();
15099 // Failing access check results in exception.
15100 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15101 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15102 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15103 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15105 // No failing access check when just returning a constant.
15106 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15108 // Now compile the source again. And get the newly compiled functions, except
15109 // for h for which access is blocked.
15110 CompileRun(source);
15111 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15112 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15113 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15114 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15115 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15117 // Failing access check results in exception.
15118 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15119 CHECK(result.IsEmpty());
15120 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15121 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15122 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15123 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15127 // Tests that ScriptData can be serialized and deserialized.
15128 TEST(PreCompileSerialization) {
15129 v8::V8::Initialize();
15131 v8::Isolate* isolate = env->GetIsolate();
15132 HandleScope handle_scope(isolate);
15134 i::FLAG_min_preparse_length = 0;
15135 const char* script = "function foo(a) { return a+1; }";
15136 v8::ScriptCompiler::Source source(v8_str(script));
15137 v8::ScriptCompiler::Compile(isolate, &source,
15138 v8::ScriptCompiler::kProduceParserCache);
15140 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15141 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15142 i::MemCopy(serialized_data, cd->data, cd->length);
15145 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15147 // Verify that the original is the same as the deserialized.
15148 CHECK_EQ(cd->length, deserialized->length());
15149 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15151 delete deserialized;
15152 i::DeleteArray(serialized_data);
15156 // This tests that we do not allow dictionary load/call inline caches
15157 // to use functions that have not yet been compiled. The potential
15158 // problem of loading a function that has not yet been compiled can
15159 // arise because we share code between contexts via the compilation
15161 THREADED_TEST(DictionaryICLoadedFunction) {
15162 v8::HandleScope scope(CcTest::isolate());
15164 for (int i = 0; i < 2; i++) {
15165 LocalContext context;
15166 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15167 context->Global()->Delete(v8_str("tmp"));
15168 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15171 for (int i = 0; i < 2; i++) {
15172 LocalContext context;
15173 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15174 context->Global()->Delete(v8_str("tmp"));
15175 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15180 // Test that cross-context new calls use the context of the callee to
15181 // create the new JavaScript object.
15182 THREADED_TEST(CrossContextNew) {
15183 v8::Isolate* isolate = CcTest::isolate();
15184 v8::HandleScope scope(isolate);
15185 v8::Local<Context> context0 = Context::New(isolate);
15186 v8::Local<Context> context1 = Context::New(isolate);
15188 // Allow cross-domain access.
15189 Local<String> token = v8_str("<security token>");
15190 context0->SetSecurityToken(token);
15191 context1->SetSecurityToken(token);
15193 // Set an 'x' property on the Object prototype and define a
15194 // constructor function in context0.
15196 CompileRun("Object.prototype.x = 42; function C() {};");
15199 // Call the constructor function from context0 and check that the
15200 // result has the 'x' property.
15202 context1->Global()->Set(v8_str("other"), context0->Global());
15203 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15204 CHECK(value->IsInt32());
15205 CHECK_EQ(42, value->Int32Value());
15210 // Verify that we can clone an object
15211 TEST(ObjectClone) {
15213 v8::Isolate* isolate = env->GetIsolate();
15214 v8::HandleScope scope(isolate);
15216 const char* sample =
15218 "rv.alpha = 'hello';" \
15222 // Create an object, verify basics.
15223 Local<Value> val = CompileRun(sample);
15224 CHECK(val->IsObject());
15225 Local<v8::Object> obj = val.As<v8::Object>();
15226 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15228 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15229 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15230 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15233 Local<v8::Object> clone = obj->Clone();
15234 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15235 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15236 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15238 // Set a property on the clone, verify each object.
15239 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15240 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15241 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15245 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15247 explicit OneByteVectorResource(i::Vector<const char> vector)
15249 virtual ~OneByteVectorResource() {}
15250 virtual size_t length() const { return data_.length(); }
15251 virtual const char* data() const { return data_.start(); }
15253 i::Vector<const char> data_;
15257 class UC16VectorResource : public v8::String::ExternalStringResource {
15259 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15261 virtual ~UC16VectorResource() {}
15262 virtual size_t length() const { return data_.length(); }
15263 virtual const i::uc16* data() const { return data_.start(); }
15265 i::Vector<const i::uc16> data_;
15269 static void MorphAString(i::String* string,
15270 OneByteVectorResource* one_byte_resource,
15271 UC16VectorResource* uc16_resource) {
15272 CHECK(i::StringShape(string).IsExternal());
15273 if (string->IsOneByteRepresentation()) {
15274 // Check old map is not internalized or long.
15275 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15276 // Morph external string to be TwoByte string.
15277 string->set_map(CcTest::heap()->external_string_map());
15278 i::ExternalTwoByteString* morphed =
15279 i::ExternalTwoByteString::cast(string);
15280 morphed->set_resource(uc16_resource);
15282 // Check old map is not internalized or long.
15283 CHECK(string->map() == CcTest::heap()->external_string_map());
15284 // Morph external string to be one-byte string.
15285 string->set_map(CcTest::heap()->external_one_byte_string_map());
15286 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15287 morphed->set_resource(one_byte_resource);
15292 // Test that we can still flatten a string if the components it is built up
15293 // from have been turned into 16 bit strings in the mean time.
15294 THREADED_TEST(MorphCompositeStringTest) {
15295 char utf_buffer[129];
15296 const char* c_string = "Now is the time for all good men"
15297 " to come to the aid of the party";
15298 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15301 i::Factory* factory = CcTest::i_isolate()->factory();
15302 v8::HandleScope scope(env->GetIsolate());
15303 OneByteVectorResource one_byte_resource(
15304 i::Vector<const char>(c_string, i::StrLength(c_string)));
15305 UC16VectorResource uc16_resource(
15306 i::Vector<const uint16_t>(two_byte_string,
15307 i::StrLength(c_string)));
15310 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15311 &one_byte_resource).ToHandleChecked()));
15313 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15314 &one_byte_resource).ToHandleChecked()));
15316 env->Global()->Set(v8_str("lhs"), lhs);
15317 env->Global()->Set(v8_str("rhs"), rhs);
15320 "var cons = lhs + rhs;"
15321 "var slice = lhs.substring(1, lhs.length - 1);"
15322 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15324 CHECK(lhs->IsOneByte());
15325 CHECK(rhs->IsOneByte());
15327 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15329 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15332 // This should UTF-8 without flattening, since everything is ASCII.
15333 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15334 CHECK_EQ(128, cons->Utf8Length());
15336 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15337 CHECK_EQ(128, nchars);
15338 CHECK_EQ(0, strcmp(
15340 "Now is the time for all good men to come to the aid of the party"
15341 "Now is the time for all good men to come to the aid of the party"));
15343 // Now do some stuff to make sure the strings are flattened, etc.
15345 "/[^a-z]/.test(cons);"
15346 "/[^a-z]/.test(slice);"
15347 "/[^a-z]/.test(slice_on_cons);");
15348 const char* expected_cons =
15349 "Now is the time for all good men to come to the aid of the party"
15350 "Now is the time for all good men to come to the aid of the party";
15351 const char* expected_slice =
15352 "ow is the time for all good men to come to the aid of the part";
15353 const char* expected_slice_on_cons =
15354 "ow is the time for all good men to come to the aid of the party"
15355 "Now is the time for all good men to come to the aid of the part";
15356 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15357 env->Global()->Get(v8_str("cons")));
15358 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15359 env->Global()->Get(v8_str("slice")));
15360 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15361 env->Global()->Get(v8_str("slice_on_cons")));
15363 i::DeleteArray(two_byte_string);
15367 TEST(CompileExternalTwoByteSource) {
15368 LocalContext context;
15369 v8::HandleScope scope(context->GetIsolate());
15371 // This is a very short list of sources, which currently is to check for a
15372 // regression caused by r2703.
15373 const char* one_byte_sources[] = {
15375 "-0.5", // This mainly testes PushBack in the Scanner.
15376 "--0.5", // This mainly testes PushBack in the Scanner.
15379 // Compile the sources as external two byte strings.
15380 for (int i = 0; one_byte_sources[i] != NULL; i++) {
15381 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15382 TestResource* uc16_resource = new TestResource(two_byte_string);
15383 v8::Local<v8::String> source =
15384 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15385 v8::Script::Compile(source);
15390 #ifndef V8_INTERPRETED_REGEXP
15392 struct RegExpInterruptionData {
15394 UC16VectorResource* string_resource;
15395 v8::Persistent<v8::String> string;
15396 } regexp_interruption_data;
15399 class RegExpInterruptionThread : public v8::base::Thread {
15401 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15402 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15404 virtual void Run() {
15405 for (regexp_interruption_data.loop_count = 0;
15406 regexp_interruption_data.loop_count < 7;
15407 regexp_interruption_data.loop_count++) {
15408 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
15409 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15411 v8::base::OS::Sleep(50); // Wait a bit before terminating.
15412 v8::V8::TerminateExecution(isolate_);
15416 v8::Isolate* isolate_;
15420 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15421 if (regexp_interruption_data.loop_count != 2) return;
15422 v8::HandleScope scope(CcTest::isolate());
15423 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15424 CcTest::isolate(), regexp_interruption_data.string);
15425 string->MakeExternal(regexp_interruption_data.string_resource);
15429 // Test that RegExp execution can be interrupted. Specifically, we test
15430 // * interrupting with GC
15431 // * turn the subject string from one-byte internal to two-byte external string
15432 // * force termination
15433 TEST(RegExpInterruption) {
15434 v8::HandleScope scope(CcTest::isolate());
15437 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15439 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15440 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15441 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15442 v8::Local<v8::String> string = v8_str(one_byte_content);
15444 CcTest::global()->Set(v8_str("a"), string);
15445 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15446 regexp_interruption_data.string_resource = new UC16VectorResource(
15447 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15449 v8::TryCatch try_catch;
15450 timeout_thread.Start();
15452 CompileRun("/((a*)*)*b/.exec(a)");
15453 CHECK(try_catch.HasTerminated());
15455 timeout_thread.Join();
15457 regexp_interruption_data.string.Reset();
15458 i::DeleteArray(uc16_content);
15461 #endif // V8_INTERPRETED_REGEXP
15464 // Test that we cannot set a property on the global object if there
15465 // is a read-only property in the prototype chain.
15466 TEST(ReadOnlyPropertyInGlobalProto) {
15467 v8::Isolate* isolate = CcTest::isolate();
15468 v8::HandleScope scope(isolate);
15469 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15470 LocalContext context(0, templ);
15471 v8::Handle<v8::Object> global = context->Global();
15472 v8::Handle<v8::Object> global_proto =
15473 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15474 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15476 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15478 // Check without 'eval' or 'with'.
15479 v8::Handle<v8::Value> res =
15480 CompileRun("function f() { x = 42; return x; }; f()");
15481 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15482 // Check with 'eval'.
15483 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15484 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15485 // Check with 'with'.
15486 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15487 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15490 static int force_set_set_count = 0;
15491 static int force_set_get_count = 0;
15492 bool pass_on_get = false;
15494 static void ForceSetGetter(v8::Local<v8::String> name,
15495 const v8::PropertyCallbackInfo<v8::Value>& info) {
15496 force_set_get_count++;
15500 info.GetReturnValue().Set(3);
15503 static void ForceSetSetter(v8::Local<v8::String> name,
15504 v8::Local<v8::Value> value,
15505 const v8::PropertyCallbackInfo<void>& info) {
15506 force_set_set_count++;
15509 static void ForceSetInterceptSetter(
15510 v8::Local<v8::String> name,
15511 v8::Local<v8::Value> value,
15512 const v8::PropertyCallbackInfo<v8::Value>& info) {
15513 force_set_set_count++;
15514 info.GetReturnValue().SetUndefined();
15519 force_set_get_count = 0;
15520 force_set_set_count = 0;
15521 pass_on_get = false;
15523 v8::Isolate* isolate = CcTest::isolate();
15524 v8::HandleScope scope(isolate);
15525 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15526 v8::Handle<v8::String> access_property =
15527 v8::String::NewFromUtf8(isolate, "a");
15528 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15529 LocalContext context(NULL, templ);
15530 v8::Handle<v8::Object> global = context->Global();
15532 // Ordinary properties
15533 v8::Handle<v8::String> simple_property =
15534 v8::String::NewFromUtf8(isolate, "p");
15535 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15536 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15537 // This should fail because the property is read-only
15538 global->Set(simple_property, v8::Int32::New(isolate, 5));
15539 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15540 // This should succeed even though the property is read-only
15541 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15542 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15545 CHECK_EQ(0, force_set_set_count);
15546 CHECK_EQ(0, force_set_get_count);
15547 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15548 // CHECK_EQ the property shouldn't override it, just call the setter
15549 // which in this case does nothing.
15550 global->Set(access_property, v8::Int32::New(isolate, 7));
15551 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15552 CHECK_EQ(1, force_set_set_count);
15553 CHECK_EQ(2, force_set_get_count);
15554 // Forcing the property to be set should override the accessor without
15556 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15557 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15558 CHECK_EQ(1, force_set_set_count);
15559 CHECK_EQ(2, force_set_get_count);
15563 TEST(ForceSetWithInterceptor) {
15564 force_set_get_count = 0;
15565 force_set_set_count = 0;
15566 pass_on_get = false;
15568 v8::Isolate* isolate = CcTest::isolate();
15569 v8::HandleScope scope(isolate);
15570 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15571 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15572 LocalContext context(NULL, templ);
15573 v8::Handle<v8::Object> global = context->Global();
15575 v8::Handle<v8::String> some_property =
15576 v8::String::NewFromUtf8(isolate, "a");
15577 CHECK_EQ(0, force_set_set_count);
15578 CHECK_EQ(0, force_set_get_count);
15579 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15580 // Setting the property shouldn't override it, just call the setter
15581 // which in this case does nothing.
15582 global->Set(some_property, v8::Int32::New(isolate, 7));
15583 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15584 CHECK_EQ(1, force_set_set_count);
15585 CHECK_EQ(2, force_set_get_count);
15586 // Getting the property when the interceptor returns an empty handle
15587 // should yield undefined, since the property isn't present on the
15588 // object itself yet.
15589 pass_on_get = true;
15590 CHECK(global->Get(some_property)->IsUndefined());
15591 CHECK_EQ(1, force_set_set_count);
15592 CHECK_EQ(3, force_set_get_count);
15593 // Forcing the property to be set should cause the value to be
15594 // set locally without calling the interceptor.
15595 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15596 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15597 CHECK_EQ(1, force_set_set_count);
15598 CHECK_EQ(4, force_set_get_count);
15599 // Reenabling the interceptor should cause it to take precedence over
15601 pass_on_get = false;
15602 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15603 CHECK_EQ(1, force_set_set_count);
15604 CHECK_EQ(5, force_set_get_count);
15605 // The interceptor should also work for other properties
15606 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15608 CHECK_EQ(1, force_set_set_count);
15609 CHECK_EQ(6, force_set_get_count);
15613 THREADED_TEST(ForceDelete) {
15614 v8::Isolate* isolate = CcTest::isolate();
15615 v8::HandleScope scope(isolate);
15616 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15617 LocalContext context(NULL, templ);
15618 v8::Handle<v8::Object> global = context->Global();
15620 // Ordinary properties
15621 v8::Handle<v8::String> simple_property =
15622 v8::String::NewFromUtf8(isolate, "p");
15623 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15624 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15625 // This should fail because the property is dont-delete.
15626 CHECK(!global->Delete(simple_property));
15627 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15628 // This should succeed even though the property is dont-delete.
15629 CHECK(global->ForceDelete(simple_property));
15630 CHECK(global->Get(simple_property)->IsUndefined());
15634 static int force_delete_interceptor_count = 0;
15635 static bool pass_on_delete = false;
15638 static void ForceDeleteDeleter(
15639 v8::Local<v8::String> name,
15640 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15641 force_delete_interceptor_count++;
15642 if (pass_on_delete) return;
15643 info.GetReturnValue().Set(true);
15647 THREADED_TEST(ForceDeleteWithInterceptor) {
15648 force_delete_interceptor_count = 0;
15649 pass_on_delete = false;
15651 v8::Isolate* isolate = CcTest::isolate();
15652 v8::HandleScope scope(isolate);
15653 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15654 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15655 LocalContext context(NULL, templ);
15656 v8::Handle<v8::Object> global = context->Global();
15658 v8::Handle<v8::String> some_property =
15659 v8::String::NewFromUtf8(isolate, "a");
15660 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15663 // Deleting a property should get intercepted and nothing should
15665 CHECK_EQ(0, force_delete_interceptor_count);
15666 CHECK(global->Delete(some_property));
15667 CHECK_EQ(1, force_delete_interceptor_count);
15668 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15669 // Deleting the property when the interceptor returns an empty
15670 // handle should not delete the property since it is DontDelete.
15671 pass_on_delete = true;
15672 CHECK(!global->Delete(some_property));
15673 CHECK_EQ(2, force_delete_interceptor_count);
15674 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15675 // Forcing the property to be deleted should delete the value
15676 // without calling the interceptor.
15677 CHECK(global->ForceDelete(some_property));
15678 CHECK(global->Get(some_property)->IsUndefined());
15679 CHECK_EQ(2, force_delete_interceptor_count);
15683 // Make sure that forcing a delete invalidates any IC stubs, so we
15684 // don't read the hole value.
15685 THREADED_TEST(ForceDeleteIC) {
15686 LocalContext context;
15687 v8::HandleScope scope(context->GetIsolate());
15688 // Create a DontDelete variable on the global object.
15689 CompileRun("this.__proto__ = { foo: 'horse' };"
15690 "var foo = 'fish';"
15691 "function f() { return foo.length; }");
15692 // Initialize the IC for foo in f.
15693 CompileRun("for (var i = 0; i < 4; i++) f();");
15694 // Make sure the value of foo is correct before the deletion.
15695 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15696 // Force the deletion of foo.
15697 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15698 // Make sure the value for foo is read from the prototype, and that
15699 // we don't get in trouble with reading the deleted cell value
15701 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15705 TEST(InlinedFunctionAcrossContexts) {
15706 i::FLAG_allow_natives_syntax = true;
15707 v8::Isolate* isolate = CcTest::isolate();
15708 v8::HandleScope outer_scope(isolate);
15709 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15710 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15714 v8::HandleScope inner_scope(CcTest::isolate());
15715 CompileRun("var G = 42; function foo() { return G; }");
15716 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15718 ctx2->Global()->Set(v8_str("o"), foo);
15719 v8::Local<v8::Value> res = CompileRun(
15720 "function f() { return o(); }"
15721 "for (var i = 0; i < 10; ++i) f();"
15722 "%OptimizeFunctionOnNextCall(f);"
15724 CHECK_EQ(42, res->Int32Value());
15726 v8::Handle<v8::String> G_property =
15727 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15728 CHECK(ctx1->Global()->ForceDelete(G_property));
15735 " return e.toString();"
15738 "ReferenceError: G is not defined");
15745 static v8::Local<Context> calling_context0;
15746 static v8::Local<Context> calling_context1;
15747 static v8::Local<Context> calling_context2;
15750 // Check that the call to the callback is initiated in
15751 // calling_context2, the directly calling context is calling_context1
15752 // and the callback itself is in calling_context0.
15753 static void GetCallingContextCallback(
15754 const v8::FunctionCallbackInfo<v8::Value>& args) {
15755 ApiTestFuzzer::Fuzz();
15756 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15757 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15758 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15759 args.GetReturnValue().Set(42);
15763 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15764 i::Isolate* isolate = CcTest::i_isolate();
15765 CHECK(isolate != NULL);
15766 CHECK(isolate->context() == NULL);
15767 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15768 v8::HandleScope scope(v8_isolate);
15769 // The following should not crash, but return an empty handle.
15770 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15771 CHECK(current.IsEmpty());
15775 THREADED_TEST(GetCallingContext) {
15776 v8::Isolate* isolate = CcTest::isolate();
15777 v8::HandleScope scope(isolate);
15779 Local<Context> calling_context0(Context::New(isolate));
15780 Local<Context> calling_context1(Context::New(isolate));
15781 Local<Context> calling_context2(Context::New(isolate));
15782 ::calling_context0 = calling_context0;
15783 ::calling_context1 = calling_context1;
15784 ::calling_context2 = calling_context2;
15786 // Allow cross-domain access.
15787 Local<String> token = v8_str("<security token>");
15788 calling_context0->SetSecurityToken(token);
15789 calling_context1->SetSecurityToken(token);
15790 calling_context2->SetSecurityToken(token);
15792 // Create an object with a C++ callback in context0.
15793 calling_context0->Enter();
15794 Local<v8::FunctionTemplate> callback_templ =
15795 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15796 calling_context0->Global()->Set(v8_str("callback"),
15797 callback_templ->GetFunction());
15798 calling_context0->Exit();
15800 // Expose context0 in context1 and set up a function that calls the
15801 // callback function.
15802 calling_context1->Enter();
15803 calling_context1->Global()->Set(v8_str("context0"),
15804 calling_context0->Global());
15805 CompileRun("function f() { context0.callback() }");
15806 calling_context1->Exit();
15808 // Expose context1 in context2 and call the callback function in
15809 // context0 indirectly through f in context1.
15810 calling_context2->Enter();
15811 calling_context2->Global()->Set(v8_str("context1"),
15812 calling_context1->Global());
15813 CompileRun("context1.f()");
15814 calling_context2->Exit();
15815 ::calling_context0.Clear();
15816 ::calling_context1.Clear();
15817 ::calling_context2.Clear();
15821 // Check that a variable declaration with no explicit initialization
15822 // value does shadow an existing property in the prototype chain.
15823 THREADED_TEST(InitGlobalVarInProtoChain) {
15824 LocalContext context;
15825 v8::HandleScope scope(context->GetIsolate());
15826 // Introduce a variable in the prototype chain.
15827 CompileRun("__proto__.x = 42");
15828 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15829 CHECK(!result->IsUndefined());
15830 CHECK_EQ(43, result->Int32Value());
15834 // Regression test for issue 398.
15835 // If a function is added to an object, creating a constant function
15836 // field, and the result is cloned, replacing the constant function on the
15837 // original should not affect the clone.
15838 // See http://code.google.com/p/v8/issues/detail?id=398
15839 THREADED_TEST(ReplaceConstantFunction) {
15840 LocalContext context;
15841 v8::Isolate* isolate = context->GetIsolate();
15842 v8::HandleScope scope(isolate);
15843 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15844 v8::Handle<v8::FunctionTemplate> func_templ =
15845 v8::FunctionTemplate::New(isolate);
15846 v8::Handle<v8::String> foo_string =
15847 v8::String::NewFromUtf8(isolate, "foo");
15848 obj->Set(foo_string, func_templ->GetFunction());
15849 v8::Handle<v8::Object> obj_clone = obj->Clone();
15850 obj_clone->Set(foo_string,
15851 v8::String::NewFromUtf8(isolate, "Hello"));
15852 CHECK(!obj->Get(foo_string)->IsUndefined());
15856 static void CheckElementValue(i::Isolate* isolate,
15858 i::Handle<i::Object> obj,
15860 i::Object* element =
15861 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15862 CHECK_EQ(expected, i::Smi::cast(element)->value());
15866 THREADED_TEST(PixelArray) {
15867 LocalContext context;
15868 i::Isolate* isolate = CcTest::i_isolate();
15869 i::Factory* factory = isolate->factory();
15870 v8::HandleScope scope(context->GetIsolate());
15871 const int kElementCount = 260;
15872 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15873 i::Handle<i::ExternalUint8ClampedArray> pixels =
15874 i::Handle<i::ExternalUint8ClampedArray>::cast(
15875 factory->NewExternalArray(kElementCount,
15876 v8::kExternalUint8ClampedArray,
15878 // Force GC to trigger verification.
15879 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15880 for (int i = 0; i < kElementCount; i++) {
15881 pixels->set(i, i % 256);
15883 // Force GC to trigger verification.
15884 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15885 for (int i = 0; i < kElementCount; i++) {
15886 CHECK_EQ(i % 256, pixels->get_scalar(i));
15887 CHECK_EQ(i % 256, pixel_data[i]);
15890 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15891 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15892 // Set the elements to be the pixels.
15893 // jsobj->set_elements(*pixels);
15894 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15895 CheckElementValue(isolate, 1, jsobj, 1);
15896 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15897 context->Global()->Set(v8_str("pixels"), obj);
15898 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15899 CHECK_EQ(1503, result->Int32Value());
15900 result = CompileRun("pixels[1]");
15901 CHECK_EQ(1, result->Int32Value());
15903 result = CompileRun("var sum = 0;"
15904 "for (var i = 0; i < 8; i++) {"
15905 " sum += pixels[i] = pixels[i] = -i;"
15908 CHECK_EQ(-28, result->Int32Value());
15910 result = CompileRun("var sum = 0;"
15911 "for (var i = 0; i < 8; i++) {"
15912 " sum += pixels[i] = pixels[i] = 0;"
15915 CHECK_EQ(0, result->Int32Value());
15917 result = CompileRun("var sum = 0;"
15918 "for (var i = 0; i < 8; i++) {"
15919 " sum += pixels[i] = pixels[i] = 255;"
15922 CHECK_EQ(8 * 255, result->Int32Value());
15924 result = CompileRun("var sum = 0;"
15925 "for (var i = 0; i < 8; i++) {"
15926 " sum += pixels[i] = pixels[i] = 256 + i;"
15929 CHECK_EQ(2076, result->Int32Value());
15931 result = CompileRun("var sum = 0;"
15932 "for (var i = 0; i < 8; i++) {"
15933 " sum += pixels[i] = pixels[i] = i;"
15936 CHECK_EQ(28, result->Int32Value());
15938 result = CompileRun("var sum = 0;"
15939 "for (var i = 0; i < 8; i++) {"
15940 " sum += pixels[i];"
15943 CHECK_EQ(28, result->Int32Value());
15945 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15946 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15947 i::Handle<i::Object> no_failure;
15948 no_failure = i::JSObject::SetElement(
15949 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15950 DCHECK(!no_failure.is_null());
15952 CheckElementValue(isolate, 2, jsobj, 1);
15953 *value.location() = i::Smi::FromInt(256);
15954 no_failure = i::JSObject::SetElement(
15955 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15956 DCHECK(!no_failure.is_null());
15958 CheckElementValue(isolate, 255, jsobj, 1);
15959 *value.location() = i::Smi::FromInt(-1);
15960 no_failure = i::JSObject::SetElement(
15961 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15962 DCHECK(!no_failure.is_null());
15964 CheckElementValue(isolate, 0, jsobj, 1);
15966 result = CompileRun("for (var i = 0; i < 8; i++) {"
15967 " pixels[i] = (i * 65) - 109;"
15969 "pixels[1] + pixels[6];");
15970 CHECK_EQ(255, result->Int32Value());
15971 CheckElementValue(isolate, 0, jsobj, 0);
15972 CheckElementValue(isolate, 0, jsobj, 1);
15973 CheckElementValue(isolate, 21, jsobj, 2);
15974 CheckElementValue(isolate, 86, jsobj, 3);
15975 CheckElementValue(isolate, 151, jsobj, 4);
15976 CheckElementValue(isolate, 216, jsobj, 5);
15977 CheckElementValue(isolate, 255, jsobj, 6);
15978 CheckElementValue(isolate, 255, jsobj, 7);
15979 result = CompileRun("var sum = 0;"
15980 "for (var i = 0; i < 8; i++) {"
15981 " sum += pixels[i];"
15984 CHECK_EQ(984, result->Int32Value());
15986 result = CompileRun("for (var i = 0; i < 8; i++) {"
15987 " pixels[i] = (i * 1.1);"
15989 "pixels[1] + pixels[6];");
15990 CHECK_EQ(8, result->Int32Value());
15991 CheckElementValue(isolate, 0, jsobj, 0);
15992 CheckElementValue(isolate, 1, jsobj, 1);
15993 CheckElementValue(isolate, 2, jsobj, 2);
15994 CheckElementValue(isolate, 3, jsobj, 3);
15995 CheckElementValue(isolate, 4, jsobj, 4);
15996 CheckElementValue(isolate, 6, jsobj, 5);
15997 CheckElementValue(isolate, 7, jsobj, 6);
15998 CheckElementValue(isolate, 8, jsobj, 7);
16000 result = CompileRun("for (var i = 0; i < 8; i++) {"
16001 " pixels[7] = undefined;"
16004 CHECK_EQ(0, result->Int32Value());
16005 CheckElementValue(isolate, 0, jsobj, 7);
16007 result = CompileRun("for (var i = 0; i < 8; i++) {"
16008 " pixels[6] = '2.3';"
16011 CHECK_EQ(2, result->Int32Value());
16012 CheckElementValue(isolate, 2, jsobj, 6);
16014 result = CompileRun("for (var i = 0; i < 8; i++) {"
16015 " pixels[5] = NaN;"
16018 CHECK_EQ(0, result->Int32Value());
16019 CheckElementValue(isolate, 0, jsobj, 5);
16021 result = CompileRun("for (var i = 0; i < 8; i++) {"
16022 " pixels[8] = Infinity;"
16025 CHECK_EQ(255, result->Int32Value());
16026 CheckElementValue(isolate, 255, jsobj, 8);
16028 result = CompileRun("for (var i = 0; i < 8; i++) {"
16029 " pixels[9] = -Infinity;"
16032 CHECK_EQ(0, result->Int32Value());
16033 CheckElementValue(isolate, 0, jsobj, 9);
16035 result = CompileRun("pixels[3] = 33;"
16036 "delete pixels[3];"
16038 CHECK_EQ(33, result->Int32Value());
16040 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16041 "pixels[2] = 12; pixels[3] = 13;"
16042 "pixels.__defineGetter__('2',"
16043 "function() { return 120; });"
16045 CHECK_EQ(12, result->Int32Value());
16047 result = CompileRun("var js_array = new Array(40);"
16048 "js_array[0] = 77;"
16050 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16052 result = CompileRun("pixels[1] = 23;"
16053 "pixels.__proto__ = [];"
16054 "js_array.__proto__ = pixels;"
16055 "js_array.concat(pixels);");
16056 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16057 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16059 result = CompileRun("pixels[1] = 23;");
16060 CHECK_EQ(23, result->Int32Value());
16062 // Test for index greater than 255. Regression test for:
16063 // http://code.google.com/p/chromium/issues/detail?id=26337.
16064 result = CompileRun("pixels[256] = 255;");
16065 CHECK_EQ(255, result->Int32Value());
16066 result = CompileRun("var i = 0;"
16067 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16069 CHECK_EQ(255, result->Int32Value());
16071 // Make sure that pixel array ICs recognize when a non-pixel array
16072 // is passed to it.
16073 result = CompileRun("function pa_load(p) {"
16075 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16078 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16079 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16080 "just_ints = new Object();"
16081 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16082 "for (var i = 0; i < 10; ++i) {"
16083 " result = pa_load(just_ints);"
16086 CHECK_EQ(32640, result->Int32Value());
16088 // Make sure that pixel array ICs recognize out-of-bound accesses.
16089 result = CompileRun("function pa_load(p, start) {"
16091 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16094 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16095 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16096 "for (var i = 0; i < 10; ++i) {"
16097 " result = pa_load(pixels,-10);"
16100 CHECK_EQ(0, result->Int32Value());
16102 // Make sure that generic ICs properly handles a pixel array.
16103 result = CompileRun("function pa_load(p) {"
16105 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16108 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16109 "just_ints = new Object();"
16110 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16111 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16112 "for (var i = 0; i < 10; ++i) {"
16113 " result = pa_load(pixels);"
16116 CHECK_EQ(32640, result->Int32Value());
16118 // Make sure that generic load ICs recognize out-of-bound accesses in
16120 result = CompileRun("function pa_load(p, start) {"
16122 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16125 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16126 "just_ints = new Object();"
16127 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16128 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16129 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16130 "for (var i = 0; i < 10; ++i) {"
16131 " result = pa_load(pixels,-10);"
16134 CHECK_EQ(0, result->Int32Value());
16136 // Make sure that generic ICs properly handles other types than pixel
16137 // arrays (that the inlined fast pixel array test leaves the right information
16138 // in the right registers).
16139 result = CompileRun("function pa_load(p) {"
16141 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16144 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16145 "just_ints = new Object();"
16146 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16147 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16148 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16149 "sparse_array = new Object();"
16150 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16151 "sparse_array[1000000] = 3;"
16152 "for (var i = 0; i < 10; ++i) {"
16153 " result = pa_load(sparse_array);"
16156 CHECK_EQ(32640, result->Int32Value());
16158 // Make sure that pixel array store ICs clamp values correctly.
16159 result = CompileRun("function pa_store(p) {"
16160 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16162 "pa_store(pixels);"
16164 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16166 CHECK_EQ(48896, result->Int32Value());
16168 // Make sure that pixel array stores correctly handle accesses outside
16169 // of the pixel array..
16170 result = CompileRun("function pa_store(p,start) {"
16171 " for (var j = 0; j < 256; j++) {"
16172 " p[j+start] = j * 2;"
16175 "pa_store(pixels,0);"
16176 "pa_store(pixels,-128);"
16178 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16180 CHECK_EQ(65280, result->Int32Value());
16182 // Make sure that the generic store stub correctly handle accesses outside
16183 // of the pixel array..
16184 result = CompileRun("function pa_store(p,start) {"
16185 " for (var j = 0; j < 256; j++) {"
16186 " p[j+start] = j * 2;"
16189 "pa_store(pixels,0);"
16190 "just_ints = new Object();"
16191 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16192 "pa_store(just_ints, 0);"
16193 "pa_store(pixels,-128);"
16195 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16197 CHECK_EQ(65280, result->Int32Value());
16199 // Make sure that the generic keyed store stub clamps pixel array values
16201 result = CompileRun("function pa_store(p) {"
16202 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16204 "pa_store(pixels);"
16205 "just_ints = new Object();"
16206 "pa_store(just_ints);"
16207 "pa_store(pixels);"
16209 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16211 CHECK_EQ(48896, result->Int32Value());
16213 // Make sure that pixel array loads are optimized by crankshaft.
16214 result = CompileRun("function pa_load(p) {"
16216 " for (var i=0; i<256; ++i) {"
16221 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16222 "for (var i = 0; i < 5000; ++i) {"
16223 " result = pa_load(pixels);"
16226 CHECK_EQ(32640, result->Int32Value());
16228 // Make sure that pixel array stores are optimized by crankshaft.
16229 result = CompileRun("function pa_init(p) {"
16230 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16232 "function pa_load(p) {"
16234 " for (var i=0; i<256; ++i) {"
16239 "for (var i = 0; i < 5000; ++i) {"
16240 " pa_init(pixels);"
16242 "result = pa_load(pixels);"
16244 CHECK_EQ(32640, result->Int32Value());
16250 THREADED_TEST(PixelArrayInfo) {
16251 LocalContext context;
16252 v8::HandleScope scope(context->GetIsolate());
16253 for (int size = 0; size < 100; size += 10) {
16254 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16255 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16256 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16257 CHECK(obj->HasIndexedPropertiesInPixelData());
16258 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16259 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16265 static void NotHandledIndexedPropertyGetter(
16267 const v8::PropertyCallbackInfo<v8::Value>& info) {
16268 ApiTestFuzzer::Fuzz();
16272 static void NotHandledIndexedPropertySetter(
16274 Local<Value> value,
16275 const v8::PropertyCallbackInfo<v8::Value>& info) {
16276 ApiTestFuzzer::Fuzz();
16280 THREADED_TEST(PixelArrayWithInterceptor) {
16281 LocalContext context;
16282 i::Factory* factory = CcTest::i_isolate()->factory();
16283 v8::Isolate* isolate = context->GetIsolate();
16284 v8::HandleScope scope(isolate);
16285 const int kElementCount = 260;
16286 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16287 i::Handle<i::ExternalUint8ClampedArray> pixels =
16288 i::Handle<i::ExternalUint8ClampedArray>::cast(
16289 factory->NewExternalArray(kElementCount,
16290 v8::kExternalUint8ClampedArray,
16292 for (int i = 0; i < kElementCount; i++) {
16293 pixels->set(i, i % 256);
16295 v8::Handle<v8::ObjectTemplate> templ =
16296 v8::ObjectTemplate::New(context->GetIsolate());
16297 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16298 NotHandledIndexedPropertySetter);
16299 v8::Handle<v8::Object> obj = templ->NewInstance();
16300 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16301 context->Global()->Set(v8_str("pixels"), obj);
16302 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16303 CHECK_EQ(1, result->Int32Value());
16304 result = CompileRun("var sum = 0;"
16305 "for (var i = 0; i < 8; i++) {"
16306 " sum += pixels[i] = pixels[i] = -i;"
16309 CHECK_EQ(-28, result->Int32Value());
16310 result = CompileRun("pixels.hasOwnProperty('1')");
16311 CHECK(result->BooleanValue());
16316 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16317 switch (array_type) {
16318 case v8::kExternalInt8Array:
16319 case v8::kExternalUint8Array:
16320 case v8::kExternalUint8ClampedArray:
16323 case v8::kExternalInt16Array:
16324 case v8::kExternalUint16Array:
16327 case v8::kExternalInt32Array:
16328 case v8::kExternalUint32Array:
16329 case v8::kExternalFloat32Array:
16332 case v8::kExternalFloat64Array:
16344 template <class ExternalArrayClass, class ElementType>
16345 static void ObjectWithExternalArrayTestHelper(
16346 Handle<Context> context,
16347 v8::Handle<Object> obj,
16349 v8::ExternalArrayType array_type,
16350 int64_t low, int64_t high) {
16351 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16352 i::Isolate* isolate = jsobj->GetIsolate();
16353 obj->Set(v8_str("field"),
16354 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16355 context->Global()->Set(v8_str("ext_array"), obj);
16356 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16357 CHECK_EQ(1503, result->Int32Value());
16358 result = CompileRun("ext_array[1]");
16359 CHECK_EQ(1, result->Int32Value());
16361 // Check assigned smis
16362 result = CompileRun("for (var i = 0; i < 8; i++) {"
16363 " ext_array[i] = i;"
16366 "for (var i = 0; i < 8; i++) {"
16367 " sum += ext_array[i];"
16371 CHECK_EQ(28, result->Int32Value());
16372 // Check pass through of assigned smis
16373 result = CompileRun("var sum = 0;"
16374 "for (var i = 0; i < 8; i++) {"
16375 " sum += ext_array[i] = ext_array[i] = -i;"
16378 CHECK_EQ(-28, result->Int32Value());
16381 // Check assigned smis in reverse order
16382 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16383 " ext_array[i] = i;"
16386 "for (var i = 0; i < 8; i++) {"
16387 " sum += ext_array[i];"
16390 CHECK_EQ(28, result->Int32Value());
16392 // Check pass through of assigned HeapNumbers
16393 result = CompileRun("var sum = 0;"
16394 "for (var i = 0; i < 16; i+=2) {"
16395 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16398 CHECK_EQ(-28, result->Int32Value());
16400 // Check assigned HeapNumbers
16401 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16402 " ext_array[i] = (i * 0.5);"
16405 "for (var i = 0; i < 16; i+=2) {"
16406 " sum += ext_array[i];"
16409 CHECK_EQ(28, result->Int32Value());
16411 // Check assigned HeapNumbers in reverse order
16412 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16413 " ext_array[i] = (i * 0.5);"
16416 "for (var i = 0; i < 16; i+=2) {"
16417 " sum += ext_array[i];"
16420 CHECK_EQ(28, result->Int32Value());
16422 i::ScopedVector<char> test_buf(1024);
16424 // Check legal boundary conditions.
16425 // The repeated loads and stores ensure the ICs are exercised.
16426 const char* boundary_program =
16428 "for (var i = 0; i < 16; i++) {"
16429 " ext_array[i] = %lld;"
16431 " res = ext_array[i];"
16435 i::SNPrintF(test_buf,
16438 result = CompileRun(test_buf.start());
16439 CHECK_EQ(low, result->IntegerValue());
16441 i::SNPrintF(test_buf,
16444 result = CompileRun(test_buf.start());
16445 CHECK_EQ(high, result->IntegerValue());
16447 // Check misprediction of type in IC.
16448 result = CompileRun("var tmp_array = ext_array;"
16450 "for (var i = 0; i < 8; i++) {"
16451 " tmp_array[i] = i;"
16452 " sum += tmp_array[i];"
16458 // Force GC to trigger verification.
16459 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16460 CHECK_EQ(28, result->Int32Value());
16462 // Make sure out-of-range loads do not throw.
16463 i::SNPrintF(test_buf,
16464 "var caught_exception = false;"
16468 " caught_exception = true;"
16470 "caught_exception;",
16472 result = CompileRun(test_buf.start());
16473 CHECK_EQ(false, result->BooleanValue());
16475 // Make sure out-of-range stores do not throw.
16476 i::SNPrintF(test_buf,
16477 "var caught_exception = false;"
16479 " ext_array[%d] = 1;"
16481 " caught_exception = true;"
16483 "caught_exception;",
16485 result = CompileRun(test_buf.start());
16486 CHECK_EQ(false, result->BooleanValue());
16488 // Check other boundary conditions, values and operations.
16489 result = CompileRun("for (var i = 0; i < 8; i++) {"
16490 " ext_array[7] = undefined;"
16493 CHECK_EQ(0, result->Int32Value());
16494 if (array_type == v8::kExternalFloat64Array ||
16495 array_type == v8::kExternalFloat32Array) {
16496 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16498 i::Object::GetElement(
16499 isolate, jsobj, 7).ToHandleChecked()->Number()));
16501 CheckElementValue(isolate, 0, jsobj, 7);
16504 result = CompileRun("for (var i = 0; i < 8; i++) {"
16505 " ext_array[6] = '2.3';"
16508 CHECK_EQ(2, result->Int32Value());
16511 i::Object::GetElement(
16512 isolate, jsobj, 6).ToHandleChecked()->Number()));
16514 if (array_type != v8::kExternalFloat32Array &&
16515 array_type != v8::kExternalFloat64Array) {
16516 // Though the specification doesn't state it, be explicit about
16517 // converting NaNs and +/-Infinity to zero.
16518 result = CompileRun("for (var i = 0; i < 8; i++) {"
16519 " ext_array[i] = 5;"
16521 "for (var i = 0; i < 8; i++) {"
16522 " ext_array[i] = NaN;"
16525 CHECK_EQ(0, result->Int32Value());
16526 CheckElementValue(isolate, 0, jsobj, 5);
16528 result = CompileRun("for (var i = 0; i < 8; i++) {"
16529 " ext_array[i] = 5;"
16531 "for (var i = 0; i < 8; i++) {"
16532 " ext_array[i] = Infinity;"
16535 int expected_value =
16536 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16537 CHECK_EQ(expected_value, result->Int32Value());
16538 CheckElementValue(isolate, expected_value, jsobj, 5);
16540 result = CompileRun("for (var i = 0; i < 8; i++) {"
16541 " ext_array[i] = 5;"
16543 "for (var i = 0; i < 8; i++) {"
16544 " ext_array[i] = -Infinity;"
16547 CHECK_EQ(0, result->Int32Value());
16548 CheckElementValue(isolate, 0, jsobj, 5);
16550 // Check truncation behavior of integral arrays.
16551 const char* unsigned_data =
16552 "var source_data = [0.6, 10.6];"
16553 "var expected_results = [0, 10];";
16554 const char* signed_data =
16555 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16556 "var expected_results = [0, 10, 0, -10];";
16557 const char* pixel_data =
16558 "var source_data = [0.6, 10.6];"
16559 "var expected_results = [1, 11];";
16561 (array_type == v8::kExternalUint8Array ||
16562 array_type == v8::kExternalUint16Array ||
16563 array_type == v8::kExternalUint32Array);
16564 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16566 i::SNPrintF(test_buf,
16568 "var all_passed = true;"
16569 "for (var i = 0; i < source_data.length; i++) {"
16570 " for (var j = 0; j < 8; j++) {"
16571 " ext_array[j] = source_data[i];"
16573 " all_passed = all_passed &&"
16574 " (ext_array[5] == expected_results[i]);"
16579 (is_pixel_data ? pixel_data : signed_data)));
16580 result = CompileRun(test_buf.start());
16581 CHECK_EQ(true, result->BooleanValue());
16584 i::Handle<ExternalArrayClass> array(
16585 ExternalArrayClass::cast(jsobj->elements()));
16586 for (int i = 0; i < element_count; i++) {
16587 array->set(i, static_cast<ElementType>(i));
16590 // Test complex assignments
16591 result = CompileRun("function ee_op_test_complex_func(sum) {"
16592 " for (var i = 0; i < 40; ++i) {"
16593 " sum += (ext_array[i] += 1);"
16594 " sum += (ext_array[i] -= 1);"
16599 "for (var i=0;i<10000;++i) {"
16600 " sum=ee_op_test_complex_func(sum);"
16603 CHECK_EQ(16000000, result->Int32Value());
16605 // Test count operations
16606 result = CompileRun("function ee_op_test_count_func(sum) {"
16607 " for (var i = 0; i < 40; ++i) {"
16608 " sum += (++ext_array[i]);"
16609 " sum += (--ext_array[i]);"
16614 "for (var i=0;i<10000;++i) {"
16615 " sum=ee_op_test_count_func(sum);"
16618 CHECK_EQ(16000000, result->Int32Value());
16620 result = CompileRun("ext_array[3] = 33;"
16621 "delete ext_array[3];"
16623 CHECK_EQ(33, result->Int32Value());
16625 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16626 "ext_array[2] = 12; ext_array[3] = 13;"
16627 "ext_array.__defineGetter__('2',"
16628 "function() { return 120; });"
16630 CHECK_EQ(12, result->Int32Value());
16632 result = CompileRun("var js_array = new Array(40);"
16633 "js_array[0] = 77;"
16635 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16637 result = CompileRun("ext_array[1] = 23;"
16638 "ext_array.__proto__ = [];"
16639 "js_array.__proto__ = ext_array;"
16640 "js_array.concat(ext_array);");
16641 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16642 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16644 result = CompileRun("ext_array[1] = 23;");
16645 CHECK_EQ(23, result->Int32Value());
16649 template <class FixedTypedArrayClass,
16650 i::ElementsKind elements_kind,
16652 static void FixedTypedArrayTestHelper(
16653 v8::ExternalArrayType array_type,
16655 ElementType high) {
16656 i::FLAG_allow_natives_syntax = true;
16657 LocalContext context;
16658 i::Isolate* isolate = CcTest::i_isolate();
16659 i::Factory* factory = isolate->factory();
16660 v8::HandleScope scope(context->GetIsolate());
16661 const int kElementCount = 260;
16662 i::Handle<FixedTypedArrayClass> fixed_array =
16663 i::Handle<FixedTypedArrayClass>::cast(
16664 factory->NewFixedTypedArray(kElementCount, array_type));
16665 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16666 fixed_array->map()->instance_type());
16667 CHECK_EQ(kElementCount, fixed_array->length());
16668 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16669 for (int i = 0; i < kElementCount; i++) {
16670 fixed_array->set(i, static_cast<ElementType>(i));
16672 // Force GC to trigger verification.
16673 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16674 for (int i = 0; i < kElementCount; i++) {
16675 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16676 static_cast<int64_t>(fixed_array->get_scalar(i)));
16678 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16679 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16680 i::Handle<i::Map> fixed_array_map =
16681 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16682 jsobj->set_map(*fixed_array_map);
16683 jsobj->set_elements(*fixed_array);
16685 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16686 context.local(), obj, kElementCount, array_type,
16687 static_cast<int64_t>(low),
16688 static_cast<int64_t>(high));
16692 THREADED_TEST(FixedUint8Array) {
16693 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16694 v8::kExternalUint8Array,
16699 THREADED_TEST(FixedUint8ClampedArray) {
16700 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16701 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16702 v8::kExternalUint8ClampedArray,
16707 THREADED_TEST(FixedInt8Array) {
16708 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16709 v8::kExternalInt8Array,
16714 THREADED_TEST(FixedUint16Array) {
16715 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16716 v8::kExternalUint16Array,
16721 THREADED_TEST(FixedInt16Array) {
16722 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16723 v8::kExternalInt16Array,
16728 THREADED_TEST(FixedUint32Array) {
16729 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16730 v8::kExternalUint32Array,
16735 THREADED_TEST(FixedInt32Array) {
16736 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16737 v8::kExternalInt32Array,
16742 THREADED_TEST(FixedFloat32Array) {
16743 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16744 v8::kExternalFloat32Array,
16749 THREADED_TEST(FixedFloat64Array) {
16750 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16751 v8::kExternalFloat64Array,
16756 template <class ExternalArrayClass, class ElementType>
16757 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16760 LocalContext context;
16761 i::Isolate* isolate = CcTest::i_isolate();
16762 i::Factory* factory = isolate->factory();
16763 v8::HandleScope scope(context->GetIsolate());
16764 const int kElementCount = 40;
16765 int element_size = ExternalArrayElementSize(array_type);
16766 ElementType* array_data =
16767 static_cast<ElementType*>(malloc(kElementCount * element_size));
16768 i::Handle<ExternalArrayClass> array =
16769 i::Handle<ExternalArrayClass>::cast(
16770 factory->NewExternalArray(kElementCount, array_type, array_data));
16771 // Force GC to trigger verification.
16772 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16773 for (int i = 0; i < kElementCount; i++) {
16774 array->set(i, static_cast<ElementType>(i));
16776 // Force GC to trigger verification.
16777 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16778 for (int i = 0; i < kElementCount; i++) {
16779 CHECK_EQ(static_cast<int64_t>(i),
16780 static_cast<int64_t>(array->get_scalar(i)));
16781 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16784 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16785 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16786 // Set the elements to be the external array.
16787 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16792 i::Object::GetElement(
16793 isolate, jsobj, 1).ToHandleChecked()->Number()));
16795 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16796 context.local(), obj, kElementCount, array_type, low, high);
16798 v8::Handle<v8::Value> result;
16800 // Test more complex manipulations which cause eax to contain values
16801 // that won't be completely overwritten by loads from the arrays.
16802 // This catches bugs in the instructions used for the KeyedLoadIC
16803 // for byte and word types.
16805 const int kXSize = 300;
16806 const int kYSize = 300;
16807 const int kLargeElementCount = kXSize * kYSize * 4;
16808 ElementType* large_array_data =
16809 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16810 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16811 // Set the elements to be the external array.
16812 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16814 kLargeElementCount);
16815 context->Global()->Set(v8_str("large_array"), large_obj);
16816 // Initialize contents of a few rows.
16817 for (int x = 0; x < 300; x++) {
16819 int offset = row * 300 * 4;
16820 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16821 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16822 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16823 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16825 offset = row * 300 * 4;
16826 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16827 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16828 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16829 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16831 offset = row * 300 * 4;
16832 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16833 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16834 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16835 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16837 // The goal of the code below is to make "offset" large enough
16838 // that the computation of the index (which goes into eax) has
16839 // high bits set which will not be overwritten by a byte or short
16841 result = CompileRun("var failed = false;"
16843 "for (var i = 0; i < 300; i++) {"
16844 " if (large_array[4 * i] != 127 ||"
16845 " large_array[4 * i + 1] != 0 ||"
16846 " large_array[4 * i + 2] != 0 ||"
16847 " large_array[4 * i + 3] != 127) {"
16851 "offset = 150 * 300 * 4;"
16852 "for (var i = 0; i < 300; i++) {"
16853 " if (large_array[offset + 4 * i] != 127 ||"
16854 " large_array[offset + 4 * i + 1] != 0 ||"
16855 " large_array[offset + 4 * i + 2] != 0 ||"
16856 " large_array[offset + 4 * i + 3] != 127) {"
16860 "offset = 298 * 300 * 4;"
16861 "for (var i = 0; i < 300; i++) {"
16862 " if (large_array[offset + 4 * i] != 127 ||"
16863 " large_array[offset + 4 * i + 1] != 0 ||"
16864 " large_array[offset + 4 * i + 2] != 0 ||"
16865 " large_array[offset + 4 * i + 3] != 127) {"
16870 CHECK_EQ(true, result->BooleanValue());
16871 free(large_array_data);
16874 // The "" property descriptor is overloaded to store information about
16875 // the external array. Ensure that setting and accessing the "" property
16876 // works (it should overwrite the information cached about the external
16877 // array in the DescriptorArray) in various situations.
16878 result = CompileRun("ext_array[''] = 23; ext_array['']");
16879 CHECK_EQ(23, result->Int32Value());
16881 // Property "" set after the external array is associated with the object.
16883 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16884 obj2->Set(v8_str("ee_test_field"),
16885 v8::Int32::New(context->GetIsolate(), 256));
16886 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16887 // Set the elements to be the external array.
16888 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16891 context->Global()->Set(v8_str("ext_array"), obj2);
16892 result = CompileRun("ext_array['']");
16893 CHECK_EQ(1503, result->Int32Value());
16896 // Property "" set after the external array is associated with the object.
16898 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16899 obj2->Set(v8_str("ee_test_field_2"),
16900 v8::Int32::New(context->GetIsolate(), 256));
16901 // Set the elements to be the external array.
16902 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16905 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16906 context->Global()->Set(v8_str("ext_array"), obj2);
16907 result = CompileRun("ext_array['']");
16908 CHECK_EQ(1503, result->Int32Value());
16911 // Should reuse the map from previous test.
16913 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16914 obj2->Set(v8_str("ee_test_field_2"),
16915 v8::Int32::New(context->GetIsolate(), 256));
16916 // Set the elements to be the external array. Should re-use the map
16917 // from previous test.
16918 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16921 context->Global()->Set(v8_str("ext_array"), obj2);
16922 result = CompileRun("ext_array['']");
16925 // Property "" is a constant function that shouldn't not be interfered with
16926 // when an external array is set.
16928 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16930 obj2->Set(v8_str("ee_test_field3"),
16931 v8::Int32::New(context->GetIsolate(), 256));
16933 // Add a constant function to an object.
16934 context->Global()->Set(v8_str("ext_array"), obj2);
16935 result = CompileRun("ext_array[''] = function() {return 1503;};"
16936 "ext_array['']();");
16938 // Add an external array transition to the same map that
16939 // has the constant transition.
16940 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16941 obj3->Set(v8_str("ee_test_field3"),
16942 v8::Int32::New(context->GetIsolate(), 256));
16943 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16946 context->Global()->Set(v8_str("ext_array"), obj3);
16949 // If a external array transition is in the map, it should get clobbered
16950 // by a constant function.
16952 // Add an external array transition.
16953 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16954 obj3->Set(v8_str("ee_test_field4"),
16955 v8::Int32::New(context->GetIsolate(), 256));
16956 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16960 // Add a constant function to the same map that just got an external array
16962 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16963 obj2->Set(v8_str("ee_test_field4"),
16964 v8::Int32::New(context->GetIsolate(), 256));
16965 context->Global()->Set(v8_str("ext_array"), obj2);
16966 result = CompileRun("ext_array[''] = function() {return 1503;};"
16967 "ext_array['']();");
16974 THREADED_TEST(ExternalInt8Array) {
16975 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16976 v8::kExternalInt8Array,
16982 THREADED_TEST(ExternalUint8Array) {
16983 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16984 v8::kExternalUint8Array,
16990 THREADED_TEST(ExternalUint8ClampedArray) {
16991 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16992 v8::kExternalUint8ClampedArray,
16998 THREADED_TEST(ExternalInt16Array) {
16999 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17000 v8::kExternalInt16Array,
17006 THREADED_TEST(ExternalUint16Array) {
17007 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17008 v8::kExternalUint16Array,
17014 THREADED_TEST(ExternalInt32Array) {
17015 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17016 v8::kExternalInt32Array,
17017 INT_MIN, // -2147483648
17018 INT_MAX); // 2147483647
17022 THREADED_TEST(ExternalUint32Array) {
17023 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17024 v8::kExternalUint32Array,
17026 UINT_MAX); // 4294967295
17030 THREADED_TEST(ExternalFloat32Array) {
17031 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17032 v8::kExternalFloat32Array,
17038 THREADED_TEST(ExternalFloat64Array) {
17039 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17040 v8::kExternalFloat64Array,
17046 THREADED_TEST(ExternalArrays) {
17047 TestExternalInt8Array();
17048 TestExternalUint8Array();
17049 TestExternalInt16Array();
17050 TestExternalUint16Array();
17051 TestExternalInt32Array();
17052 TestExternalUint32Array();
17053 TestExternalFloat32Array();
17057 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17058 LocalContext context;
17059 v8::HandleScope scope(context->GetIsolate());
17060 for (int size = 0; size < 100; size += 10) {
17061 int element_size = ExternalArrayElementSize(array_type);
17062 void* external_data = malloc(size * element_size);
17063 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17064 obj->SetIndexedPropertiesToExternalArrayData(
17065 external_data, array_type, size);
17066 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17067 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17068 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17069 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17070 free(external_data);
17075 THREADED_TEST(ExternalArrayInfo) {
17076 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17077 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17078 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17079 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17080 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17081 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17082 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17083 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17084 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17088 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17089 v8::ExternalArrayType array_type,
17091 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17092 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17093 last_location = last_message = NULL;
17094 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17095 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17096 CHECK_NE(NULL, last_location);
17097 CHECK_NE(NULL, last_message);
17101 TEST(ExternalArrayLimits) {
17102 LocalContext context;
17103 v8::Isolate* isolate = context->GetIsolate();
17104 v8::HandleScope scope(isolate);
17105 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17106 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17107 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17108 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17109 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17110 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17111 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17112 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17113 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17114 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17115 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17116 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17117 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17118 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17119 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17120 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17121 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17122 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17126 template <typename ElementType, typename TypedArray,
17127 class ExternalArrayClass>
17128 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17129 int64_t low, int64_t high) {
17130 const int kElementCount = 50;
17132 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17135 v8::Isolate* isolate = env->GetIsolate();
17136 v8::HandleScope handle_scope(isolate);
17138 Local<v8::ArrayBuffer> ab =
17139 v8::ArrayBuffer::New(isolate, backing_store.start(),
17140 (kElementCount + 2) * sizeof(ElementType));
17141 Local<TypedArray> ta =
17142 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17143 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17144 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17145 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17146 CHECK_EQ(kElementCount*sizeof(ElementType),
17147 static_cast<int>(ta->ByteLength()));
17148 CHECK_EQ(ab, ta->Buffer());
17150 ElementType* data = backing_store.start() + 2;
17151 for (int i = 0; i < kElementCount; i++) {
17152 data[i] = static_cast<ElementType>(i);
17155 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17156 env.local(), ta, kElementCount, array_type, low, high);
17160 THREADED_TEST(Uint8Array) {
17161 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17162 v8::kExternalUint8Array, 0, 0xFF);
17166 THREADED_TEST(Int8Array) {
17167 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17168 v8::kExternalInt8Array, -0x80, 0x7F);
17172 THREADED_TEST(Uint16Array) {
17173 TypedArrayTestHelper<uint16_t,
17175 i::ExternalUint16Array>(
17176 v8::kExternalUint16Array, 0, 0xFFFF);
17180 THREADED_TEST(Int16Array) {
17181 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17182 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17186 THREADED_TEST(Uint32Array) {
17187 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17188 v8::kExternalUint32Array, 0, UINT_MAX);
17192 THREADED_TEST(Int32Array) {
17193 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17194 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17198 THREADED_TEST(Float32Array) {
17199 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17200 v8::kExternalFloat32Array, -500, 500);
17204 THREADED_TEST(Float64Array) {
17205 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17206 v8::kExternalFloat64Array, -500, 500);
17210 THREADED_TEST(Uint8ClampedArray) {
17211 TypedArrayTestHelper<uint8_t,
17212 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17213 v8::kExternalUint8ClampedArray, 0, 0xFF);
17217 THREADED_TEST(DataView) {
17218 const int kSize = 50;
17220 i::ScopedVector<uint8_t> backing_store(kSize+2);
17223 v8::Isolate* isolate = env->GetIsolate();
17224 v8::HandleScope handle_scope(isolate);
17226 Local<v8::ArrayBuffer> ab =
17227 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17228 Local<v8::DataView> dv =
17229 v8::DataView::New(ab, 2, kSize);
17230 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17231 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17232 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17233 CHECK_EQ(ab, dv->Buffer());
17237 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17238 THREADED_TEST(Is##View) { \
17239 LocalContext env; \
17240 v8::Isolate* isolate = env->GetIsolate(); \
17241 v8::HandleScope handle_scope(isolate); \
17243 Handle<Value> result = CompileRun( \
17244 "var ab = new ArrayBuffer(128);" \
17245 "new " #View "(ab)"); \
17246 CHECK(result->IsArrayBufferView()); \
17247 CHECK(result->Is##View()); \
17248 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17251 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17252 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17253 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17254 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17255 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17256 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17257 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17258 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17259 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17260 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17262 #undef IS_ARRAY_BUFFER_VIEW_TEST
17266 THREADED_TEST(ScriptContextDependence) {
17268 v8::HandleScope scope(c1->GetIsolate());
17269 const char *source = "foo";
17270 v8::Handle<v8::Script> dep = v8_compile(source);
17271 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17272 c1->GetIsolate(), source));
17273 v8::Handle<v8::UnboundScript> indep =
17274 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17275 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17276 v8::Integer::New(c1->GetIsolate(), 100));
17277 CHECK_EQ(dep->Run()->Int32Value(), 100);
17278 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17280 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17281 v8::Integer::New(c2->GetIsolate(), 101));
17282 CHECK_EQ(dep->Run()->Int32Value(), 100);
17283 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17287 THREADED_TEST(StackTrace) {
17288 LocalContext context;
17289 v8::HandleScope scope(context->GetIsolate());
17290 v8::TryCatch try_catch;
17291 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17292 v8::Handle<v8::String> src =
17293 v8::String::NewFromUtf8(context->GetIsolate(), source);
17294 v8::Handle<v8::String> origin =
17295 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17296 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17297 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17298 ->BindToCurrentContext()
17300 CHECK(try_catch.HasCaught());
17301 v8::String::Utf8Value stack(try_catch.StackTrace());
17302 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17306 // Checks that a StackFrame has certain expected values.
17307 void checkStackFrame(const char* expected_script_name,
17308 const char* expected_func_name, int expected_line_number,
17309 int expected_column, bool is_eval, bool is_constructor,
17310 v8::Handle<v8::StackFrame> frame) {
17311 v8::HandleScope scope(CcTest::isolate());
17312 v8::String::Utf8Value func_name(frame->GetFunctionName());
17313 v8::String::Utf8Value script_name(frame->GetScriptName());
17314 if (*script_name == NULL) {
17315 // The situation where there is no associated script, like for evals.
17316 CHECK(expected_script_name == NULL);
17318 CHECK(strstr(*script_name, expected_script_name) != NULL);
17320 CHECK(strstr(*func_name, expected_func_name) != NULL);
17321 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17322 CHECK_EQ(expected_column, frame->GetColumn());
17323 CHECK_EQ(is_eval, frame->IsEval());
17324 CHECK_EQ(is_constructor, frame->IsConstructor());
17328 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17329 v8::HandleScope scope(args.GetIsolate());
17330 const char* origin = "capture-stack-trace-test";
17331 const int kOverviewTest = 1;
17332 const int kDetailedTest = 2;
17334 DCHECK(args.Length() == 1);
17336 int testGroup = args[0]->Int32Value();
17337 if (testGroup == kOverviewTest) {
17338 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17339 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17340 CHECK_EQ(4, stackTrace->GetFrameCount());
17341 checkStackFrame(origin, "bar", 2, 10, false, false,
17342 stackTrace->GetFrame(0));
17343 checkStackFrame(origin, "foo", 6, 3, false, false,
17344 stackTrace->GetFrame(1));
17345 // This is the source string inside the eval which has the call to foo.
17346 checkStackFrame(NULL, "", 1, 5, false, false,
17347 stackTrace->GetFrame(2));
17348 // The last frame is an anonymous function which has the initial eval call.
17349 checkStackFrame(origin, "", 8, 7, false, false,
17350 stackTrace->GetFrame(3));
17352 CHECK(stackTrace->AsArray()->IsArray());
17353 } else if (testGroup == kDetailedTest) {
17354 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17355 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17356 CHECK_EQ(4, stackTrace->GetFrameCount());
17357 checkStackFrame(origin, "bat", 4, 22, false, false,
17358 stackTrace->GetFrame(0));
17359 checkStackFrame(origin, "baz", 8, 3, false, true,
17360 stackTrace->GetFrame(1));
17361 bool is_eval = true;
17362 // This is the source string inside the eval which has the call to baz.
17363 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17364 stackTrace->GetFrame(2));
17365 // The last frame is an anonymous function which has the initial eval call.
17366 checkStackFrame(origin, "", 10, 1, false, false,
17367 stackTrace->GetFrame(3));
17369 CHECK(stackTrace->AsArray()->IsArray());
17374 // Tests the C++ StackTrace API.
17375 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17376 // THREADED_TEST(CaptureStackTrace) {
17377 TEST(CaptureStackTrace) {
17378 v8::Isolate* isolate = CcTest::isolate();
17379 v8::HandleScope scope(isolate);
17380 v8::Handle<v8::String> origin =
17381 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17382 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17383 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17384 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17385 LocalContext context(0, templ);
17387 // Test getting OVERVIEW information. Should ignore information that is not
17388 // script name, function name, line number, and column offset.
17389 const char *overview_source =
17390 "function bar() {\n"
17391 " var y; AnalyzeStackInNativeCode(1);\n"
17393 "function foo() {\n"
17397 "var x;eval('new foo();');";
17398 v8::Handle<v8::String> overview_src =
17399 v8::String::NewFromUtf8(isolate, overview_source);
17400 v8::ScriptCompiler::Source script_source(overview_src,
17401 v8::ScriptOrigin(origin));
17402 v8::Handle<Value> overview_result(
17403 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17404 ->BindToCurrentContext()
17406 CHECK(!overview_result.IsEmpty());
17407 CHECK(overview_result->IsObject());
17409 // Test getting DETAILED information.
17410 const char *detailed_source =
17411 "function bat() {AnalyzeStackInNativeCode(2);\n"
17414 "function baz() {\n"
17417 "eval('new baz();');";
17418 v8::Handle<v8::String> detailed_src =
17419 v8::String::NewFromUtf8(isolate, detailed_source);
17420 // Make the script using a non-zero line and column offset.
17421 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17422 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17423 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17424 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17425 v8::Handle<v8::UnboundScript> detailed_script(
17426 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17427 v8::Handle<Value> detailed_result(
17428 detailed_script->BindToCurrentContext()->Run());
17429 CHECK(!detailed_result.IsEmpty());
17430 CHECK(detailed_result->IsObject());
17434 static void StackTraceForUncaughtExceptionListener(
17435 v8::Handle<v8::Message> message,
17436 v8::Handle<Value>) {
17437 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17438 CHECK_EQ(2, stack_trace->GetFrameCount());
17439 checkStackFrame("origin", "foo", 2, 3, false, false,
17440 stack_trace->GetFrame(0));
17441 checkStackFrame("origin", "bar", 5, 3, false, false,
17442 stack_trace->GetFrame(1));
17446 TEST(CaptureStackTraceForUncaughtException) {
17449 v8::HandleScope scope(env->GetIsolate());
17450 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17451 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17453 CompileRunWithOrigin(
17454 "function foo() {\n"
17457 "function bar() {\n"
17461 v8::Local<v8::Object> global = env->Global();
17462 Local<Value> trouble = global->Get(v8_str("bar"));
17463 CHECK(trouble->IsFunction());
17464 Function::Cast(*trouble)->Call(global, 0, NULL);
17465 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17466 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17470 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17472 v8::HandleScope scope(env->GetIsolate());
17473 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17475 v8::StackTrace::kDetailed);
17478 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17479 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17480 " 'isConstructor'];\n"
17481 "for (var i = 0; i < setters.length; i++) {\n"
17482 " var prop = setters[i];\n"
17483 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17485 CompileRun("throw 'exception';");
17486 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17490 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17491 v8::Handle<v8::Value> data) {
17492 // Use the frame where JavaScript is called from.
17493 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17494 CHECK(!stack_trace.IsEmpty());
17495 int frame_count = stack_trace->GetFrameCount();
17496 CHECK_EQ(3, frame_count);
17497 int line_number[] = {1, 2, 5};
17498 for (int i = 0; i < frame_count; i++) {
17499 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17504 // Test that we only return the stack trace at the site where the exception
17505 // is first thrown (not where it is rethrown).
17506 TEST(RethrowStackTrace) {
17508 v8::HandleScope scope(env->GetIsolate());
17509 // We make sure that
17510 // - the stack trace of the ReferenceError in g() is reported.
17511 // - the stack trace is not overwritten when e1 is rethrown by t().
17512 // - the stack trace of e2 does not overwrite that of e1.
17513 const char* source =
17514 "function g() { error; } \n"
17515 "function f() { g(); } \n"
17516 "function t(e) { throw e; } \n"
17519 "} catch (e1) { \n"
17522 " } catch (e2) { \n"
17526 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17527 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17528 CompileRun(source);
17529 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17530 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17534 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17535 v8::Handle<v8::Value> data) {
17536 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17537 CHECK(!stack_trace.IsEmpty());
17538 int frame_count = stack_trace->GetFrameCount();
17539 CHECK_EQ(2, frame_count);
17540 int line_number[] = {3, 7};
17541 for (int i = 0; i < frame_count; i++) {
17542 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17547 // Test that we do not recognize identity for primitive exceptions.
17548 TEST(RethrowPrimitiveStackTrace) {
17550 v8::HandleScope scope(env->GetIsolate());
17551 // We do not capture stack trace for non Error objects on creation time.
17552 // Instead, we capture the stack trace on last throw.
17553 const char* source =
17554 "function g() { throw 404; } \n"
17555 "function f() { g(); } \n"
17556 "function t(e) { throw e; } \n"
17559 "} catch (e1) { \n"
17562 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17563 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17564 CompileRun(source);
17565 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17566 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17570 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17571 v8::Handle<v8::Value> data) {
17572 // Use the frame where JavaScript is called from.
17573 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17574 CHECK(!stack_trace.IsEmpty());
17575 CHECK_EQ(1, stack_trace->GetFrameCount());
17576 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17580 // Test that the stack trace is captured when the error object is created and
17581 // not where it is thrown.
17582 TEST(RethrowExistingStackTrace) {
17584 v8::HandleScope scope(env->GetIsolate());
17585 const char* source =
17586 "var e = new Error(); \n"
17588 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17589 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17590 CompileRun(source);
17591 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17592 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17596 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17597 v8::Handle<v8::Value> data) {
17598 // Use the frame where JavaScript is called from.
17599 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17600 CHECK(!stack_trace.IsEmpty());
17601 CHECK_EQ(1, stack_trace->GetFrameCount());
17602 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17606 // Test that the stack trace is captured where the bogus Error object is thrown.
17607 TEST(RethrowBogusErrorStackTrace) {
17609 v8::HandleScope scope(env->GetIsolate());
17610 const char* source =
17611 "var e = {__proto__: new Error()} \n"
17613 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17614 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17615 CompileRun(source);
17616 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17617 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17621 void AnalyzeStackOfEvalWithSourceURL(
17622 const v8::FunctionCallbackInfo<v8::Value>& args) {
17623 v8::HandleScope scope(args.GetIsolate());
17624 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17625 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17626 CHECK_EQ(5, stackTrace->GetFrameCount());
17627 v8::Handle<v8::String> url = v8_str("eval_url");
17628 for (int i = 0; i < 3; i++) {
17629 v8::Handle<v8::String> name =
17630 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17631 CHECK(!name.IsEmpty());
17632 CHECK_EQ(url, name);
17637 TEST(SourceURLInStackTrace) {
17638 v8::Isolate* isolate = CcTest::isolate();
17639 v8::HandleScope scope(isolate);
17640 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17641 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17642 v8::FunctionTemplate::New(isolate,
17643 AnalyzeStackOfEvalWithSourceURL));
17644 LocalContext context(0, templ);
17646 const char *source =
17647 "function outer() {\n"
17648 "function bar() {\n"
17649 " AnalyzeStackOfEvalWithSourceURL();\n"
17651 "function foo() {\n"
17657 "eval('(' + outer +')()%s');";
17659 i::ScopedVector<char> code(1024);
17660 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17661 CHECK(CompileRun(code.start())->IsUndefined());
17662 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17663 CHECK(CompileRun(code.start())->IsUndefined());
17667 static int scriptIdInStack[2];
17669 void AnalyzeScriptIdInStack(
17670 const v8::FunctionCallbackInfo<v8::Value>& args) {
17671 v8::HandleScope scope(args.GetIsolate());
17672 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17673 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17674 CHECK_EQ(2, stackTrace->GetFrameCount());
17675 for (int i = 0; i < 2; i++) {
17676 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17681 TEST(ScriptIdInStackTrace) {
17682 v8::Isolate* isolate = CcTest::isolate();
17683 v8::HandleScope scope(isolate);
17684 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17685 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17686 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17687 LocalContext context(0, templ);
17689 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17691 "function foo() {\n"
17692 " AnalyzeScriptIdInStack();"
17695 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17697 for (int i = 0; i < 2; i++) {
17698 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17699 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17704 void AnalyzeStackOfInlineScriptWithSourceURL(
17705 const v8::FunctionCallbackInfo<v8::Value>& args) {
17706 v8::HandleScope scope(args.GetIsolate());
17707 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17708 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17709 CHECK_EQ(4, stackTrace->GetFrameCount());
17710 v8::Handle<v8::String> url = v8_str("url");
17711 for (int i = 0; i < 3; i++) {
17712 v8::Handle<v8::String> name =
17713 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17714 CHECK(!name.IsEmpty());
17715 CHECK_EQ(url, name);
17720 TEST(InlineScriptWithSourceURLInStackTrace) {
17721 v8::Isolate* isolate = CcTest::isolate();
17722 v8::HandleScope scope(isolate);
17723 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17724 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17725 v8::FunctionTemplate::New(
17726 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17727 LocalContext context(0, templ);
17729 const char *source =
17730 "function outer() {\n"
17731 "function bar() {\n"
17732 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17734 "function foo() {\n"
17742 i::ScopedVector<char> code(1024);
17743 i::SNPrintF(code, source, "//# sourceURL=source_url");
17744 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17745 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17746 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17750 void AnalyzeStackOfDynamicScriptWithSourceURL(
17751 const v8::FunctionCallbackInfo<v8::Value>& args) {
17752 v8::HandleScope scope(args.GetIsolate());
17753 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17754 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17755 CHECK_EQ(4, stackTrace->GetFrameCount());
17756 v8::Handle<v8::String> url = v8_str("source_url");
17757 for (int i = 0; i < 3; i++) {
17758 v8::Handle<v8::String> name =
17759 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17760 CHECK(!name.IsEmpty());
17761 CHECK_EQ(url, name);
17766 TEST(DynamicWithSourceURLInStackTrace) {
17767 v8::Isolate* isolate = CcTest::isolate();
17768 v8::HandleScope scope(isolate);
17769 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17770 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17771 v8::FunctionTemplate::New(
17772 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17773 LocalContext context(0, templ);
17775 const char *source =
17776 "function outer() {\n"
17777 "function bar() {\n"
17778 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17780 "function foo() {\n"
17788 i::ScopedVector<char> code(1024);
17789 i::SNPrintF(code, source, "//# sourceURL=source_url");
17790 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17791 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17792 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17796 TEST(DynamicWithSourceURLInStackTraceString) {
17797 LocalContext context;
17798 v8::HandleScope scope(context->GetIsolate());
17800 const char *source =
17801 "function outer() {\n"
17802 " function foo() {\n"
17809 i::ScopedVector<char> code(1024);
17810 i::SNPrintF(code, source, "//# sourceURL=source_url");
17811 v8::TryCatch try_catch;
17812 CompileRunWithOrigin(code.start(), "", 0, 0);
17813 CHECK(try_catch.HasCaught());
17814 v8::String::Utf8Value stack(try_catch.StackTrace());
17815 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17819 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17820 LocalContext context;
17821 v8::HandleScope scope(context->GetIsolate());
17823 const char *source =
17824 "function outer() {\n"
17825 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17826 " //# sourceURL=source_url\";\n"
17827 " eval(scriptContents);\n"
17830 "//# sourceURL=outer_url";
17832 v8::TryCatch try_catch;
17833 CompileRun(source);
17834 CHECK(try_catch.HasCaught());
17836 Local<v8::Message> message = try_catch.Message();
17837 Handle<Value> sourceURL =
17838 message->GetScriptOrigin().ResourceName();
17839 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17843 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17844 LocalContext context;
17845 v8::HandleScope scope(context->GetIsolate());
17847 const char *source =
17848 "function outer() {\n"
17849 " var scriptContents = \"function boo(){ boo(); }\\\n"
17850 " //# sourceURL=source_url\";\n"
17851 " eval(scriptContents);\n"
17854 "//# sourceURL=outer_url";
17856 v8::TryCatch try_catch;
17857 CompileRun(source);
17858 CHECK(try_catch.HasCaught());
17860 Local<v8::Message> message = try_catch.Message();
17861 Handle<Value> sourceURL =
17862 message->GetScriptOrigin().ResourceName();
17863 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17867 static void CreateGarbageInOldSpace() {
17868 i::Factory* factory = CcTest::i_isolate()->factory();
17869 v8::HandleScope scope(CcTest::isolate());
17870 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17871 for (int i = 0; i < 1000; i++) {
17872 factory->NewFixedArray(1000, i::TENURED);
17877 // Test that idle notification can be handled and eventually returns true.
17878 TEST(IdleNotification) {
17879 const intptr_t MB = 1024 * 1024;
17880 const int IdlePauseInMs = 1000;
17882 v8::HandleScope scope(env->GetIsolate());
17883 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17884 CreateGarbageInOldSpace();
17885 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17886 CHECK_GT(size_with_garbage, initial_size + MB);
17887 bool finished = false;
17888 for (int i = 0; i < 200 && !finished; i++) {
17889 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17891 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17893 CHECK_LT(final_size, initial_size + 1);
17897 // Test that idle notification can be handled and eventually collects garbage.
17898 TEST(IdleNotificationWithSmallHint) {
17899 const intptr_t MB = 1024 * 1024;
17900 const int IdlePauseInMs = 900;
17902 v8::HandleScope scope(env->GetIsolate());
17903 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17904 CreateGarbageInOldSpace();
17905 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17906 CHECK_GT(size_with_garbage, initial_size + MB);
17907 bool finished = false;
17908 for (int i = 0; i < 200 && !finished; i++) {
17909 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17911 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17913 CHECK_LT(final_size, initial_size + 1);
17917 // Test that idle notification can be handled and eventually collects garbage.
17918 TEST(IdleNotificationWithLargeHint) {
17919 const intptr_t MB = 1024 * 1024;
17920 const int IdlePauseInMs = 900;
17922 v8::HandleScope scope(env->GetIsolate());
17923 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17924 CreateGarbageInOldSpace();
17925 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17926 CHECK_GT(size_with_garbage, initial_size + MB);
17927 bool finished = false;
17928 for (int i = 0; i < 200 && !finished; i++) {
17929 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17931 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17933 CHECK_LT(final_size, initial_size + 1);
17937 TEST(Regress2107) {
17938 const intptr_t MB = 1024 * 1024;
17939 const int kIdlePauseInMs = 1000;
17941 v8::Isolate* isolate = env->GetIsolate();
17942 v8::HandleScope scope(env->GetIsolate());
17943 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17944 // Send idle notification to start a round of incremental GCs.
17945 env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17946 // Emulate 7 page reloads.
17947 for (int i = 0; i < 7; i++) {
17949 v8::HandleScope inner_scope(env->GetIsolate());
17950 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17952 CreateGarbageInOldSpace();
17955 env->GetIsolate()->ContextDisposedNotification();
17956 env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17958 // Create garbage and check that idle notification still collects it.
17959 CreateGarbageInOldSpace();
17960 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17961 CHECK_GT(size_with_garbage, initial_size + MB);
17962 bool finished = false;
17963 for (int i = 0; i < 200 && !finished; i++) {
17964 finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17966 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17967 CHECK_LT(final_size, initial_size + 1);
17971 TEST(Regress2333) {
17973 for (int i = 0; i < 3; i++) {
17974 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17978 static uint32_t* stack_limit;
17980 static void GetStackLimitCallback(
17981 const v8::FunctionCallbackInfo<v8::Value>& args) {
17982 stack_limit = reinterpret_cast<uint32_t*>(
17983 CcTest::i_isolate()->stack_guard()->real_climit());
17987 // Uses the address of a local variable to determine the stack top now.
17988 // Given a size, returns an address that is that far from the current
17990 static uint32_t* ComputeStackLimit(uint32_t size) {
17991 uint32_t* answer = &size - (size / sizeof(size));
17992 // If the size is very large and the stack is very near the bottom of
17993 // memory then the calculation above may wrap around and give an address
17994 // that is above the (downwards-growing) stack. In that case we return
17995 // a very low address.
17996 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18001 // We need at least 165kB for an x64 debug build with clang and ASAN.
18002 static const int stack_breathing_room = 256 * i::KB;
18005 TEST(SetStackLimit) {
18006 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18008 // Set stack limit.
18009 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18011 // Execute a script.
18013 v8::HandleScope scope(env->GetIsolate());
18014 Local<v8::FunctionTemplate> fun_templ =
18015 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18016 Local<Function> fun = fun_templ->GetFunction();
18017 env->Global()->Set(v8_str("get_stack_limit"), fun);
18018 CompileRun("get_stack_limit();");
18020 CHECK(stack_limit == set_limit);
18024 TEST(SetStackLimitInThread) {
18025 uint32_t* set_limit;
18027 v8::Locker locker(CcTest::isolate());
18028 set_limit = ComputeStackLimit(stack_breathing_room);
18030 // Set stack limit.
18031 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18033 // Execute a script.
18034 v8::HandleScope scope(CcTest::isolate());
18036 Local<v8::FunctionTemplate> fun_templ =
18037 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18038 Local<Function> fun = fun_templ->GetFunction();
18039 env->Global()->Set(v8_str("get_stack_limit"), fun);
18040 CompileRun("get_stack_limit();");
18042 CHECK(stack_limit == set_limit);
18045 v8::Locker locker(CcTest::isolate());
18046 CHECK(stack_limit == set_limit);
18051 THREADED_TEST(GetHeapStatistics) {
18053 v8::HandleScope scope(c1->GetIsolate());
18054 v8::HeapStatistics heap_statistics;
18055 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
18056 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
18057 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18058 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18059 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18063 class VisitorImpl : public v8::ExternalResourceVisitor {
18065 explicit VisitorImpl(TestResource** resource) {
18066 for (int i = 0; i < 4; i++) {
18067 resource_[i] = resource[i];
18068 found_resource_[i] = false;
18071 virtual ~VisitorImpl() {}
18072 virtual void VisitExternalString(v8::Handle<v8::String> string) {
18073 if (!string->IsExternal()) {
18074 CHECK(string->IsExternalOneByte());
18077 v8::String::ExternalStringResource* resource =
18078 string->GetExternalStringResource();
18080 for (int i = 0; i < 4; i++) {
18081 if (resource_[i] == resource) {
18082 CHECK(!found_resource_[i]);
18083 found_resource_[i] = true;
18087 void CheckVisitedResources() {
18088 for (int i = 0; i < 4; i++) {
18089 CHECK(found_resource_[i]);
18094 v8::String::ExternalStringResource* resource_[4];
18095 bool found_resource_[4];
18099 TEST(ExternalizeOldSpaceTwoByteCons) {
18101 v8::HandleScope scope(env->GetIsolate());
18102 v8::Local<v8::String> cons =
18103 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18104 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18105 CcTest::heap()->CollectAllAvailableGarbage();
18106 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18107 *v8::Utils::OpenHandle(*cons)));
18109 TestResource* resource = new TestResource(
18110 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18111 cons->MakeExternal(resource);
18113 CHECK(cons->IsExternal());
18114 CHECK_EQ(resource, cons->GetExternalStringResource());
18115 String::Encoding encoding;
18116 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18117 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18121 TEST(ExternalizeOldSpaceOneByteCons) {
18123 v8::HandleScope scope(env->GetIsolate());
18124 v8::Local<v8::String> cons =
18125 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18126 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18127 CcTest::heap()->CollectAllAvailableGarbage();
18128 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18129 *v8::Utils::OpenHandle(*cons)));
18131 TestOneByteResource* resource =
18132 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18133 cons->MakeExternal(resource);
18135 CHECK(cons->IsExternalOneByte());
18136 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18137 String::Encoding encoding;
18138 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18139 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18143 TEST(VisitExternalStrings) {
18145 v8::HandleScope scope(env->GetIsolate());
18146 const char* string = "Some string";
18147 uint16_t* two_byte_string = AsciiToTwoByteString(string);
18148 TestResource* resource[4];
18149 resource[0] = new TestResource(two_byte_string);
18150 v8::Local<v8::String> string0 =
18151 v8::String::NewExternal(env->GetIsolate(), resource[0]);
18152 resource[1] = new TestResource(two_byte_string, NULL, false);
18153 v8::Local<v8::String> string1 =
18154 v8::String::NewExternal(env->GetIsolate(), resource[1]);
18156 // Externalized symbol.
18157 resource[2] = new TestResource(two_byte_string, NULL, false);
18158 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18159 env->GetIsolate(), string, v8::String::kInternalizedString);
18160 CHECK(string2->MakeExternal(resource[2]));
18162 // Symbolized External.
18163 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18164 v8::Local<v8::String> string3 =
18165 v8::String::NewExternal(env->GetIsolate(), resource[3]);
18166 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
18167 // Turn into a symbol.
18168 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18169 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18170 string3_i).is_null());
18171 CHECK(string3_i->IsInternalizedString());
18173 // We need to add usages for string* to avoid warnings in GCC 4.7
18174 CHECK(string0->IsExternal());
18175 CHECK(string1->IsExternal());
18176 CHECK(string2->IsExternal());
18177 CHECK(string3->IsExternal());
18179 VisitorImpl visitor(resource);
18180 v8::V8::VisitExternalResources(&visitor);
18181 visitor.CheckVisitedResources();
18185 TEST(ExternalStringCollectedAtTearDown) {
18187 v8::Isolate* isolate = v8::Isolate::New();
18188 { v8::Isolate::Scope isolate_scope(isolate);
18189 v8::HandleScope handle_scope(isolate);
18190 const char* s = "One string to test them all, one string to find them.";
18191 TestOneByteResource* inscription =
18192 new TestOneByteResource(i::StrDup(s), &destroyed);
18193 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18194 // Ring is still alive. Orcs are roaming freely across our lands.
18195 CHECK_EQ(0, destroyed);
18199 isolate->Dispose();
18200 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18201 CHECK_EQ(1, destroyed);
18205 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18207 v8::Isolate* isolate = v8::Isolate::New();
18208 { v8::Isolate::Scope isolate_scope(isolate);
18209 LocalContext env(isolate);
18210 v8::HandleScope handle_scope(isolate);
18211 CompileRun("var ring = 'One string to test them all';");
18212 const char* s = "One string to test them all";
18213 TestOneByteResource* inscription =
18214 new TestOneByteResource(i::StrDup(s), &destroyed);
18215 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18216 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18217 ring->MakeExternal(inscription);
18218 // Ring is still alive. Orcs are roaming freely across our lands.
18219 CHECK_EQ(0, destroyed);
18223 isolate->Dispose();
18224 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18225 CHECK_EQ(1, destroyed);
18229 TEST(ExternalInternalizedStringCollectedAtGC) {
18231 { LocalContext env;
18232 v8::HandleScope handle_scope(env->GetIsolate());
18233 CompileRun("var ring = 'One string to test them all';");
18234 const char* s = "One string to test them all";
18235 TestOneByteResource* inscription =
18236 new TestOneByteResource(i::StrDup(s), &destroyed);
18237 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18238 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18239 ring->MakeExternal(inscription);
18240 // Ring is still alive. Orcs are roaming freely across our lands.
18241 CHECK_EQ(0, destroyed);
18245 // Garbage collector deals swift blows to evil.
18246 CcTest::i_isolate()->compilation_cache()->Clear();
18247 CcTest::heap()->CollectAllAvailableGarbage();
18249 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18250 CHECK_EQ(1, destroyed);
18254 static double DoubleFromBits(uint64_t value) {
18256 i::MemCopy(&target, &value, sizeof(target));
18261 static uint64_t DoubleToBits(double value) {
18263 i::MemCopy(&target, &value, sizeof(target));
18268 static double DoubleToDateTime(double input) {
18269 double date_limit = 864e13;
18270 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18271 return v8::base::OS::nan_value();
18273 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18277 // We don't have a consistent way to write 64-bit constants syntactically, so we
18278 // split them into two 32-bit constants and combine them programmatically.
18279 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18280 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18284 THREADED_TEST(QuietSignalingNaNs) {
18285 LocalContext context;
18286 v8::Isolate* isolate = context->GetIsolate();
18287 v8::HandleScope scope(isolate);
18288 v8::TryCatch try_catch;
18290 // Special double values.
18291 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18292 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18293 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18294 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18295 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18296 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18297 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18299 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18300 // on either side of the epoch.
18301 double date_limit = 864e13;
18303 double test_values[] = {
18325 int num_test_values = 20;
18327 for (int i = 0; i < num_test_values; i++) {
18328 double test_value = test_values[i];
18330 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18331 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18332 double stored_number = number->NumberValue();
18333 if (!std::isnan(test_value)) {
18334 CHECK_EQ(test_value, stored_number);
18336 uint64_t stored_bits = DoubleToBits(stored_number);
18337 // Check if quiet nan (bits 51..62 all set).
18338 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18339 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18340 // Most significant fraction bit for quiet nan is set to 0
18341 // on MIPS architecture. Allowed by IEEE-754.
18342 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18344 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18348 // Check that Date::New preserves non-NaNs in the date range and
18350 v8::Handle<v8::Value> date =
18351 v8::Date::New(isolate, test_value);
18352 double expected_stored_date = DoubleToDateTime(test_value);
18353 double stored_date = date->NumberValue();
18354 if (!std::isnan(expected_stored_date)) {
18355 CHECK_EQ(expected_stored_date, stored_date);
18357 uint64_t stored_bits = DoubleToBits(stored_date);
18358 // Check if quiet nan (bits 51..62 all set).
18359 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18360 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18361 // Most significant fraction bit for quiet nan is set to 0
18362 // on MIPS architecture. Allowed by IEEE-754.
18363 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18365 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18372 static void SpaghettiIncident(
18373 const v8::FunctionCallbackInfo<v8::Value>& args) {
18374 v8::HandleScope scope(args.GetIsolate());
18376 v8::Handle<v8::String> str(args[0]->ToString());
18378 if (tc.HasCaught())
18383 // Test that an exception can be propagated down through a spaghetti
18384 // stack using ReThrow.
18385 THREADED_TEST(SpaghettiStackReThrow) {
18386 v8::Isolate* isolate = CcTest::isolate();
18387 v8::HandleScope scope(isolate);
18388 LocalContext context;
18389 context->Global()->Set(
18390 v8::String::NewFromUtf8(isolate, "s"),
18391 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18392 v8::TryCatch try_catch;
18396 " toString: function () {"
18406 CHECK(try_catch.HasCaught());
18407 v8::String::Utf8Value value(try_catch.Exception());
18408 CHECK_EQ(0, strcmp(*value, "Hey!"));
18413 v8::V8::Initialize();
18414 v8::Isolate* isolate = CcTest::isolate();
18415 v8::HandleScope scope(isolate);
18416 v8::Local<Context> other_context;
18419 // Create a context used to keep the code from aging in the compilation
18421 other_context = Context::New(isolate);
18423 // Context-dependent context data creates reference from the compilation
18424 // cache to the global object.
18425 const char* source_simple = "1";
18427 v8::HandleScope scope(isolate);
18428 v8::Local<Context> context = Context::New(isolate);
18431 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18432 context->SetEmbedderData(0, obj);
18433 CompileRun(source_simple);
18436 isolate->ContextDisposedNotification();
18437 for (gc_count = 1; gc_count < 10; gc_count++) {
18438 other_context->Enter();
18439 CompileRun(source_simple);
18440 other_context->Exit();
18441 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18442 if (GetGlobalObjectsCount() == 1) break;
18444 CHECK_GE(2, gc_count);
18445 CHECK_EQ(1, GetGlobalObjectsCount());
18447 // Eval in a function creates reference from the compilation cache to the
18449 const char* source_eval = "function f(){eval('1')}; f()";
18451 v8::HandleScope scope(isolate);
18452 v8::Local<Context> context = Context::New(isolate);
18455 CompileRun(source_eval);
18458 isolate->ContextDisposedNotification();
18459 for (gc_count = 1; gc_count < 10; gc_count++) {
18460 other_context->Enter();
18461 CompileRun(source_eval);
18462 other_context->Exit();
18463 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18464 if (GetGlobalObjectsCount() == 1) break;
18466 CHECK_GE(2, gc_count);
18467 CHECK_EQ(1, GetGlobalObjectsCount());
18469 // Looking up the line number for an exception creates reference from the
18470 // compilation cache to the global object.
18471 const char* source_exception = "function f(){throw 1;} f()";
18473 v8::HandleScope scope(isolate);
18474 v8::Local<Context> context = Context::New(isolate);
18477 v8::TryCatch try_catch;
18478 CompileRun(source_exception);
18479 CHECK(try_catch.HasCaught());
18480 v8::Handle<v8::Message> message = try_catch.Message();
18481 CHECK(!message.IsEmpty());
18482 CHECK_EQ(1, message->GetLineNumber());
18485 isolate->ContextDisposedNotification();
18486 for (gc_count = 1; gc_count < 10; gc_count++) {
18487 other_context->Enter();
18488 CompileRun(source_exception);
18489 other_context->Exit();
18490 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18491 if (GetGlobalObjectsCount() == 1) break;
18493 CHECK_GE(2, gc_count);
18494 CHECK_EQ(1, GetGlobalObjectsCount());
18496 isolate->ContextDisposedNotification();
18500 THREADED_TEST(ScriptOrigin) {
18502 v8::HandleScope scope(env->GetIsolate());
18503 v8::ScriptOrigin origin =
18504 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18505 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18506 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18507 v8::Script::Compile(script, &origin)->Run();
18508 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18509 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18510 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18511 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18513 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18514 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18515 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18517 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18518 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18519 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18523 THREADED_TEST(FunctionGetInferredName) {
18525 v8::HandleScope scope(env->GetIsolate());
18526 v8::ScriptOrigin origin =
18527 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18528 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18530 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18531 v8::Script::Compile(script, &origin)->Run();
18532 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18533 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18534 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18538 THREADED_TEST(FunctionGetDisplayName) {
18540 v8::HandleScope scope(env->GetIsolate());
18541 const char* code = "var error = false;"
18542 "function a() { this.x = 1; };"
18543 "a.displayName = 'display_a';"
18544 "var b = (function() {"
18545 " var f = function() { this.x = 2; };"
18546 " f.displayName = 'display_b';"
18549 "var c = function() {};"
18550 "c.__defineGetter__('displayName', function() {"
18552 " throw new Error();"
18555 "d.__defineGetter__('displayName', function() {"
18557 " return 'wrong_display_name';"
18560 "e.displayName = 'wrong_display_name';"
18561 "e.__defineSetter__('displayName', function() {"
18563 " throw new Error();"
18566 "f.displayName = { 'foo': 6, toString: function() {"
18568 " return 'wrong_display_name';"
18570 "var g = function() {"
18571 " arguments.callee.displayName = 'set_in_runtime';"
18574 v8::ScriptOrigin origin =
18575 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18576 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18578 v8::Local<v8::Value> error =
18579 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18580 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18581 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18582 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18583 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18584 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18585 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18586 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18587 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18588 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18589 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18590 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18591 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18592 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18593 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18594 CHECK_EQ(false, error->BooleanValue());
18595 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18596 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18597 CHECK(c->GetDisplayName()->IsUndefined());
18598 CHECK(d->GetDisplayName()->IsUndefined());
18599 CHECK(e->GetDisplayName()->IsUndefined());
18600 CHECK(f->GetDisplayName()->IsUndefined());
18601 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18605 THREADED_TEST(ScriptLineNumber) {
18607 v8::HandleScope scope(env->GetIsolate());
18608 v8::ScriptOrigin origin =
18609 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18610 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18611 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18612 v8::Script::Compile(script, &origin)->Run();
18613 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18614 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18615 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18616 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18617 CHECK_EQ(0, f->GetScriptLineNumber());
18618 CHECK_EQ(2, g->GetScriptLineNumber());
18622 THREADED_TEST(ScriptColumnNumber) {
18624 v8::Isolate* isolate = env->GetIsolate();
18625 v8::HandleScope scope(isolate);
18626 v8::ScriptOrigin origin =
18627 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18628 v8::Integer::New(isolate, 3),
18629 v8::Integer::New(isolate, 2));
18630 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18631 isolate, "function foo() {}\n\n function bar() {}");
18632 v8::Script::Compile(script, &origin)->Run();
18633 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18634 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18635 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18636 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18637 CHECK_EQ(14, foo->GetScriptColumnNumber());
18638 CHECK_EQ(17, bar->GetScriptColumnNumber());
18642 THREADED_TEST(FunctionIsBuiltin) {
18644 v8::Isolate* isolate = env->GetIsolate();
18645 v8::HandleScope scope(isolate);
18646 v8::Local<v8::Function> f;
18647 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18648 CHECK(f->IsBuiltin());
18649 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18650 CHECK(f->IsBuiltin());
18651 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18652 CHECK(f->IsBuiltin());
18653 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18654 CHECK(f->IsBuiltin());
18655 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18656 CHECK(!f->IsBuiltin());
18660 THREADED_TEST(FunctionGetScriptId) {
18662 v8::Isolate* isolate = env->GetIsolate();
18663 v8::HandleScope scope(isolate);
18664 v8::ScriptOrigin origin =
18665 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18666 v8::Integer::New(isolate, 3),
18667 v8::Integer::New(isolate, 2));
18668 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18669 isolate, "function foo() {}\n\n function bar() {}");
18670 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18672 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18673 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18674 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18675 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18676 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18677 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18681 THREADED_TEST(FunctionGetBoundFunction) {
18683 v8::HandleScope scope(env->GetIsolate());
18684 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18685 env->GetIsolate(), "test"));
18686 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18688 "var a = new Object();\n"
18690 "function f () { return this.x };\n"
18691 "var g = f.bind(a);\n"
18693 v8::Script::Compile(script, &origin)->Run();
18694 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18695 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18696 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18697 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18698 CHECK(g->GetBoundFunction()->IsFunction());
18699 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18700 g->GetBoundFunction());
18701 CHECK_EQ(f->GetName(), original_function->GetName());
18702 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18703 CHECK_EQ(f->GetScriptColumnNumber(),
18704 original_function->GetScriptColumnNumber());
18708 static void GetterWhichReturns42(
18709 Local<String> name,
18710 const v8::PropertyCallbackInfo<v8::Value>& info) {
18711 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18712 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18713 info.GetReturnValue().Set(v8_num(42));
18717 static void SetterWhichSetsYOnThisTo23(
18718 Local<String> name,
18719 Local<Value> value,
18720 const v8::PropertyCallbackInfo<void>& info) {
18721 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18722 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18723 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18727 void FooGetInterceptor(Local<String> name,
18728 const v8::PropertyCallbackInfo<v8::Value>& info) {
18729 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18730 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18731 if (!name->Equals(v8_str("foo"))) return;
18732 info.GetReturnValue().Set(v8_num(42));
18736 void FooSetInterceptor(Local<String> name,
18737 Local<Value> value,
18738 const v8::PropertyCallbackInfo<v8::Value>& info) {
18739 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18740 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18741 if (!name->Equals(v8_str("foo"))) return;
18742 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18743 info.GetReturnValue().Set(v8_num(23));
18747 TEST(SetterOnConstructorPrototype) {
18748 v8::Isolate* isolate = CcTest::isolate();
18749 v8::HandleScope scope(isolate);
18750 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18751 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18752 SetterWhichSetsYOnThisTo23);
18753 LocalContext context;
18754 context->Global()->Set(v8_str("P"), templ->NewInstance());
18755 CompileRun("function C1() {"
18758 "C1.prototype = P;"
18762 "C2.prototype = { };"
18763 "C2.prototype.__proto__ = P;");
18765 v8::Local<v8::Script> script;
18766 script = v8_compile("new C1();");
18767 for (int i = 0; i < 10; i++) {
18768 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18769 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18770 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18773 script = v8_compile("new C2();");
18774 for (int i = 0; i < 10; i++) {
18775 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18776 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18777 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18782 static void NamedPropertyGetterWhichReturns42(
18783 Local<String> name,
18784 const v8::PropertyCallbackInfo<v8::Value>& info) {
18785 info.GetReturnValue().Set(v8_num(42));
18789 static void NamedPropertySetterWhichSetsYOnThisTo23(
18790 Local<String> name,
18791 Local<Value> value,
18792 const v8::PropertyCallbackInfo<v8::Value>& info) {
18793 if (name->Equals(v8_str("x"))) {
18794 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18799 THREADED_TEST(InterceptorOnConstructorPrototype) {
18800 v8::Isolate* isolate = CcTest::isolate();
18801 v8::HandleScope scope(isolate);
18802 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18803 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18804 NamedPropertySetterWhichSetsYOnThisTo23);
18805 LocalContext context;
18806 context->Global()->Set(v8_str("P"), templ->NewInstance());
18807 CompileRun("function C1() {"
18810 "C1.prototype = P;"
18814 "C2.prototype = { };"
18815 "C2.prototype.__proto__ = P;");
18817 v8::Local<v8::Script> script;
18818 script = v8_compile("new C1();");
18819 for (int i = 0; i < 10; i++) {
18820 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18821 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18822 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18825 script = v8_compile("new C2();");
18826 for (int i = 0; i < 10; i++) {
18827 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18828 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18829 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18835 const char* source = "function C1() {"
18838 "C1.prototype = P;";
18840 LocalContext context;
18841 v8::Isolate* isolate = context->GetIsolate();
18842 v8::HandleScope scope(isolate);
18843 v8::Local<v8::Script> script;
18845 // Use a simple object as prototype.
18846 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18847 prototype->Set(v8_str("y"), v8_num(42));
18848 context->Global()->Set(v8_str("P"), prototype);
18850 // This compile will add the code to the compilation cache.
18851 CompileRun(source);
18853 script = v8_compile("new C1();");
18854 // Allow enough iterations for the inobject slack tracking logic
18855 // to finalize instance size and install the fast construct stub.
18856 for (int i = 0; i < 256; i++) {
18857 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18858 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18859 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18862 // Use an API object with accessors as prototype.
18863 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18864 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18865 SetterWhichSetsYOnThisTo23);
18866 context->Global()->Set(v8_str("P"), templ->NewInstance());
18868 // This compile will get the code from the compilation cache.
18869 CompileRun(source);
18871 script = v8_compile("new C1();");
18872 for (int i = 0; i < 10; i++) {
18873 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18874 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18875 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18879 v8::Isolate* gc_callbacks_isolate = NULL;
18880 int prologue_call_count = 0;
18881 int epilogue_call_count = 0;
18882 int prologue_call_count_second = 0;
18883 int epilogue_call_count_second = 0;
18884 int prologue_call_count_alloc = 0;
18885 int epilogue_call_count_alloc = 0;
18887 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18888 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18889 ++prologue_call_count;
18893 void PrologueCallback(v8::Isolate* isolate,
18895 v8::GCCallbackFlags flags) {
18896 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18897 CHECK_EQ(gc_callbacks_isolate, isolate);
18898 ++prologue_call_count;
18902 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18903 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18904 ++epilogue_call_count;
18908 void EpilogueCallback(v8::Isolate* isolate,
18910 v8::GCCallbackFlags flags) {
18911 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18912 CHECK_EQ(gc_callbacks_isolate, isolate);
18913 ++epilogue_call_count;
18917 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18918 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18919 ++prologue_call_count_second;
18923 void PrologueCallbackSecond(v8::Isolate* isolate,
18925 v8::GCCallbackFlags flags) {
18926 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18927 CHECK_EQ(gc_callbacks_isolate, isolate);
18928 ++prologue_call_count_second;
18932 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18933 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18934 ++epilogue_call_count_second;
18938 void EpilogueCallbackSecond(v8::Isolate* isolate,
18940 v8::GCCallbackFlags flags) {
18941 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18942 CHECK_EQ(gc_callbacks_isolate, isolate);
18943 ++epilogue_call_count_second;
18947 void PrologueCallbackAlloc(v8::Isolate* isolate,
18949 v8::GCCallbackFlags flags) {
18950 v8::HandleScope scope(isolate);
18952 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18953 CHECK_EQ(gc_callbacks_isolate, isolate);
18954 ++prologue_call_count_alloc;
18956 // Simulate full heap to see if we will reenter this callback
18957 SimulateFullSpace(CcTest::heap()->new_space());
18959 Local<Object> obj = Object::New(isolate);
18960 CHECK(!obj.IsEmpty());
18962 CcTest::heap()->CollectAllGarbage(
18963 i::Heap::kAbortIncrementalMarkingMask);
18967 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18969 v8::GCCallbackFlags flags) {
18970 v8::HandleScope scope(isolate);
18972 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18973 CHECK_EQ(gc_callbacks_isolate, isolate);
18974 ++epilogue_call_count_alloc;
18976 // Simulate full heap to see if we will reenter this callback
18977 SimulateFullSpace(CcTest::heap()->new_space());
18979 Local<Object> obj = Object::New(isolate);
18980 CHECK(!obj.IsEmpty());
18982 CcTest::heap()->CollectAllGarbage(
18983 i::Heap::kAbortIncrementalMarkingMask);
18987 TEST(GCCallbacksOld) {
18988 LocalContext context;
18990 v8::V8::AddGCPrologueCallback(PrologueCallback);
18991 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18992 CHECK_EQ(0, prologue_call_count);
18993 CHECK_EQ(0, epilogue_call_count);
18994 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18995 CHECK_EQ(1, prologue_call_count);
18996 CHECK_EQ(1, epilogue_call_count);
18997 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18998 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18999 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19000 CHECK_EQ(2, prologue_call_count);
19001 CHECK_EQ(2, epilogue_call_count);
19002 CHECK_EQ(1, prologue_call_count_second);
19003 CHECK_EQ(1, epilogue_call_count_second);
19004 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
19005 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
19006 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19007 CHECK_EQ(2, prologue_call_count);
19008 CHECK_EQ(2, epilogue_call_count);
19009 CHECK_EQ(2, prologue_call_count_second);
19010 CHECK_EQ(2, epilogue_call_count_second);
19011 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
19012 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19013 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19014 CHECK_EQ(2, prologue_call_count);
19015 CHECK_EQ(2, epilogue_call_count);
19016 CHECK_EQ(2, prologue_call_count_second);
19017 CHECK_EQ(2, epilogue_call_count_second);
19021 TEST(GCCallbacks) {
19022 LocalContext context;
19023 v8::Isolate* isolate = context->GetIsolate();
19024 gc_callbacks_isolate = isolate;
19025 isolate->AddGCPrologueCallback(PrologueCallback);
19026 isolate->AddGCEpilogueCallback(EpilogueCallback);
19027 CHECK_EQ(0, prologue_call_count);
19028 CHECK_EQ(0, epilogue_call_count);
19029 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19030 CHECK_EQ(1, prologue_call_count);
19031 CHECK_EQ(1, epilogue_call_count);
19032 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19033 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19034 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19035 CHECK_EQ(2, prologue_call_count);
19036 CHECK_EQ(2, epilogue_call_count);
19037 CHECK_EQ(1, prologue_call_count_second);
19038 CHECK_EQ(1, epilogue_call_count_second);
19039 isolate->RemoveGCPrologueCallback(PrologueCallback);
19040 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19041 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19042 CHECK_EQ(2, prologue_call_count);
19043 CHECK_EQ(2, epilogue_call_count);
19044 CHECK_EQ(2, prologue_call_count_second);
19045 CHECK_EQ(2, epilogue_call_count_second);
19046 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19047 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19048 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19049 CHECK_EQ(2, prologue_call_count);
19050 CHECK_EQ(2, epilogue_call_count);
19051 CHECK_EQ(2, prologue_call_count_second);
19052 CHECK_EQ(2, epilogue_call_count_second);
19054 CHECK_EQ(0, prologue_call_count_alloc);
19055 CHECK_EQ(0, epilogue_call_count_alloc);
19056 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19057 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19058 CcTest::heap()->CollectAllGarbage(
19059 i::Heap::kAbortIncrementalMarkingMask);
19060 CHECK_EQ(1, prologue_call_count_alloc);
19061 CHECK_EQ(1, epilogue_call_count_alloc);
19062 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19063 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19067 THREADED_TEST(AddToJSFunctionResultCache) {
19068 i::FLAG_stress_compaction = false;
19069 i::FLAG_allow_natives_syntax = true;
19070 v8::HandleScope scope(CcTest::isolate());
19072 LocalContext context;
19078 " var r0 = %_GetFromCache(0, key0);"
19079 " var r1 = %_GetFromCache(0, key1);"
19080 " var r0_ = %_GetFromCache(0, key0);"
19082 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
19083 " var r1_ = %_GetFromCache(0, key1);"
19085 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
19086 " return 'PASSED';"
19088 CcTest::heap()->ClearJSFunctionResultCaches();
19089 ExpectString(code, "PASSED");
19093 THREADED_TEST(FillJSFunctionResultCache) {
19094 i::FLAG_allow_natives_syntax = true;
19095 LocalContext context;
19096 v8::HandleScope scope(context->GetIsolate());
19101 " var r = %_GetFromCache(0, k);"
19102 " for (var i = 0; i < 16; i++) {"
19103 " %_GetFromCache(0, 'a' + i);"
19105 " if (r === %_GetFromCache(0, k))"
19106 " return 'FAILED: k0CacheSize is too small';"
19107 " return 'PASSED';"
19109 CcTest::heap()->ClearJSFunctionResultCaches();
19110 ExpectString(code, "PASSED");
19114 THREADED_TEST(RoundRobinGetFromCache) {
19115 i::FLAG_allow_natives_syntax = true;
19116 LocalContext context;
19117 v8::HandleScope scope(context->GetIsolate());
19122 " for (var i = 0; i < 16; i++) keys.push(i);"
19123 " var values = [];"
19124 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19125 " for (var i = 0; i < 16; i++) {"
19126 " var v = %_GetFromCache(0, keys[i]);"
19127 " if (v.toString() !== values[i].toString())"
19128 " return 'Wrong value for ' + "
19129 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19131 " return 'PASSED';"
19133 CcTest::heap()->ClearJSFunctionResultCaches();
19134 ExpectString(code, "PASSED");
19138 THREADED_TEST(ReverseGetFromCache) {
19139 i::FLAG_allow_natives_syntax = true;
19140 LocalContext context;
19141 v8::HandleScope scope(context->GetIsolate());
19146 " for (var i = 0; i < 16; i++) keys.push(i);"
19147 " var values = [];"
19148 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19149 " for (var i = 15; i >= 16; i--) {"
19150 " var v = %_GetFromCache(0, keys[i]);"
19151 " if (v !== values[i])"
19152 " return 'Wrong value for ' + "
19153 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19155 " return 'PASSED';"
19157 CcTest::heap()->ClearJSFunctionResultCaches();
19158 ExpectString(code, "PASSED");
19162 THREADED_TEST(TestEviction) {
19163 i::FLAG_allow_natives_syntax = true;
19164 LocalContext context;
19165 v8::HandleScope scope(context->GetIsolate());
19169 " for (var i = 0; i < 2*16; i++) {"
19170 " %_GetFromCache(0, 'a' + i);"
19172 " return 'PASSED';"
19174 CcTest::heap()->ClearJSFunctionResultCaches();
19175 ExpectString(code, "PASSED");
19179 THREADED_TEST(TwoByteStringInOneByteCons) {
19180 // See Chromium issue 47824.
19181 LocalContext context;
19182 v8::HandleScope scope(context->GetIsolate());
19184 const char* init_code =
19185 "var str1 = 'abelspendabel';"
19186 "var str2 = str1 + str1 + str1;"
19188 Local<Value> result = CompileRun(init_code);
19190 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19191 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19193 CHECK(result->IsString());
19194 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19195 int length = string->length();
19196 CHECK(string->IsOneByteRepresentation());
19198 i::Handle<i::String> flat_string = i::String::Flatten(string);
19200 CHECK(string->IsOneByteRepresentation());
19201 CHECK(flat_string->IsOneByteRepresentation());
19203 // Create external resource.
19204 uint16_t* uc16_buffer = new uint16_t[length + 1];
19206 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19207 uc16_buffer[length] = 0;
19209 TestResource resource(uc16_buffer);
19211 flat_string->MakeExternal(&resource);
19213 CHECK(flat_string->IsTwoByteRepresentation());
19215 // If the cons string has been short-circuited, skip the following checks.
19216 if (!string.is_identical_to(flat_string)) {
19217 // At this point, we should have a Cons string which is flat and one-byte,
19218 // with a first half that is a two-byte string (although it only contains
19219 // one-byte characters). This is a valid sequence of steps, and it can
19220 // happen in real pages.
19221 CHECK(string->IsOneByteRepresentation());
19222 i::ConsString* cons = i::ConsString::cast(*string);
19223 CHECK_EQ(0, cons->second()->length());
19224 CHECK(cons->first()->IsTwoByteRepresentation());
19227 // Check that some string operations work.
19230 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19231 CHECK_EQ(6, reresult->Int32Value());
19234 reresult = CompileRun("str2.match(/abe./g).length;");
19235 CHECK_EQ(6, reresult->Int32Value());
19237 reresult = CompileRun("str2.search(/bel/g);");
19238 CHECK_EQ(1, reresult->Int32Value());
19240 reresult = CompileRun("str2.search(/be./g);");
19241 CHECK_EQ(1, reresult->Int32Value());
19243 ExpectTrue("/bel/g.test(str2);");
19245 ExpectTrue("/be./g.test(str2);");
19247 reresult = CompileRun("/bel/g.exec(str2);");
19248 CHECK(!reresult->IsNull());
19250 reresult = CompileRun("/be./g.exec(str2);");
19251 CHECK(!reresult->IsNull());
19253 ExpectString("str2.substring(2, 10);", "elspenda");
19255 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19257 ExpectString("str2.charAt(2);", "e");
19259 ExpectObject("str2.indexOf('els');", indexof);
19261 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19263 reresult = CompileRun("str2.charCodeAt(2);");
19264 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19268 TEST(ContainsOnlyOneByte) {
19269 v8::V8::Initialize();
19270 v8::Isolate* isolate = CcTest::isolate();
19271 v8::HandleScope scope(isolate);
19272 // Make a buffer long enough that it won't automatically be converted.
19273 const int length = 512;
19274 // Ensure word aligned assignment.
19275 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19276 i::SmartArrayPointer<uintptr_t>
19277 aligned_contents(new uintptr_t[aligned_length]);
19278 uint16_t* string_contents =
19279 reinterpret_cast<uint16_t*>(aligned_contents.get());
19280 // Set to contain only one byte.
19281 for (int i = 0; i < length-1; i++) {
19282 string_contents[i] = 0x41;
19284 string_contents[length-1] = 0;
19286 Handle<String> string =
19287 String::NewExternal(isolate,
19288 new TestResource(string_contents, NULL, false));
19289 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19290 // Counter example.
19291 string = String::NewFromTwoByte(isolate, string_contents);
19292 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19293 // Test left right and balanced cons strings.
19294 Handle<String> base = String::NewFromUtf8(isolate, "a");
19295 Handle<String> left = base;
19296 Handle<String> right = base;
19297 for (int i = 0; i < 1000; i++) {
19298 left = String::Concat(base, left);
19299 right = String::Concat(right, base);
19301 Handle<String> balanced = String::Concat(left, base);
19302 balanced = String::Concat(balanced, right);
19303 Handle<String> cons_strings[] = {left, balanced, right};
19304 Handle<String> two_byte =
19305 String::NewExternal(isolate,
19306 new TestResource(string_contents, NULL, false));
19307 USE(two_byte); USE(cons_strings);
19308 for (size_t i = 0; i < arraysize(cons_strings); i++) {
19309 // Base assumptions.
19310 string = cons_strings[i];
19311 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19312 // Test left and right concatentation.
19313 string = String::Concat(two_byte, cons_strings[i]);
19314 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19315 string = String::Concat(cons_strings[i], two_byte);
19316 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19318 // Set bits in different positions
19319 // for strings of different lengths and alignments.
19320 for (int alignment = 0; alignment < 7; alignment++) {
19321 for (int size = 2; alignment + size < length; size *= 2) {
19322 int zero_offset = size + alignment;
19323 string_contents[zero_offset] = 0;
19324 for (int i = 0; i < size; i++) {
19325 int shift = 8 + (i % 7);
19326 string_contents[alignment + i] = 1 << shift;
19327 string = String::NewExternal(
19329 new TestResource(string_contents + alignment, NULL, false));
19330 CHECK_EQ(size, string->Length());
19331 CHECK(!string->ContainsOnlyOneByte());
19332 string_contents[alignment + i] = 0x41;
19334 string_contents[zero_offset] = 0x41;
19340 // Failed access check callback that performs a GC on each invocation.
19341 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19342 v8::AccessType type,
19343 Local<v8::Value> data) {
19344 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19348 TEST(GCInFailedAccessCheckCallback) {
19349 // Install a failed access check callback that performs a GC on each
19350 // invocation. Then force the callback to be called from va
19352 v8::V8::Initialize();
19353 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19355 v8::Isolate* isolate = CcTest::isolate();
19356 v8::HandleScope scope(isolate);
19358 // Create an ObjectTemplate for global objects and install access
19359 // check callbacks that will block access.
19360 v8::Handle<v8::ObjectTemplate> global_template =
19361 v8::ObjectTemplate::New(isolate);
19362 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19363 IndexedGetAccessBlocker,
19364 v8::Handle<v8::Value>(),
19367 // Create a context and set an x property on it's global object.
19368 LocalContext context0(NULL, global_template);
19369 context0->Global()->Set(v8_str("x"), v8_num(42));
19370 v8::Handle<v8::Object> global0 = context0->Global();
19372 // Create a context with a different security token so that the
19373 // failed access check callback will be called on each access.
19374 LocalContext context1(NULL, global_template);
19375 context1->Global()->Set(v8_str("other"), global0);
19377 // Get property with failed access check.
19378 ExpectUndefined("other.x");
19380 // Get element with failed access check.
19381 ExpectUndefined("other[0]");
19383 // Set property with failed access check.
19384 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19385 CHECK(result->IsObject());
19387 // Set element with failed access check.
19388 result = CompileRun("other[0] = new Object()");
19389 CHECK(result->IsObject());
19391 // Get property attribute with failed access check.
19392 ExpectFalse("\'x\' in other");
19394 // Get property attribute for element with failed access check.
19395 ExpectFalse("0 in other");
19397 // Delete property.
19398 ExpectFalse("delete other.x");
19401 CHECK_EQ(false, global0->Delete(0));
19405 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19407 // Define JavaScript accessor.
19408 ExpectUndefined("Object.prototype.__defineGetter__.call("
19409 " other, \'x\', function() { return 42; })");
19412 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19416 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19418 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19419 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19420 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19422 // Reset the failed access check callback so it does not influence
19423 // the other tests.
19424 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19428 TEST(IsolateNewDispose) {
19429 v8::Isolate* current_isolate = CcTest::isolate();
19430 v8::Isolate* isolate = v8::Isolate::New();
19431 CHECK(isolate != NULL);
19432 CHECK(current_isolate != isolate);
19433 CHECK(current_isolate == CcTest::isolate());
19435 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19436 last_location = last_message = NULL;
19437 isolate->Dispose();
19438 CHECK_EQ(last_location, NULL);
19439 CHECK_EQ(last_message, NULL);
19443 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19444 v8::Isolate* isolate = v8::Isolate::New();
19446 v8::Isolate::Scope i_scope(isolate);
19447 v8::HandleScope scope(isolate);
19448 LocalContext context(isolate);
19449 // Run something in this isolate.
19450 ExpectTrue("true");
19451 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19452 last_location = last_message = NULL;
19453 // Still entered, should fail.
19454 isolate->Dispose();
19455 CHECK_NE(last_location, NULL);
19456 CHECK_NE(last_message, NULL);
19458 isolate->Dispose();
19462 TEST(RunTwoIsolatesOnSingleThread) {
19464 v8::Isolate* isolate1 = v8::Isolate::New();
19466 v8::Persistent<v8::Context> context1;
19468 v8::HandleScope scope(isolate1);
19469 context1.Reset(isolate1, Context::New(isolate1));
19473 v8::HandleScope scope(isolate1);
19474 v8::Local<v8::Context> context =
19475 v8::Local<v8::Context>::New(isolate1, context1);
19476 v8::Context::Scope context_scope(context);
19477 // Run something in new isolate.
19478 CompileRun("var foo = 'isolate 1';");
19479 ExpectString("function f() { return foo; }; f()", "isolate 1");
19483 v8::Isolate* isolate2 = v8::Isolate::New();
19484 v8::Persistent<v8::Context> context2;
19487 v8::Isolate::Scope iscope(isolate2);
19488 v8::HandleScope scope(isolate2);
19489 context2.Reset(isolate2, Context::New(isolate2));
19490 v8::Local<v8::Context> context =
19491 v8::Local<v8::Context>::New(isolate2, context2);
19492 v8::Context::Scope context_scope(context);
19494 // Run something in new isolate.
19495 CompileRun("var foo = 'isolate 2';");
19496 ExpectString("function f() { return foo; }; f()", "isolate 2");
19500 v8::HandleScope scope(isolate1);
19501 v8::Local<v8::Context> context =
19502 v8::Local<v8::Context>::New(isolate1, context1);
19503 v8::Context::Scope context_scope(context);
19504 // Now again in isolate 1
19505 ExpectString("function f() { return foo; }; f()", "isolate 1");
19510 // Run some stuff in default isolate.
19511 v8::Persistent<v8::Context> context_default;
19513 v8::Isolate* isolate = CcTest::isolate();
19514 v8::Isolate::Scope iscope(isolate);
19515 v8::HandleScope scope(isolate);
19516 context_default.Reset(isolate, Context::New(isolate));
19520 v8::HandleScope scope(CcTest::isolate());
19521 v8::Local<v8::Context> context =
19522 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19523 v8::Context::Scope context_scope(context);
19524 // Variables in other isolates should be not available, verify there
19525 // is an exception.
19526 ExpectTrue("function f() {"
19534 "var isDefaultIsolate = true;"
19541 v8::Isolate::Scope iscope(isolate2);
19542 v8::HandleScope scope(isolate2);
19543 v8::Local<v8::Context> context =
19544 v8::Local<v8::Context>::New(isolate2, context2);
19545 v8::Context::Scope context_scope(context);
19546 ExpectString("function f() { return foo; }; f()", "isolate 2");
19550 v8::HandleScope scope(v8::Isolate::GetCurrent());
19551 v8::Local<v8::Context> context =
19552 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19553 v8::Context::Scope context_scope(context);
19554 ExpectString("function f() { return foo; }; f()", "isolate 1");
19558 v8::Isolate::Scope iscope(isolate2);
19565 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19566 last_location = last_message = NULL;
19568 isolate1->Dispose();
19569 CHECK_EQ(last_location, NULL);
19570 CHECK_EQ(last_message, NULL);
19572 isolate2->Dispose();
19573 CHECK_EQ(last_location, NULL);
19574 CHECK_EQ(last_message, NULL);
19576 // Check that default isolate still runs.
19578 v8::HandleScope scope(CcTest::isolate());
19579 v8::Local<v8::Context> context =
19580 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19581 v8::Context::Scope context_scope(context);
19582 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19587 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19588 v8::Isolate::Scope isolate_scope(isolate);
19589 v8::HandleScope scope(isolate);
19590 LocalContext context(isolate);
19591 i::ScopedVector<char> code(1024);
19592 i::SNPrintF(code, "function fib(n) {"
19593 " if (n <= 2) return 1;"
19594 " return fib(n-1) + fib(n-2);"
19597 Local<Value> value = CompileRun(code.start());
19598 CHECK(value->IsNumber());
19599 return static_cast<int>(value->NumberValue());
19602 class IsolateThread : public v8::base::Thread {
19604 explicit IsolateThread(int fib_limit)
19605 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
19608 v8::Isolate* isolate = v8::Isolate::New();
19609 result_ = CalcFibonacci(isolate, fib_limit_);
19610 isolate->Dispose();
19613 int result() { return result_; }
19621 TEST(MultipleIsolatesOnIndividualThreads) {
19622 IsolateThread thread1(21);
19623 IsolateThread thread2(12);
19625 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19629 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19630 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19635 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19636 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19637 CHECK_EQ(result1, 10946);
19638 CHECK_EQ(result2, 144);
19639 CHECK_EQ(result1, thread1.result());
19640 CHECK_EQ(result2, thread2.result());
19644 TEST(IsolateDifferentContexts) {
19645 v8::Isolate* isolate = v8::Isolate::New();
19646 Local<v8::Context> context;
19648 v8::Isolate::Scope isolate_scope(isolate);
19649 v8::HandleScope handle_scope(isolate);
19650 context = v8::Context::New(isolate);
19651 v8::Context::Scope context_scope(context);
19652 Local<Value> v = CompileRun("2");
19653 CHECK(v->IsNumber());
19654 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19657 v8::Isolate::Scope isolate_scope(isolate);
19658 v8::HandleScope handle_scope(isolate);
19659 context = v8::Context::New(isolate);
19660 v8::Context::Scope context_scope(context);
19661 Local<Value> v = CompileRun("22");
19662 CHECK(v->IsNumber());
19663 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19665 isolate->Dispose();
19668 class InitDefaultIsolateThread : public v8::base::Thread {
19671 SetResourceConstraints,
19673 SetCounterFunction,
19674 SetCreateHistogramFunction,
19675 SetAddHistogramSampleFunction
19678 explicit InitDefaultIsolateThread(TestCase testCase)
19679 : Thread(Options("InitDefaultIsolateThread")),
19680 testCase_(testCase),
19684 v8::Isolate::CreateParams create_params;
19685 switch (testCase_) {
19686 case SetResourceConstraints: {
19687 create_params.constraints.set_max_semi_space_size(1);
19688 create_params.constraints.set_max_old_space_size(4);
19694 v8::Isolate* isolate = v8::Isolate::New(create_params);
19696 switch (testCase_) {
19697 case SetResourceConstraints:
19698 // Already handled in pre-Isolate-creation block.
19701 case SetFatalHandler:
19702 v8::V8::SetFatalErrorHandler(NULL);
19705 case SetCounterFunction:
19706 CcTest::isolate()->SetCounterFunction(NULL);
19709 case SetCreateHistogramFunction:
19710 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19713 case SetAddHistogramSampleFunction:
19714 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19718 isolate->Dispose();
19722 bool result() { return result_; }
19725 TestCase testCase_;
19730 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19731 InitDefaultIsolateThread thread(testCase);
19734 CHECK_EQ(thread.result(), true);
19738 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19739 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19743 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19744 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19748 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19749 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19753 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19754 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19758 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19759 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19763 TEST(StringCheckMultipleContexts) {
19765 "(function() { return \"a\".charAt(0); })()";
19768 // Run the code twice in the first context to initialize the call IC.
19769 LocalContext context1;
19770 v8::HandleScope scope(context1->GetIsolate());
19771 ExpectString(code, "a");
19772 ExpectString(code, "a");
19776 // Change the String.prototype in the second context and check
19777 // that the right function gets called.
19778 LocalContext context2;
19779 v8::HandleScope scope(context2->GetIsolate());
19780 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19781 ExpectString(code, "not a");
19786 TEST(NumberCheckMultipleContexts) {
19788 "(function() { return (42).toString(); })()";
19791 // Run the code twice in the first context to initialize the call IC.
19792 LocalContext context1;
19793 v8::HandleScope scope(context1->GetIsolate());
19794 ExpectString(code, "42");
19795 ExpectString(code, "42");
19799 // Change the Number.prototype in the second context and check
19800 // that the right function gets called.
19801 LocalContext context2;
19802 v8::HandleScope scope(context2->GetIsolate());
19803 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19804 ExpectString(code, "not 42");
19809 TEST(BooleanCheckMultipleContexts) {
19811 "(function() { return true.toString(); })()";
19814 // Run the code twice in the first context to initialize the call IC.
19815 LocalContext context1;
19816 v8::HandleScope scope(context1->GetIsolate());
19817 ExpectString(code, "true");
19818 ExpectString(code, "true");
19822 // Change the Boolean.prototype in the second context and check
19823 // that the right function gets called.
19824 LocalContext context2;
19825 v8::HandleScope scope(context2->GetIsolate());
19826 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19827 ExpectString(code, "");
19832 TEST(DontDeleteCellLoadIC) {
19833 const char* function_code =
19834 "function readCell() { while (true) { return cell; } }";
19837 // Run the code twice in the first context to initialize the load
19838 // IC for a don't delete cell.
19839 LocalContext context1;
19840 v8::HandleScope scope(context1->GetIsolate());
19841 CompileRun("var cell = \"first\";");
19842 ExpectBoolean("delete cell", false);
19843 CompileRun(function_code);
19844 ExpectString("readCell()", "first");
19845 ExpectString("readCell()", "first");
19849 // Use a deletable cell in the second context.
19850 LocalContext context2;
19851 v8::HandleScope scope(context2->GetIsolate());
19852 CompileRun("cell = \"second\";");
19853 CompileRun(function_code);
19854 ExpectString("readCell()", "second");
19855 ExpectBoolean("delete cell", true);
19856 ExpectString("(function() {"
19858 " return readCell();"
19860 " return e.toString();"
19863 "ReferenceError: cell is not defined");
19864 CompileRun("cell = \"new_second\";");
19865 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19866 ExpectString("readCell()", "new_second");
19867 ExpectString("readCell()", "new_second");
19872 TEST(DontDeleteCellLoadICForceDelete) {
19873 const char* function_code =
19874 "function readCell() { while (true) { return cell; } }";
19876 // Run the code twice to initialize the load IC for a don't delete
19878 LocalContext context;
19879 v8::HandleScope scope(context->GetIsolate());
19880 CompileRun("var cell = \"value\";");
19881 ExpectBoolean("delete cell", false);
19882 CompileRun(function_code);
19883 ExpectString("readCell()", "value");
19884 ExpectString("readCell()", "value");
19886 // Delete the cell using the API and check the inlined code works
19888 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19889 ExpectString("(function() {"
19891 " return readCell();"
19893 " return e.toString();"
19896 "ReferenceError: cell is not defined");
19900 TEST(DontDeleteCellLoadICAPI) {
19901 const char* function_code =
19902 "function readCell() { while (true) { return cell; } }";
19904 // Run the code twice to initialize the load IC for a don't delete
19905 // cell created using the API.
19906 LocalContext context;
19907 v8::HandleScope scope(context->GetIsolate());
19908 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19909 ExpectBoolean("delete cell", false);
19910 CompileRun(function_code);
19911 ExpectString("readCell()", "value");
19912 ExpectString("readCell()", "value");
19914 // Delete the cell using the API and check the inlined code works
19916 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19917 ExpectString("(function() {"
19919 " return readCell();"
19921 " return e.toString();"
19924 "ReferenceError: cell is not defined");
19928 class Visitor42 : public v8::PersistentHandleVisitor {
19930 explicit Visitor42(v8::Persistent<v8::Object>* object)
19931 : counter_(0), object_(object) { }
19933 virtual void VisitPersistentHandle(Persistent<Value>* value,
19934 uint16_t class_id) {
19935 if (class_id != 42) return;
19936 CHECK_EQ(42, value->WrapperClassId());
19937 v8::Isolate* isolate = CcTest::isolate();
19938 v8::HandleScope handle_scope(isolate);
19939 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19940 v8::Handle<v8::Value> object =
19941 v8::Local<v8::Object>::New(isolate, *object_);
19942 CHECK(handle->IsObject());
19943 CHECK_EQ(Handle<Object>::Cast(handle), object);
19948 v8::Persistent<v8::Object>* object_;
19952 TEST(PersistentHandleVisitor) {
19953 LocalContext context;
19954 v8::Isolate* isolate = context->GetIsolate();
19955 v8::HandleScope scope(isolate);
19956 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19957 CHECK_EQ(0, object.WrapperClassId());
19958 object.SetWrapperClassId(42);
19959 CHECK_EQ(42, object.WrapperClassId());
19961 Visitor42 visitor(&object);
19962 v8::V8::VisitHandlesWithClassIds(&visitor);
19963 CHECK_EQ(1, visitor.counter_);
19969 TEST(WrapperClassId) {
19970 LocalContext context;
19971 v8::Isolate* isolate = context->GetIsolate();
19972 v8::HandleScope scope(isolate);
19973 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19974 CHECK_EQ(0, object.WrapperClassId());
19975 object.SetWrapperClassId(65535);
19976 CHECK_EQ(65535, object.WrapperClassId());
19981 TEST(PersistentHandleInNewSpaceVisitor) {
19982 LocalContext context;
19983 v8::Isolate* isolate = context->GetIsolate();
19984 v8::HandleScope scope(isolate);
19985 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19986 CHECK_EQ(0, object1.WrapperClassId());
19987 object1.SetWrapperClassId(42);
19988 CHECK_EQ(42, object1.WrapperClassId());
19990 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19991 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19993 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19994 CHECK_EQ(0, object2.WrapperClassId());
19995 object2.SetWrapperClassId(42);
19996 CHECK_EQ(42, object2.WrapperClassId());
19998 Visitor42 visitor(&object2);
19999 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
20000 CHECK_EQ(1, visitor.counter_);
20008 LocalContext context;
20009 v8::HandleScope scope(context->GetIsolate());
20011 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
20012 CHECK(re->IsRegExp());
20013 CHECK(re->GetSource()->Equals(v8_str("foo")));
20014 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20016 re = v8::RegExp::New(v8_str("bar"),
20017 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20018 v8::RegExp::kGlobal));
20019 CHECK(re->IsRegExp());
20020 CHECK(re->GetSource()->Equals(v8_str("bar")));
20021 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20022 static_cast<int>(re->GetFlags()));
20024 re = v8::RegExp::New(v8_str("baz"),
20025 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20026 v8::RegExp::kMultiline));
20027 CHECK(re->IsRegExp());
20028 CHECK(re->GetSource()->Equals(v8_str("baz")));
20029 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20030 static_cast<int>(re->GetFlags()));
20032 re = CompileRun("/quux/").As<v8::RegExp>();
20033 CHECK(re->IsRegExp());
20034 CHECK(re->GetSource()->Equals(v8_str("quux")));
20035 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20037 re = CompileRun("/quux/gm").As<v8::RegExp>();
20038 CHECK(re->IsRegExp());
20039 CHECK(re->GetSource()->Equals(v8_str("quux")));
20040 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20041 static_cast<int>(re->GetFlags()));
20043 // Override the RegExp constructor and check the API constructor
20045 CompileRun("RegExp = function() {}");
20047 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
20048 CHECK(re->IsRegExp());
20049 CHECK(re->GetSource()->Equals(v8_str("foobar")));
20050 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20052 re = v8::RegExp::New(v8_str("foobarbaz"),
20053 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20054 v8::RegExp::kMultiline));
20055 CHECK(re->IsRegExp());
20056 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
20057 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20058 static_cast<int>(re->GetFlags()));
20060 context->Global()->Set(v8_str("re"), re);
20061 ExpectTrue("re.test('FoobarbaZ')");
20063 // RegExps are objects on which you can set properties.
20064 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
20065 v8::Handle<v8::Value> value(CompileRun("re.property"));
20066 CHECK_EQ(32, value->Int32Value());
20068 v8::TryCatch try_catch;
20069 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
20070 CHECK(re.IsEmpty());
20071 CHECK(try_catch.HasCaught());
20072 context->Global()->Set(v8_str("ex"), try_catch.Exception());
20073 ExpectTrue("ex instanceof SyntaxError");
20077 THREADED_TEST(Equals) {
20078 LocalContext localContext;
20079 v8::HandleScope handleScope(localContext->GetIsolate());
20081 v8::Handle<v8::Object> globalProxy = localContext->Global();
20082 v8::Handle<Value> global = globalProxy->GetPrototype();
20084 CHECK(global->StrictEquals(global));
20085 CHECK(!global->StrictEquals(globalProxy));
20086 CHECK(!globalProxy->StrictEquals(global));
20087 CHECK(globalProxy->StrictEquals(globalProxy));
20089 CHECK(global->Equals(global));
20090 CHECK(!global->Equals(globalProxy));
20091 CHECK(!globalProxy->Equals(global));
20092 CHECK(globalProxy->Equals(globalProxy));
20096 static void Getter(v8::Local<v8::String> property,
20097 const v8::PropertyCallbackInfo<v8::Value>& info ) {
20098 info.GetReturnValue().Set(v8_str("42!"));
20102 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20103 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20104 result->Set(0, v8_str("universalAnswer"));
20105 info.GetReturnValue().Set(result);
20109 TEST(NamedEnumeratorAndForIn) {
20110 LocalContext context;
20111 v8::Isolate* isolate = context->GetIsolate();
20112 v8::HandleScope handle_scope(isolate);
20113 v8::Context::Scope context_scope(context.local());
20115 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20116 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20117 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20118 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20119 "var result = []; for (var k in o) result.push(k); result"));
20120 CHECK_EQ(1, result->Length());
20121 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20125 TEST(DefinePropertyPostDetach) {
20126 LocalContext context;
20127 v8::HandleScope scope(context->GetIsolate());
20128 v8::Handle<v8::Object> proxy = context->Global();
20129 v8::Handle<v8::Function> define_property =
20130 CompileRun("(function() {"
20131 " Object.defineProperty("
20134 " { configurable: true, enumerable: true, value: 3 });"
20135 "})").As<Function>();
20136 context->DetachGlobal();
20137 define_property->Call(proxy, 0, NULL);
20141 static void InstallContextId(v8::Handle<Context> context, int id) {
20142 Context::Scope scope(context);
20143 CompileRun("Object.prototype").As<Object>()->
20144 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20148 static void CheckContextId(v8::Handle<Object> object, int expected) {
20149 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20153 THREADED_TEST(CreationContext) {
20154 v8::Isolate* isolate = CcTest::isolate();
20155 HandleScope handle_scope(isolate);
20156 Handle<Context> context1 = Context::New(isolate);
20157 InstallContextId(context1, 1);
20158 Handle<Context> context2 = Context::New(isolate);
20159 InstallContextId(context2, 2);
20160 Handle<Context> context3 = Context::New(isolate);
20161 InstallContextId(context3, 3);
20163 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20165 Local<Object> object1;
20166 Local<Function> func1;
20168 Context::Scope scope(context1);
20169 object1 = Object::New(isolate);
20170 func1 = tmpl->GetFunction();
20173 Local<Object> object2;
20174 Local<Function> func2;
20176 Context::Scope scope(context2);
20177 object2 = Object::New(isolate);
20178 func2 = tmpl->GetFunction();
20181 Local<Object> instance1;
20182 Local<Object> instance2;
20185 Context::Scope scope(context3);
20186 instance1 = func1->NewInstance();
20187 instance2 = func2->NewInstance();
20190 CHECK(object1->CreationContext() == context1);
20191 CheckContextId(object1, 1);
20192 CHECK(func1->CreationContext() == context1);
20193 CheckContextId(func1, 1);
20194 CHECK(instance1->CreationContext() == context1);
20195 CheckContextId(instance1, 1);
20196 CHECK(object2->CreationContext() == context2);
20197 CheckContextId(object2, 2);
20198 CHECK(func2->CreationContext() == context2);
20199 CheckContextId(func2, 2);
20200 CHECK(instance2->CreationContext() == context2);
20201 CheckContextId(instance2, 2);
20204 Context::Scope scope(context1);
20205 CHECK(object1->CreationContext() == context1);
20206 CheckContextId(object1, 1);
20207 CHECK(func1->CreationContext() == context1);
20208 CheckContextId(func1, 1);
20209 CHECK(instance1->CreationContext() == context1);
20210 CheckContextId(instance1, 1);
20211 CHECK(object2->CreationContext() == context2);
20212 CheckContextId(object2, 2);
20213 CHECK(func2->CreationContext() == context2);
20214 CheckContextId(func2, 2);
20215 CHECK(instance2->CreationContext() == context2);
20216 CheckContextId(instance2, 2);
20220 Context::Scope scope(context2);
20221 CHECK(object1->CreationContext() == context1);
20222 CheckContextId(object1, 1);
20223 CHECK(func1->CreationContext() == context1);
20224 CheckContextId(func1, 1);
20225 CHECK(instance1->CreationContext() == context1);
20226 CheckContextId(instance1, 1);
20227 CHECK(object2->CreationContext() == context2);
20228 CheckContextId(object2, 2);
20229 CHECK(func2->CreationContext() == context2);
20230 CheckContextId(func2, 2);
20231 CHECK(instance2->CreationContext() == context2);
20232 CheckContextId(instance2, 2);
20237 THREADED_TEST(CreationContextOfJsFunction) {
20238 HandleScope handle_scope(CcTest::isolate());
20239 Handle<Context> context = Context::New(CcTest::isolate());
20240 InstallContextId(context, 1);
20242 Local<Object> function;
20244 Context::Scope scope(context);
20245 function = CompileRun("function foo() {}; foo").As<Object>();
20248 CHECK(function->CreationContext() == context);
20249 CheckContextId(function, 1);
20253 void HasOwnPropertyIndexedPropertyGetter(
20255 const v8::PropertyCallbackInfo<v8::Value>& info) {
20256 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20260 void HasOwnPropertyNamedPropertyGetter(
20261 Local<String> property,
20262 const v8::PropertyCallbackInfo<v8::Value>& info) {
20263 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20267 void HasOwnPropertyIndexedPropertyQuery(
20268 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20269 if (index == 42) info.GetReturnValue().Set(1);
20273 void HasOwnPropertyNamedPropertyQuery(
20274 Local<String> property,
20275 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20276 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20280 void HasOwnPropertyNamedPropertyQuery2(
20281 Local<String> property,
20282 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20283 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20287 void HasOwnPropertyAccessorGetter(
20288 Local<String> property,
20289 const v8::PropertyCallbackInfo<v8::Value>& info) {
20290 info.GetReturnValue().Set(v8_str("yes"));
20294 TEST(HasOwnProperty) {
20296 v8::Isolate* isolate = env->GetIsolate();
20297 v8::HandleScope scope(isolate);
20298 { // Check normal properties and defined getters.
20299 Handle<Value> value = CompileRun(
20302 " this.__defineGetter__('baz', function() { return 1; });"
20304 "function Bar() { "
20306 " this.__defineGetter__('bla', function() { return 2; });"
20308 "Bar.prototype = new Foo();"
20310 CHECK(value->IsObject());
20311 Handle<Object> object = value->ToObject();
20312 CHECK(object->Has(v8_str("foo")));
20313 CHECK(!object->HasOwnProperty(v8_str("foo")));
20314 CHECK(object->HasOwnProperty(v8_str("bar")));
20315 CHECK(object->Has(v8_str("baz")));
20316 CHECK(!object->HasOwnProperty(v8_str("baz")));
20317 CHECK(object->HasOwnProperty(v8_str("bla")));
20319 { // Check named getter interceptors.
20320 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20321 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20322 Handle<Object> instance = templ->NewInstance();
20323 CHECK(!instance->HasOwnProperty(v8_str("42")));
20324 CHECK(instance->HasOwnProperty(v8_str("foo")));
20325 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20327 { // Check indexed getter interceptors.
20328 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20329 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20330 Handle<Object> instance = templ->NewInstance();
20331 CHECK(instance->HasOwnProperty(v8_str("42")));
20332 CHECK(!instance->HasOwnProperty(v8_str("43")));
20333 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20335 { // Check named query interceptors.
20336 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20337 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20338 Handle<Object> instance = templ->NewInstance();
20339 CHECK(instance->HasOwnProperty(v8_str("foo")));
20340 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20342 { // Check indexed query interceptors.
20343 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20344 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20345 Handle<Object> instance = templ->NewInstance();
20346 CHECK(instance->HasOwnProperty(v8_str("42")));
20347 CHECK(!instance->HasOwnProperty(v8_str("41")));
20349 { // Check callbacks.
20350 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20351 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20352 Handle<Object> instance = templ->NewInstance();
20353 CHECK(instance->HasOwnProperty(v8_str("foo")));
20354 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20356 { // Check that query wins on disagreement.
20357 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20358 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20360 HasOwnPropertyNamedPropertyQuery2);
20361 Handle<Object> instance = templ->NewInstance();
20362 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20363 CHECK(instance->HasOwnProperty(v8_str("bar")));
20368 TEST(IndexedInterceptorWithStringProto) {
20369 v8::Isolate* isolate = CcTest::isolate();
20370 v8::HandleScope scope(isolate);
20371 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20372 templ->SetIndexedPropertyHandler(NULL,
20374 HasOwnPropertyIndexedPropertyQuery);
20375 LocalContext context;
20376 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20377 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20378 // These should be intercepted.
20379 CHECK(CompileRun("42 in obj")->BooleanValue());
20380 CHECK(CompileRun("'42' in obj")->BooleanValue());
20381 // These should fall through to the String prototype.
20382 CHECK(CompileRun("0 in obj")->BooleanValue());
20383 CHECK(CompileRun("'0' in obj")->BooleanValue());
20384 // And these should both fail.
20385 CHECK(!CompileRun("32 in obj")->BooleanValue());
20386 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20390 void CheckCodeGenerationAllowed() {
20391 Handle<Value> result = CompileRun("eval('42')");
20392 CHECK_EQ(42, result->Int32Value());
20393 result = CompileRun("(function(e) { return e('42'); })(eval)");
20394 CHECK_EQ(42, result->Int32Value());
20395 result = CompileRun("var f = new Function('return 42'); f()");
20396 CHECK_EQ(42, result->Int32Value());
20400 void CheckCodeGenerationDisallowed() {
20401 TryCatch try_catch;
20403 Handle<Value> result = CompileRun("eval('42')");
20404 CHECK(result.IsEmpty());
20405 CHECK(try_catch.HasCaught());
20408 result = CompileRun("(function(e) { return e('42'); })(eval)");
20409 CHECK(result.IsEmpty());
20410 CHECK(try_catch.HasCaught());
20413 result = CompileRun("var f = new Function('return 42'); f()");
20414 CHECK(result.IsEmpty());
20415 CHECK(try_catch.HasCaught());
20419 bool CodeGenerationAllowed(Local<Context> context) {
20420 ApiTestFuzzer::Fuzz();
20425 bool CodeGenerationDisallowed(Local<Context> context) {
20426 ApiTestFuzzer::Fuzz();
20431 THREADED_TEST(AllowCodeGenFromStrings) {
20432 LocalContext context;
20433 v8::HandleScope scope(context->GetIsolate());
20435 // eval and the Function constructor allowed by default.
20436 CHECK(context->IsCodeGenerationFromStringsAllowed());
20437 CheckCodeGenerationAllowed();
20439 // Disallow eval and the Function constructor.
20440 context->AllowCodeGenerationFromStrings(false);
20441 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20442 CheckCodeGenerationDisallowed();
20445 context->AllowCodeGenerationFromStrings(true);
20446 CheckCodeGenerationAllowed();
20448 // Disallow but setting a global callback that will allow the calls.
20449 context->AllowCodeGenerationFromStrings(false);
20450 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20451 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20452 CheckCodeGenerationAllowed();
20454 // Set a callback that disallows the code generation.
20455 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20456 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20457 CheckCodeGenerationDisallowed();
20461 TEST(SetErrorMessageForCodeGenFromStrings) {
20462 LocalContext context;
20463 v8::HandleScope scope(context->GetIsolate());
20464 TryCatch try_catch;
20466 Handle<String> message = v8_str("Message") ;
20467 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20468 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20469 context->AllowCodeGenerationFromStrings(false);
20470 context->SetErrorMessageForCodeGenerationFromStrings(message);
20471 Handle<Value> result = CompileRun("eval('42')");
20472 CHECK(result.IsEmpty());
20473 CHECK(try_catch.HasCaught());
20474 Handle<String> actual_message = try_catch.Message()->Get();
20475 CHECK(expected_message->Equals(actual_message));
20479 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20483 THREADED_TEST(CallAPIFunctionOnNonObject) {
20484 LocalContext context;
20485 v8::Isolate* isolate = context->GetIsolate();
20486 v8::HandleScope scope(isolate);
20487 Handle<FunctionTemplate> templ =
20488 v8::FunctionTemplate::New(isolate, NonObjectThis);
20489 Handle<Function> function = templ->GetFunction();
20490 context->Global()->Set(v8_str("f"), function);
20491 TryCatch try_catch;
20492 CompileRun("f.call(2)");
20496 // Regression test for issue 1470.
20497 THREADED_TEST(ReadOnlyIndexedProperties) {
20498 v8::Isolate* isolate = CcTest::isolate();
20499 v8::HandleScope scope(isolate);
20500 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20502 LocalContext context;
20503 Local<v8::Object> obj = templ->NewInstance();
20504 context->Global()->Set(v8_str("obj"), obj);
20505 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20506 obj->Set(v8_str("1"), v8_str("foobar"));
20507 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20508 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20509 obj->Set(v8_num(2), v8_str("foobar"));
20510 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20512 // Test non-smi case.
20513 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20514 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20515 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20519 THREADED_TEST(Regress1516) {
20520 LocalContext context;
20521 v8::HandleScope scope(context->GetIsolate());
20523 { v8::HandleScope temp_scope(context->GetIsolate());
20524 CompileRun("({'a': 0})");
20528 { i::MapCache* map_cache =
20529 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20530 elements = map_cache->NumberOfElements();
20531 CHECK_LE(1, elements);
20534 CcTest::heap()->CollectAllGarbage(
20535 i::Heap::kAbortIncrementalMarkingMask);
20536 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20537 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20538 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20539 CHECK_GT(elements, map_cache->NumberOfElements());
20545 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20547 v8::AccessType type,
20548 Local<Value> data) {
20549 // Only block read access to __proto__.
20550 if (type == v8::ACCESS_GET &&
20551 name->IsString() &&
20552 name->ToString()->Length() == 9 &&
20553 name->ToString()->Utf8Length() == 9) {
20555 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20556 return strncmp(buffer, "__proto__", 9) != 0;
20563 THREADED_TEST(Regress93759) {
20564 v8::Isolate* isolate = CcTest::isolate();
20565 HandleScope scope(isolate);
20567 // Template for object with security check.
20568 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20569 // We don't do indexing, so any callback can be used for that.
20570 no_proto_template->SetAccessCheckCallbacks(
20571 BlockProtoNamedSecurityTestCallback,
20572 IndexedSecurityTestCallback);
20574 // Templates for objects with hidden prototypes and possibly security check.
20575 Local<FunctionTemplate> hidden_proto_template =
20576 v8::FunctionTemplate::New(isolate);
20577 hidden_proto_template->SetHiddenPrototype(true);
20579 Local<FunctionTemplate> protected_hidden_proto_template =
20580 v8::FunctionTemplate::New(isolate);
20581 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20582 BlockProtoNamedSecurityTestCallback,
20583 IndexedSecurityTestCallback);
20584 protected_hidden_proto_template->SetHiddenPrototype(true);
20586 // Context for "foreign" objects used in test.
20587 Local<Context> context = v8::Context::New(isolate);
20590 // Plain object, no security check.
20591 Local<Object> simple_object = Object::New(isolate);
20593 // Object with explicit security check.
20594 Local<Object> protected_object =
20595 no_proto_template->NewInstance();
20597 // JSGlobalProxy object, always have security check.
20598 Local<Object> proxy_object =
20601 // Global object, the prototype of proxy_object. No security checks.
20602 Local<Object> global_object =
20603 proxy_object->GetPrototype()->ToObject();
20605 // Hidden prototype without security check.
20606 Local<Object> hidden_prototype =
20607 hidden_proto_template->GetFunction()->NewInstance();
20608 Local<Object> object_with_hidden =
20609 Object::New(isolate);
20610 object_with_hidden->SetPrototype(hidden_prototype);
20612 // Hidden prototype with security check on the hidden prototype.
20613 Local<Object> protected_hidden_prototype =
20614 protected_hidden_proto_template->GetFunction()->NewInstance();
20615 Local<Object> object_with_protected_hidden =
20616 Object::New(isolate);
20617 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20621 // Template for object for second context. Values to test are put on it as
20623 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20624 global_template->Set(v8_str("simple"), simple_object);
20625 global_template->Set(v8_str("protected"), protected_object);
20626 global_template->Set(v8_str("global"), global_object);
20627 global_template->Set(v8_str("proxy"), proxy_object);
20628 global_template->Set(v8_str("hidden"), object_with_hidden);
20629 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20631 LocalContext context2(NULL, global_template);
20633 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20634 CHECK(result1->Equals(simple_object->GetPrototype()));
20636 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20637 CHECK(result2.IsEmpty());
20639 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20640 CHECK(result3->Equals(global_object->GetPrototype()));
20642 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20643 CHECK(result4.IsEmpty());
20645 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20646 CHECK(result5->Equals(
20647 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20649 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20650 CHECK(result6.IsEmpty());
20654 THREADED_TEST(Regress125988) {
20655 v8::HandleScope scope(CcTest::isolate());
20656 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20657 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20659 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20660 CompileRun("var a = new Object();"
20661 "var b = new Intercept();"
20662 "var c = new Object();"
20666 "for (var i = 0; i < 3; i++) c.x;");
20667 ExpectBoolean("c.hasOwnProperty('x')", false);
20668 ExpectInt32("c.x", 23);
20669 CompileRun("a.y = 42;"
20670 "for (var i = 0; i < 3; i++) c.x;");
20671 ExpectBoolean("c.hasOwnProperty('x')", false);
20672 ExpectInt32("c.x", 23);
20673 ExpectBoolean("c.hasOwnProperty('y')", false);
20674 ExpectInt32("c.y", 42);
20678 static void TestReceiver(Local<Value> expected_result,
20679 Local<Value> expected_receiver,
20680 const char* code) {
20681 Local<Value> result = CompileRun(code);
20682 CHECK(result->IsObject());
20683 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20684 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20688 THREADED_TEST(ForeignFunctionReceiver) {
20689 v8::Isolate* isolate = CcTest::isolate();
20690 HandleScope scope(isolate);
20692 // Create two contexts with different "id" properties ('i' and 'o').
20693 // Call a function both from its own context and from a the foreign
20694 // context, and see what "this" is bound to (returning both "this"
20695 // and "this.id" for comparison).
20697 Local<Context> foreign_context = v8::Context::New(isolate);
20698 foreign_context->Enter();
20699 Local<Value> foreign_function =
20700 CompileRun("function func() { return { 0: this.id, "
20702 " toString: function() { "
20709 CHECK(foreign_function->IsFunction());
20710 foreign_context->Exit();
20712 LocalContext context;
20714 Local<String> password = v8_str("Password");
20715 // Don't get hit by security checks when accessing foreign_context's
20716 // global receiver (aka. global proxy).
20717 context->SetSecurityToken(password);
20718 foreign_context->SetSecurityToken(password);
20720 Local<String> i = v8_str("i");
20721 Local<String> o = v8_str("o");
20722 Local<String> id = v8_str("id");
20724 CompileRun("function ownfunc() { return { 0: this.id, "
20726 " toString: function() { "
20733 context->Global()->Set(v8_str("func"), foreign_function);
20735 // Sanity check the contexts.
20736 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20737 CHECK(o->Equals(context->Global()->Get(id)));
20739 // Checking local function's receiver.
20740 // Calling function using its call/apply methods.
20741 TestReceiver(o, context->Global(), "ownfunc.call()");
20742 TestReceiver(o, context->Global(), "ownfunc.apply()");
20743 // Making calls through built-in functions.
20744 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20745 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20746 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20747 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20748 // Calling with environment record as base.
20749 TestReceiver(o, context->Global(), "ownfunc()");
20750 // Calling with no base.
20751 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20753 // Checking foreign function return value.
20754 // Calling function using its call/apply methods.
20755 TestReceiver(i, foreign_context->Global(), "func.call()");
20756 TestReceiver(i, foreign_context->Global(), "func.apply()");
20757 // Calling function using another context's call/apply methods.
20758 TestReceiver(i, foreign_context->Global(),
20759 "Function.prototype.call.call(func)");
20760 TestReceiver(i, foreign_context->Global(),
20761 "Function.prototype.call.apply(func)");
20762 TestReceiver(i, foreign_context->Global(),
20763 "Function.prototype.apply.call(func)");
20764 TestReceiver(i, foreign_context->Global(),
20765 "Function.prototype.apply.apply(func)");
20766 // Making calls through built-in functions.
20767 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20768 // ToString(func()) is func()[0], i.e., the returned this.id.
20769 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20770 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20771 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20773 // Calling with environment record as base.
20774 TestReceiver(i, foreign_context->Global(), "func()");
20775 // Calling with no base.
20776 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20780 uint8_t callback_fired = 0;
20783 void CallCompletedCallback1() {
20784 v8::base::OS::Print("Firing callback 1.\n");
20785 callback_fired ^= 1; // Toggle first bit.
20789 void CallCompletedCallback2() {
20790 v8::base::OS::Print("Firing callback 2.\n");
20791 callback_fired ^= 2; // Toggle second bit.
20795 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20796 int32_t level = args[0]->Int32Value();
20799 v8::base::OS::Print("Entering recursion level %d.\n", level);
20801 i::Vector<char> script_vector(script, sizeof(script));
20802 i::SNPrintF(script_vector, "recursion(%d)", level);
20803 CompileRun(script_vector.start());
20804 v8::base::OS::Print("Leaving recursion level %d.\n", level);
20805 CHECK_EQ(0, callback_fired);
20807 v8::base::OS::Print("Recursion ends.\n");
20808 CHECK_EQ(0, callback_fired);
20813 TEST(CallCompletedCallback) {
20815 v8::HandleScope scope(env->GetIsolate());
20816 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20817 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20818 env->Global()->Set(v8_str("recursion"),
20819 recursive_runtime->GetFunction());
20820 // Adding the same callback a second time has no effect.
20821 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20822 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20823 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20824 v8::base::OS::Print("--- Script (1) ---\n");
20825 Local<Script> script = v8::Script::Compile(
20826 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20828 CHECK_EQ(3, callback_fired);
20830 v8::base::OS::Print("\n--- Script (2) ---\n");
20831 callback_fired = 0;
20832 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20834 CHECK_EQ(2, callback_fired);
20836 v8::base::OS::Print("\n--- Function ---\n");
20837 callback_fired = 0;
20838 Local<Function> recursive_function =
20839 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20840 v8::Handle<Value> args[] = { v8_num(0) };
20841 recursive_function->Call(env->Global(), 1, args);
20842 CHECK_EQ(2, callback_fired);
20846 void CallCompletedCallbackNoException() {
20847 v8::HandleScope scope(CcTest::isolate());
20848 CompileRun("1+1;");
20852 void CallCompletedCallbackException() {
20853 v8::HandleScope scope(CcTest::isolate());
20854 CompileRun("throw 'second exception';");
20858 TEST(CallCompletedCallbackOneException) {
20860 v8::HandleScope scope(env->GetIsolate());
20861 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20862 CompileRun("throw 'exception';");
20866 TEST(CallCompletedCallbackTwoExceptions) {
20868 v8::HandleScope scope(env->GetIsolate());
20869 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20870 CompileRun("throw 'first exception';");
20874 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20875 v8::HandleScope scope(info.GetIsolate());
20876 CompileRun("ext1Calls++;");
20880 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20881 v8::HandleScope scope(info.GetIsolate());
20882 CompileRun("ext2Calls++;");
20886 void* g_passed_to_three = NULL;
20889 static void MicrotaskThree(void* data) {
20890 g_passed_to_three = data;
20894 TEST(EnqueueMicrotask) {
20896 v8::HandleScope scope(env->GetIsolate());
20898 "var ext1Calls = 0;"
20899 "var ext2Calls = 0;");
20900 CompileRun("1+1;");
20901 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20902 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20904 env->GetIsolate()->EnqueueMicrotask(
20905 Function::New(env->GetIsolate(), MicrotaskOne));
20906 CompileRun("1+1;");
20907 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20908 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20910 env->GetIsolate()->EnqueueMicrotask(
20911 Function::New(env->GetIsolate(), MicrotaskOne));
20912 env->GetIsolate()->EnqueueMicrotask(
20913 Function::New(env->GetIsolate(), MicrotaskTwo));
20914 CompileRun("1+1;");
20915 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20916 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20918 env->GetIsolate()->EnqueueMicrotask(
20919 Function::New(env->GetIsolate(), MicrotaskTwo));
20920 CompileRun("1+1;");
20921 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20922 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20924 CompileRun("1+1;");
20925 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20926 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20928 g_passed_to_three = NULL;
20929 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20930 CompileRun("1+1;");
20931 CHECK_EQ(NULL, g_passed_to_three);
20932 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20933 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20936 env->GetIsolate()->EnqueueMicrotask(
20937 Function::New(env->GetIsolate(), MicrotaskOne));
20938 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20939 env->GetIsolate()->EnqueueMicrotask(
20940 Function::New(env->GetIsolate(), MicrotaskTwo));
20941 CompileRun("1+1;");
20942 CHECK_EQ(&dummy, g_passed_to_three);
20943 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20944 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20945 g_passed_to_three = NULL;
20949 static void MicrotaskExceptionOne(
20950 const v8::FunctionCallbackInfo<Value>& info) {
20951 v8::HandleScope scope(info.GetIsolate());
20952 CompileRun("exception1Calls++;");
20953 info.GetIsolate()->ThrowException(
20954 v8::Exception::Error(v8_str("first")));
20958 static void MicrotaskExceptionTwo(
20959 const v8::FunctionCallbackInfo<Value>& info) {
20960 v8::HandleScope scope(info.GetIsolate());
20961 CompileRun("exception2Calls++;");
20962 info.GetIsolate()->ThrowException(
20963 v8::Exception::Error(v8_str("second")));
20967 TEST(RunMicrotasksIgnoresThrownExceptions) {
20969 v8::Isolate* isolate = env->GetIsolate();
20970 v8::HandleScope scope(isolate);
20972 "var exception1Calls = 0;"
20973 "var exception2Calls = 0;");
20974 isolate->EnqueueMicrotask(
20975 Function::New(isolate, MicrotaskExceptionOne));
20976 isolate->EnqueueMicrotask(
20977 Function::New(isolate, MicrotaskExceptionTwo));
20978 TryCatch try_catch;
20979 CompileRun("1+1;");
20980 CHECK(!try_catch.HasCaught());
20981 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20982 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20986 TEST(SetAutorunMicrotasks) {
20988 v8::HandleScope scope(env->GetIsolate());
20990 "var ext1Calls = 0;"
20991 "var ext2Calls = 0;");
20992 CompileRun("1+1;");
20993 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20994 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20996 env->GetIsolate()->EnqueueMicrotask(
20997 Function::New(env->GetIsolate(), MicrotaskOne));
20998 CompileRun("1+1;");
20999 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21000 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21002 env->GetIsolate()->SetAutorunMicrotasks(false);
21003 env->GetIsolate()->EnqueueMicrotask(
21004 Function::New(env->GetIsolate(), MicrotaskOne));
21005 env->GetIsolate()->EnqueueMicrotask(
21006 Function::New(env->GetIsolate(), MicrotaskTwo));
21007 CompileRun("1+1;");
21008 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21009 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21011 env->GetIsolate()->RunMicrotasks();
21012 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21013 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21015 env->GetIsolate()->EnqueueMicrotask(
21016 Function::New(env->GetIsolate(), MicrotaskTwo));
21017 CompileRun("1+1;");
21018 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21019 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21021 env->GetIsolate()->RunMicrotasks();
21022 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21023 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21025 env->GetIsolate()->SetAutorunMicrotasks(true);
21026 env->GetIsolate()->EnqueueMicrotask(
21027 Function::New(env->GetIsolate(), MicrotaskTwo));
21028 CompileRun("1+1;");
21029 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21030 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21032 env->GetIsolate()->EnqueueMicrotask(
21033 Function::New(env->GetIsolate(), MicrotaskTwo));
21035 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21036 CompileRun("1+1;");
21037 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21038 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21041 CompileRun("1+1;");
21042 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21043 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
21047 TEST(RunMicrotasksWithoutEnteringContext) {
21048 v8::Isolate* isolate = CcTest::isolate();
21049 HandleScope handle_scope(isolate);
21050 isolate->SetAutorunMicrotasks(false);
21051 Handle<Context> context = Context::New(isolate);
21053 Context::Scope context_scope(context);
21054 CompileRun("var ext1Calls = 0;");
21055 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
21057 isolate->RunMicrotasks();
21059 Context::Scope context_scope(context);
21060 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21062 isolate->SetAutorunMicrotasks(true);
21066 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
21067 v8::DebugEvent event = event_details.GetEvent();
21068 if (event != v8::Break) return;
21069 Handle<Object> exec_state = event_details.GetExecutionState();
21070 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
21071 CompileRun("function f(id) { new FrameDetails(id, 0); }");
21072 Handle<Function> fun = Handle<Function>::Cast(
21073 CcTest::global()->Get(v8_str("f"))->ToObject());
21074 fun->Call(CcTest::global(), 1, &break_id);
21078 TEST(Regress385349) {
21079 i::FLAG_allow_natives_syntax = true;
21080 v8::Isolate* isolate = CcTest::isolate();
21081 HandleScope handle_scope(isolate);
21082 isolate->SetAutorunMicrotasks(false);
21083 Handle<Context> context = Context::New(isolate);
21084 v8::Debug::SetDebugEventListener(DebugEventInObserver);
21086 Context::Scope context_scope(context);
21087 CompileRun("var obj = {};"
21088 "Object.observe(obj, function(changes) { debugger; });"
21091 isolate->RunMicrotasks();
21092 isolate->SetAutorunMicrotasks(true);
21093 v8::Debug::SetDebugEventListener(NULL);
21098 static int probes_counter = 0;
21099 static int misses_counter = 0;
21100 static int updates_counter = 0;
21103 static int* LookupCounter(const char* name) {
21104 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21105 return &probes_counter;
21106 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21107 return &misses_counter;
21108 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21109 return &updates_counter;
21115 static const char* kMegamorphicTestProgram =
21116 "function ClassA() { };"
21117 "function ClassB() { };"
21118 "ClassA.prototype.foo = function() { };"
21119 "ClassB.prototype.foo = function() { };"
21120 "function fooify(obj) { obj.foo(); };"
21121 "var a = new ClassA();"
21122 "var b = new ClassB();"
21123 "for (var i = 0; i < 10000; i++) {"
21130 static void StubCacheHelper(bool primary) {
21132 i::FLAG_native_code_counters = true;
21134 i::FLAG_test_primary_stub_cache = true;
21136 i::FLAG_test_secondary_stub_cache = true;
21138 i::FLAG_crankshaft = false;
21140 env->GetIsolate()->SetCounterFunction(LookupCounter);
21141 v8::HandleScope scope(env->GetIsolate());
21142 int initial_probes = probes_counter;
21143 int initial_misses = misses_counter;
21144 int initial_updates = updates_counter;
21145 CompileRun(kMegamorphicTestProgram);
21146 int probes = probes_counter - initial_probes;
21147 int misses = misses_counter - initial_misses;
21148 int updates = updates_counter - initial_updates;
21149 CHECK_LT(updates, 10);
21150 CHECK_LT(misses, 10);
21151 // TODO(verwaest): Update this test to overflow the degree of polymorphism
21152 // before megamorphism. The number of probes will only work once we teach the
21153 // serializer to embed references to counters in the stubs, given that the
21154 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21155 CHECK_GE(probes, 0);
21160 TEST(SecondaryStubCache) {
21161 StubCacheHelper(true);
21165 TEST(PrimaryStubCache) {
21166 StubCacheHelper(false);
21171 static int cow_arrays_created_runtime = 0;
21174 static int* LookupCounterCOWArrays(const char* name) {
21175 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21176 return &cow_arrays_created_runtime;
21183 TEST(CheckCOWArraysCreatedRuntimeCounter) {
21185 i::FLAG_native_code_counters = true;
21187 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21188 v8::HandleScope scope(env->GetIsolate());
21189 int initial_cow_arrays = cow_arrays_created_runtime;
21190 CompileRun("var o = [1, 2, 3];");
21191 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21192 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21193 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21194 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21195 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21200 TEST(StaticGetters) {
21201 LocalContext context;
21202 i::Factory* factory = CcTest::i_isolate()->factory();
21203 v8::Isolate* isolate = CcTest::isolate();
21204 v8::HandleScope scope(isolate);
21205 i::Handle<i::Object> undefined_value = factory->undefined_value();
21206 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21207 i::Handle<i::Object> null_value = factory->null_value();
21208 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21209 i::Handle<i::Object> true_value = factory->true_value();
21210 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21211 i::Handle<i::Object> false_value = factory->false_value();
21212 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21216 UNINITIALIZED_TEST(IsolateEmbedderData) {
21217 CcTest::DisableAutomaticDispose();
21218 v8::Isolate* isolate = v8::Isolate::New();
21220 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21221 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21222 CHECK_EQ(NULL, isolate->GetData(slot));
21223 CHECK_EQ(NULL, i_isolate->GetData(slot));
21225 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21226 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21227 isolate->SetData(slot, data);
21229 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21230 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21231 CHECK_EQ(data, isolate->GetData(slot));
21232 CHECK_EQ(data, i_isolate->GetData(slot));
21234 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21235 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21236 isolate->SetData(slot, data);
21238 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21239 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21240 CHECK_EQ(data, isolate->GetData(slot));
21241 CHECK_EQ(data, i_isolate->GetData(slot));
21244 isolate->Dispose();
21248 TEST(StringEmpty) {
21249 LocalContext context;
21250 i::Factory* factory = CcTest::i_isolate()->factory();
21251 v8::Isolate* isolate = CcTest::isolate();
21252 v8::HandleScope scope(isolate);
21253 i::Handle<i::Object> empty_string = factory->empty_string();
21254 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21258 static int instance_checked_getter_count = 0;
21259 static void InstanceCheckedGetter(
21260 Local<String> name,
21261 const v8::PropertyCallbackInfo<v8::Value>& info) {
21262 CHECK_EQ(name, v8_str("foo"));
21263 instance_checked_getter_count++;
21264 info.GetReturnValue().Set(v8_num(11));
21268 static int instance_checked_setter_count = 0;
21269 static void InstanceCheckedSetter(Local<String> name,
21270 Local<Value> value,
21271 const v8::PropertyCallbackInfo<void>& info) {
21272 CHECK_EQ(name, v8_str("foo"));
21273 CHECK_EQ(value, v8_num(23));
21274 instance_checked_setter_count++;
21278 static void CheckInstanceCheckedResult(int getters, int setters,
21279 bool expects_callbacks,
21280 TryCatch* try_catch) {
21281 if (expects_callbacks) {
21282 CHECK(!try_catch->HasCaught());
21283 CHECK_EQ(getters, instance_checked_getter_count);
21284 CHECK_EQ(setters, instance_checked_setter_count);
21286 CHECK(try_catch->HasCaught());
21287 CHECK_EQ(0, instance_checked_getter_count);
21288 CHECK_EQ(0, instance_checked_setter_count);
21290 try_catch->Reset();
21294 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21295 instance_checked_getter_count = 0;
21296 instance_checked_setter_count = 0;
21297 TryCatch try_catch;
21299 // Test path through generic runtime code.
21300 CompileRun("obj.foo");
21301 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21302 CompileRun("obj.foo = 23");
21303 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21305 // Test path through generated LoadIC and StoredIC.
21306 CompileRun("function test_get(o) { o.foo; }"
21308 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21309 CompileRun("test_get(obj);");
21310 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21311 CompileRun("test_get(obj);");
21312 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21313 CompileRun("function test_set(o) { o.foo = 23; }"
21315 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21316 CompileRun("test_set(obj);");
21317 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21318 CompileRun("test_set(obj);");
21319 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21321 // Test path through optimized code.
21322 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21324 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21325 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21327 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21329 // Cleanup so that closures start out fresh in next check.
21330 CompileRun("%DeoptimizeFunction(test_get);"
21331 "%ClearFunctionTypeFeedback(test_get);"
21332 "%DeoptimizeFunction(test_set);"
21333 "%ClearFunctionTypeFeedback(test_set);");
21337 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21338 v8::internal::FLAG_allow_natives_syntax = true;
21339 LocalContext context;
21340 v8::HandleScope scope(context->GetIsolate());
21342 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21343 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21344 inst->SetAccessor(v8_str("foo"),
21345 InstanceCheckedGetter, InstanceCheckedSetter,
21349 v8::AccessorSignature::New(context->GetIsolate(), templ));
21350 context->Global()->Set(v8_str("f"), templ->GetFunction());
21352 printf("Testing positive ...\n");
21353 CompileRun("var obj = new f();");
21354 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21355 CheckInstanceCheckedAccessors(true);
21357 printf("Testing negative ...\n");
21358 CompileRun("var obj = {};"
21359 "obj.__proto__ = new f();");
21360 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21361 CheckInstanceCheckedAccessors(false);
21365 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21366 v8::internal::FLAG_allow_natives_syntax = true;
21367 LocalContext context;
21368 v8::HandleScope scope(context->GetIsolate());
21370 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21371 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21372 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21373 inst->SetAccessor(v8_str("foo"),
21374 InstanceCheckedGetter, InstanceCheckedSetter,
21378 v8::AccessorSignature::New(context->GetIsolate(), templ));
21379 context->Global()->Set(v8_str("f"), templ->GetFunction());
21381 printf("Testing positive ...\n");
21382 CompileRun("var obj = new f();");
21383 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21384 CheckInstanceCheckedAccessors(true);
21386 printf("Testing negative ...\n");
21387 CompileRun("var obj = {};"
21388 "obj.__proto__ = new f();");
21389 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21390 CheckInstanceCheckedAccessors(false);
21394 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21395 v8::internal::FLAG_allow_natives_syntax = true;
21396 LocalContext context;
21397 v8::HandleScope scope(context->GetIsolate());
21399 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21400 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21401 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21402 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21404 v8::AccessorSignature::New(context->GetIsolate(), templ));
21405 context->Global()->Set(v8_str("f"), templ->GetFunction());
21407 printf("Testing positive ...\n");
21408 CompileRun("var obj = new f();");
21409 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21410 CheckInstanceCheckedAccessors(true);
21412 printf("Testing negative ...\n");
21413 CompileRun("var obj = {};"
21414 "obj.__proto__ = new f();");
21415 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21416 CheckInstanceCheckedAccessors(false);
21418 printf("Testing positive with modified prototype chain ...\n");
21419 CompileRun("var obj = new f();"
21421 "pro.__proto__ = obj.__proto__;"
21422 "obj.__proto__ = pro;");
21423 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21424 CheckInstanceCheckedAccessors(true);
21428 TEST(TryFinallyMessage) {
21429 LocalContext context;
21430 v8::HandleScope scope(context->GetIsolate());
21432 // Test that the original error message is not lost if there is a
21433 // recursive call into Javascript is done in the finally block, e.g. to
21434 // initialize an IC. (crbug.com/129171)
21435 TryCatch try_catch;
21436 const char* trigger_ic =
21438 " throw new Error('test'); \n"
21441 " x++; \n" // Trigger an IC initialization here.
21443 CompileRun(trigger_ic);
21444 CHECK(try_catch.HasCaught());
21445 Local<Message> message = try_catch.Message();
21446 CHECK(!message.IsEmpty());
21447 CHECK_EQ(2, message->GetLineNumber());
21451 // Test that the original exception message is indeed overwritten if
21452 // a new error is thrown in the finally block.
21453 TryCatch try_catch;
21454 const char* throw_again =
21456 " throw new Error('test'); \n"
21460 " throw new Error('again'); \n" // This is the new uncaught error.
21462 CompileRun(throw_again);
21463 CHECK(try_catch.HasCaught());
21464 Local<Message> message = try_catch.Message();
21465 CHECK(!message.IsEmpty());
21466 CHECK_EQ(6, message->GetLineNumber());
21471 static void Helper137002(bool do_store,
21473 bool remove_accessor,
21474 bool interceptor) {
21475 LocalContext context;
21476 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21478 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21480 templ->SetAccessor(v8_str("foo"),
21481 GetterWhichReturns42,
21482 SetterWhichSetsYOnThisTo23);
21484 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21486 // Turn monomorphic on slow object with native accessor, then turn
21487 // polymorphic, finally optimize to create negative lookup and fail.
21488 CompileRun(do_store ?
21489 "function f(x) { x.foo = void 0; }" :
21490 "function f(x) { return x.foo; }");
21491 CompileRun("obj.y = void 0;");
21492 if (!interceptor) {
21493 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21495 CompileRun("obj.__proto__ = null;"
21496 "f(obj); f(obj); f(obj);");
21498 CompileRun("f({});");
21500 CompileRun("obj.y = void 0;"
21501 "%OptimizeFunctionOnNextCall(f);");
21502 if (remove_accessor) {
21503 CompileRun("delete obj.foo;");
21505 CompileRun("var result = f(obj);");
21507 CompileRun("result = obj.y;");
21509 if (remove_accessor && !interceptor) {
21510 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21512 CHECK_EQ(do_store ? 23 : 42,
21513 context->Global()->Get(v8_str("result"))->Int32Value());
21518 THREADED_TEST(Regress137002a) {
21519 i::FLAG_allow_natives_syntax = true;
21520 i::FLAG_compilation_cache = false;
21521 v8::HandleScope scope(CcTest::isolate());
21522 for (int i = 0; i < 16; i++) {
21523 Helper137002(i & 8, i & 4, i & 2, i & 1);
21528 THREADED_TEST(Regress137002b) {
21529 i::FLAG_allow_natives_syntax = true;
21530 LocalContext context;
21531 v8::Isolate* isolate = context->GetIsolate();
21532 v8::HandleScope scope(isolate);
21533 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21534 templ->SetAccessor(v8_str("foo"),
21535 GetterWhichReturns42,
21536 SetterWhichSetsYOnThisTo23);
21537 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21539 // Turn monomorphic on slow object with native accessor, then just
21540 // delete the property and fail.
21541 CompileRun("function load(x) { return x.foo; }"
21542 "function store(x) { x.foo = void 0; }"
21543 "function keyed_load(x, key) { return x[key]; }"
21544 // Second version of function has a different source (add void 0)
21545 // so that it does not share code with the first version. This
21546 // ensures that the ICs are monomorphic.
21547 "function load2(x) { void 0; return x.foo; }"
21548 "function store2(x) { void 0; x.foo = void 0; }"
21549 "function keyed_load2(x, key) { void 0; return x[key]; }"
21552 "obj.__proto__ = null;"
21554 "subobj.y = void 0;"
21555 "subobj.__proto__ = obj;"
21556 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21558 // Make the ICs monomorphic.
21559 "load(obj); load(obj);"
21560 "load2(subobj); load2(subobj);"
21561 "store(obj); store(obj);"
21562 "store2(subobj); store2(subobj);"
21563 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21564 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21566 // Actually test the shiny new ICs and better not crash. This
21567 // serves as a regression test for issue 142088 as well.
21572 "keyed_load(obj, 'foo');"
21573 "keyed_load2(subobj, 'foo');"
21575 // Delete the accessor. It better not be called any more now.
21578 "subobj.y = void 0;"
21580 "var load_result = load(obj);"
21581 "var load_result2 = load2(subobj);"
21582 "var keyed_load_result = keyed_load(obj, 'foo');"
21583 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21586 "var y_from_obj = obj.y;"
21587 "var y_from_subobj = subobj.y;");
21588 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21589 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21590 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21591 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21592 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21593 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21597 THREADED_TEST(Regress142088) {
21598 i::FLAG_allow_natives_syntax = true;
21599 LocalContext context;
21600 v8::Isolate* isolate = context->GetIsolate();
21601 v8::HandleScope scope(isolate);
21602 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21603 templ->SetAccessor(v8_str("foo"),
21604 GetterWhichReturns42,
21605 SetterWhichSetsYOnThisTo23);
21606 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21608 CompileRun("function load(x) { return x.foo; }"
21609 "var o = Object.create(obj);"
21610 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21611 "load(o); load(o); load(o); load(o);");
21615 THREADED_TEST(Regress3337) {
21616 LocalContext context;
21617 v8::Isolate* isolate = context->GetIsolate();
21618 v8::HandleScope scope(isolate);
21619 Local<v8::Object> o1 = Object::New(isolate);
21620 Local<v8::Object> o2 = Object::New(isolate);
21621 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21622 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21623 CHECK(io1->map() == io2->map());
21624 o1->SetIndexedPropertiesToExternalArrayData(
21625 NULL, v8::kExternalUint32Array, 0);
21626 o2->SetIndexedPropertiesToExternalArrayData(
21627 NULL, v8::kExternalUint32Array, 0);
21628 CHECK(io1->map() == io2->map());
21632 THREADED_TEST(Regress137496) {
21633 i::FLAG_expose_gc = true;
21634 LocalContext context;
21635 v8::HandleScope scope(context->GetIsolate());
21637 // Compile a try-finally clause where the finally block causes a GC
21638 // while there still is a message pending for external reporting.
21639 TryCatch try_catch;
21640 try_catch.SetVerbose(true);
21641 CompileRun("try { throw new Error(); } finally { gc(); }");
21642 CHECK(try_catch.HasCaught());
21646 THREADED_TEST(Regress149912) {
21647 LocalContext context;
21648 v8::HandleScope scope(context->GetIsolate());
21649 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21650 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21651 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21652 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21656 THREADED_TEST(Regress157124) {
21657 LocalContext context;
21658 v8::Isolate* isolate = context->GetIsolate();
21659 v8::HandleScope scope(isolate);
21660 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21661 Local<Object> obj = templ->NewInstance();
21662 obj->GetIdentityHash();
21663 obj->DeleteHiddenValue(v8_str("Bug"));
21667 THREADED_TEST(Regress2535) {
21668 LocalContext context;
21669 v8::HandleScope scope(context->GetIsolate());
21670 Local<Value> set_value = CompileRun("new Set();");
21671 Local<Object> set_object(Local<Object>::Cast(set_value));
21672 CHECK_EQ(0, set_object->InternalFieldCount());
21673 Local<Value> map_value = CompileRun("new Map();");
21674 Local<Object> map_object(Local<Object>::Cast(map_value));
21675 CHECK_EQ(0, map_object->InternalFieldCount());
21679 THREADED_TEST(Regress2746) {
21680 LocalContext context;
21681 v8::Isolate* isolate = context->GetIsolate();
21682 v8::HandleScope scope(isolate);
21683 Local<Object> obj = Object::New(isolate);
21684 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21685 obj->SetHiddenValue(key, v8::Undefined(isolate));
21686 Local<Value> value = obj->GetHiddenValue(key);
21687 CHECK(!value.IsEmpty());
21688 CHECK(value->IsUndefined());
21692 THREADED_TEST(Regress260106) {
21693 LocalContext context;
21694 v8::Isolate* isolate = context->GetIsolate();
21695 v8::HandleScope scope(isolate);
21696 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21698 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21699 Local<Function> function = templ->GetFunction();
21700 CHECK(!function.IsEmpty());
21701 CHECK(function->IsFunction());
21705 THREADED_TEST(JSONParseObject) {
21706 LocalContext context;
21707 HandleScope scope(context->GetIsolate());
21708 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21709 Handle<Object> global = context->Global();
21710 global->Set(v8_str("obj"), obj);
21711 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21715 THREADED_TEST(JSONParseNumber) {
21716 LocalContext context;
21717 HandleScope scope(context->GetIsolate());
21718 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21719 Handle<Object> global = context->Global();
21720 global->Set(v8_str("obj"), obj);
21721 ExpectString("JSON.stringify(obj)", "42");
21725 #if V8_OS_POSIX && !V8_OS_NACL
21726 class ThreadInterruptTest {
21728 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21729 ~ThreadInterruptTest() {}
21732 InterruptThread i_thread(this);
21736 CHECK_EQ(kExpectedValue, sem_value_);
21740 static const int kExpectedValue = 1;
21742 class InterruptThread : public v8::base::Thread {
21744 explicit InterruptThread(ThreadInterruptTest* test)
21745 : Thread(Options("InterruptThread")), test_(test) {}
21747 virtual void Run() {
21748 struct sigaction action;
21750 // Ensure that we'll enter waiting condition
21751 v8::base::OS::Sleep(100);
21753 // Setup signal handler
21754 memset(&action, 0, sizeof(action));
21755 action.sa_handler = SignalHandler;
21756 sigaction(SIGCHLD, &action, NULL);
21759 kill(getpid(), SIGCHLD);
21761 // Ensure that if wait has returned because of error
21762 v8::base::OS::Sleep(100);
21764 // Set value and signal semaphore
21765 test_->sem_value_ = 1;
21766 test_->sem_.Signal();
21769 static void SignalHandler(int signal) {
21773 ThreadInterruptTest* test_;
21776 v8::base::Semaphore sem_;
21777 volatile int sem_value_;
21781 THREADED_TEST(SemaphoreInterruption) {
21782 ThreadInterruptTest().RunTest();
21786 #endif // V8_OS_POSIX
21789 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21791 v8::AccessType type,
21792 Local<Value> data) {
21793 i::PrintF("Named access blocked.\n");
21798 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21800 v8::AccessType type,
21801 Local<Value> data) {
21802 i::PrintF("Indexed access blocked.\n");
21807 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21812 TEST(JSONStringifyAccessCheck) {
21813 v8::V8::Initialize();
21814 v8::Isolate* isolate = CcTest::isolate();
21815 v8::HandleScope scope(isolate);
21817 // Create an ObjectTemplate for global objects and install access
21818 // check callbacks that will block access.
21819 v8::Handle<v8::ObjectTemplate> global_template =
21820 v8::ObjectTemplate::New(isolate);
21821 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21822 IndexAccessAlwaysBlocked);
21824 // Create a context and set an x property on it's global object.
21825 LocalContext context0(NULL, global_template);
21826 v8::Handle<v8::Object> global0 = context0->Global();
21827 global0->Set(v8_str("x"), v8_num(42));
21828 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21830 for (int i = 0; i < 2; i++) {
21832 // Install a toJSON function on the second run.
21833 v8::Handle<v8::FunctionTemplate> toJSON =
21834 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21836 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21838 // Create a context with a different security token so that the
21839 // failed access check callback will be called on each access.
21840 LocalContext context1(NULL, global_template);
21841 context1->Global()->Set(v8_str("other"), global0);
21843 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21844 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21845 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21847 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21848 array->Set(0, v8_str("a"));
21849 array->Set(1, v8_str("b"));
21850 context1->Global()->Set(v8_str("array"), array);
21851 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21852 array->TurnOnAccessCheck();
21853 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21854 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21855 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21860 bool access_check_fail_thrown = false;
21861 bool catch_callback_called = false;
21864 // Failed access check callback that performs a GC on each invocation.
21865 void FailedAccessCheckThrows(Local<v8::Object> target,
21866 v8::AccessType type,
21867 Local<v8::Value> data) {
21868 access_check_fail_thrown = true;
21869 i::PrintF("Access check failed. Error thrown.\n");
21870 CcTest::isolate()->ThrowException(
21871 v8::Exception::Error(v8_str("cross context")));
21875 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21876 for (int i = 0; i < args.Length(); i++) {
21877 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21879 catch_callback_called = true;
21883 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21884 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21888 void CheckCorrectThrow(const char* script) {
21889 // Test that the script, when wrapped into a try-catch, triggers the catch
21890 // clause due to failed access check throwing an exception.
21891 // The subsequent try-catch should run without any exception.
21892 access_check_fail_thrown = false;
21893 catch_callback_called = false;
21894 i::ScopedVector<char> source(1024);
21895 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21896 CompileRun(source.start());
21897 CHECK(access_check_fail_thrown);
21898 CHECK(catch_callback_called);
21900 access_check_fail_thrown = false;
21901 catch_callback_called = false;
21902 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21903 CHECK(!access_check_fail_thrown);
21904 CHECK(!catch_callback_called);
21908 TEST(AccessCheckThrows) {
21909 i::FLAG_allow_natives_syntax = true;
21910 v8::V8::Initialize();
21911 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21912 v8::Isolate* isolate = CcTest::isolate();
21913 v8::HandleScope scope(isolate);
21915 // Create an ObjectTemplate for global objects and install access
21916 // check callbacks that will block access.
21917 v8::Handle<v8::ObjectTemplate> global_template =
21918 v8::ObjectTemplate::New(isolate);
21919 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21920 IndexAccessAlwaysBlocked);
21922 // Create a context and set an x property on it's global object.
21923 LocalContext context0(NULL, global_template);
21924 v8::Handle<v8::Object> global0 = context0->Global();
21926 // Create a context with a different security token so that the
21927 // failed access check callback will be called on each access.
21928 LocalContext context1(NULL, global_template);
21929 context1->Global()->Set(v8_str("other"), global0);
21931 v8::Handle<v8::FunctionTemplate> catcher_fun =
21932 v8::FunctionTemplate::New(isolate, CatcherCallback);
21933 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21935 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21936 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21937 context1->Global()->Set(v8_str("has_own_property"),
21938 has_own_property_fun->GetFunction());
21940 { v8::TryCatch try_catch;
21941 access_check_fail_thrown = false;
21942 CompileRun("other.x;");
21943 CHECK(access_check_fail_thrown);
21944 CHECK(try_catch.HasCaught());
21947 CheckCorrectThrow("other.x");
21948 CheckCorrectThrow("other[1]");
21949 CheckCorrectThrow("JSON.stringify(other)");
21950 CheckCorrectThrow("has_own_property(other, 'x')");
21951 CheckCorrectThrow("%GetProperty(other, 'x')");
21952 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21953 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21954 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21955 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21956 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21957 CheckCorrectThrow("%HasProperty(other, 'x')");
21958 CheckCorrectThrow("%HasElement(other, 1)");
21959 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21960 CheckCorrectThrow("%GetPropertyNames(other)");
21961 // PROPERTY_ATTRIBUTES_NONE = 0
21962 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21963 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21964 "other, 'x', null, null, 1)");
21966 // Reset the failed access check callback so it does not influence
21967 // the other tests.
21968 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21972 THREADED_TEST(Regress256330) {
21973 i::FLAG_allow_natives_syntax = true;
21974 LocalContext context;
21975 v8::HandleScope scope(context->GetIsolate());
21976 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21977 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21978 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21979 CompileRun("\"use strict\"; var o = new Bug;"
21980 "function f(o) { o.x = 10; };"
21981 "f(o); f(o); f(o);"
21982 "%OptimizeFunctionOnNextCall(f);"
21984 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21988 THREADED_TEST(CrankshaftInterceptorSetter) {
21989 i::FLAG_allow_natives_syntax = true;
21990 v8::HandleScope scope(CcTest::isolate());
21991 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21992 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21994 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21995 CompileRun("var obj = new Obj;"
21996 // Initialize fields to avoid transitions later.
21998 "obj.accessor_age = 42;"
21999 "function setter(i) { this.accessor_age = i; };"
22000 "function getter() { return this.accessor_age; };"
22001 "function setAge(i) { obj.age = i; };"
22002 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
22006 "%OptimizeFunctionOnNextCall(setAge);"
22008 // All stores went through the interceptor.
22009 ExpectInt32("obj.interceptor_age", 4);
22010 ExpectInt32("obj.accessor_age", 42);
22014 THREADED_TEST(CrankshaftInterceptorGetter) {
22015 i::FLAG_allow_natives_syntax = true;
22016 v8::HandleScope scope(CcTest::isolate());
22017 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22018 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22020 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22021 CompileRun("var obj = new Obj;"
22022 // Initialize fields to avoid transitions later.
22024 "obj.accessor_age = 42;"
22025 "function getter() { return this.accessor_age; };"
22026 "function getAge() { return obj.interceptor_age; };"
22027 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
22031 "%OptimizeFunctionOnNextCall(getAge);");
22032 // Access through interceptor.
22033 ExpectInt32("getAge()", 1);
22037 THREADED_TEST(CrankshaftInterceptorFieldRead) {
22038 i::FLAG_allow_natives_syntax = true;
22039 v8::HandleScope scope(CcTest::isolate());
22040 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22041 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22043 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22044 CompileRun("var obj = new Obj;"
22045 "obj.__proto__.interceptor_age = 42;"
22047 "function getAge() { return obj.interceptor_age; };");
22048 ExpectInt32("getAge();", 100);
22049 ExpectInt32("getAge();", 100);
22050 ExpectInt32("getAge();", 100);
22051 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
22052 // Access through interceptor.
22053 ExpectInt32("getAge();", 100);
22057 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
22058 i::FLAG_allow_natives_syntax = true;
22059 v8::HandleScope scope(CcTest::isolate());
22060 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22061 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22063 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22064 CompileRun("var obj = new Obj;"
22065 "obj.age = 100000;"
22066 "function setAge(i) { obj.age = i };"
22070 "%OptimizeFunctionOnNextCall(setAge);"
22072 ExpectInt32("obj.age", 100000);
22073 ExpectInt32("obj.interceptor_age", 103);
22077 class RequestInterruptTestBase {
22079 RequestInterruptTestBase()
22081 isolate_(env_->GetIsolate()),
22084 should_continue_(true) {
22087 virtual ~RequestInterruptTestBase() { }
22089 virtual void StartInterruptThread() = 0;
22091 virtual void TestBody() = 0;
22094 StartInterruptThread();
22096 v8::HandleScope handle_scope(isolate_);
22100 isolate_->ClearInterrupt();
22102 // Verify we arrived here because interruptor was called
22103 // not due to a bug causing us to exit the loop too early.
22104 CHECK(!should_continue());
22107 void WakeUpInterruptor() {
22111 bool should_continue() const { return should_continue_; }
22113 bool ShouldContinue() {
22115 if (--warmup_ == 0) {
22116 WakeUpInterruptor();
22120 return should_continue_;
22123 static void ShouldContinueCallback(
22124 const v8::FunctionCallbackInfo<Value>& info) {
22125 RequestInterruptTestBase* test =
22126 reinterpret_cast<RequestInterruptTestBase*>(
22127 info.Data().As<v8::External>()->Value());
22128 info.GetReturnValue().Set(test->ShouldContinue());
22132 v8::Isolate* isolate_;
22133 v8::base::Semaphore sem_;
22135 bool should_continue_;
22139 class RequestInterruptTestBaseWithSimpleInterrupt
22140 : public RequestInterruptTestBase {
22142 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22144 virtual void StartInterruptThread() {
22149 class InterruptThread : public v8::base::Thread {
22151 explicit InterruptThread(RequestInterruptTestBase* test)
22152 : Thread(Options("RequestInterruptTest")), test_(test) {}
22154 virtual void Run() {
22155 test_->sem_.Wait();
22156 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22159 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22160 reinterpret_cast<RequestInterruptTestBase*>(data)->
22161 should_continue_ = false;
22165 RequestInterruptTestBase* test_;
22168 InterruptThread i_thread;
22172 class RequestInterruptTestWithFunctionCall
22173 : public RequestInterruptTestBaseWithSimpleInterrupt {
22175 virtual void TestBody() {
22176 Local<Function> func = Function::New(
22177 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22178 env_->Global()->Set(v8_str("ShouldContinue"), func);
22180 CompileRun("while (ShouldContinue()) { }");
22185 class RequestInterruptTestWithMethodCall
22186 : public RequestInterruptTestBaseWithSimpleInterrupt {
22188 virtual void TestBody() {
22189 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22190 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22191 proto->Set(v8_str("shouldContinue"), Function::New(
22192 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22193 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22195 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22200 class RequestInterruptTestWithAccessor
22201 : public RequestInterruptTestBaseWithSimpleInterrupt {
22203 virtual void TestBody() {
22204 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22205 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22206 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22207 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22208 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22210 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22215 class RequestInterruptTestWithNativeAccessor
22216 : public RequestInterruptTestBaseWithSimpleInterrupt {
22218 virtual void TestBody() {
22219 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22220 t->InstanceTemplate()->SetNativeDataProperty(
22221 v8_str("shouldContinue"),
22222 &ShouldContinueNativeGetter,
22224 v8::External::New(isolate_, this));
22225 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22227 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22231 static void ShouldContinueNativeGetter(
22232 Local<String> property,
22233 const v8::PropertyCallbackInfo<v8::Value>& info) {
22234 RequestInterruptTestBase* test =
22235 reinterpret_cast<RequestInterruptTestBase*>(
22236 info.Data().As<v8::External>()->Value());
22237 info.GetReturnValue().Set(test->ShouldContinue());
22242 class RequestInterruptTestWithMethodCallAndInterceptor
22243 : public RequestInterruptTestBaseWithSimpleInterrupt {
22245 virtual void TestBody() {
22246 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22247 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22248 proto->Set(v8_str("shouldContinue"), Function::New(
22249 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22250 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22251 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22253 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22255 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22259 static void EmptyInterceptor(
22260 Local<String> property,
22261 const v8::PropertyCallbackInfo<v8::Value>& info) {
22266 class RequestInterruptTestWithMathAbs
22267 : public RequestInterruptTestBaseWithSimpleInterrupt {
22269 virtual void TestBody() {
22270 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22272 WakeUpInterruptorCallback,
22273 v8::External::New(isolate_, this)));
22275 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22277 ShouldContinueCallback,
22278 v8::External::New(isolate_, this)));
22280 i::FLAG_allow_natives_syntax = true;
22281 CompileRun("function loopish(o) {"
22283 " while (o.abs(1) > 0) {"
22284 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22286 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22291 "var obj = {abs: function () { return i-- }, x: null};"
22294 "%OptimizeFunctionOnNextCall(loopish);"
22297 i::FLAG_allow_natives_syntax = false;
22301 static void WakeUpInterruptorCallback(
22302 const v8::FunctionCallbackInfo<Value>& info) {
22303 if (!info[0]->BooleanValue()) return;
22305 RequestInterruptTestBase* test =
22306 reinterpret_cast<RequestInterruptTestBase*>(
22307 info.Data().As<v8::External>()->Value());
22308 test->WakeUpInterruptor();
22311 static void ShouldContinueCallback(
22312 const v8::FunctionCallbackInfo<Value>& info) {
22313 RequestInterruptTestBase* test =
22314 reinterpret_cast<RequestInterruptTestBase*>(
22315 info.Data().As<v8::External>()->Value());
22316 info.GetReturnValue().Set(test->should_continue());
22321 TEST(RequestInterruptTestWithFunctionCall) {
22322 RequestInterruptTestWithFunctionCall().RunTest();
22326 TEST(RequestInterruptTestWithMethodCall) {
22327 RequestInterruptTestWithMethodCall().RunTest();
22331 TEST(RequestInterruptTestWithAccessor) {
22332 RequestInterruptTestWithAccessor().RunTest();
22336 TEST(RequestInterruptTestWithNativeAccessor) {
22337 RequestInterruptTestWithNativeAccessor().RunTest();
22341 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22342 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22346 TEST(RequestInterruptTestWithMathAbs) {
22347 RequestInterruptTestWithMathAbs().RunTest();
22351 class ClearInterruptFromAnotherThread
22352 : public RequestInterruptTestBase {
22354 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22356 virtual void StartInterruptThread() {
22360 virtual void TestBody() {
22361 Local<Function> func = Function::New(
22362 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22363 env_->Global()->Set(v8_str("ShouldContinue"), func);
22365 CompileRun("while (ShouldContinue()) { }");
22369 class InterruptThread : public v8::base::Thread {
22371 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22372 : Thread(Options("RequestInterruptTest")), test_(test) {}
22374 virtual void Run() {
22375 test_->sem_.Wait();
22376 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22377 test_->sem_.Wait();
22378 test_->isolate_->ClearInterrupt();
22379 test_->sem2_.Signal();
22382 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22383 ClearInterruptFromAnotherThread* test =
22384 reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22385 test->sem_.Signal();
22386 bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22387 // Crash instead of timeout to make this failure more prominent.
22389 test->should_continue_ = false;
22393 ClearInterruptFromAnotherThread* test_;
22396 InterruptThread i_thread;
22397 v8::base::Semaphore sem2_;
22401 TEST(ClearInterruptFromAnotherThread) {
22402 ClearInterruptFromAnotherThread().RunTest();
22406 static Local<Value> function_new_expected_env;
22407 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22408 CHECK_EQ(function_new_expected_env, info.Data());
22409 info.GetReturnValue().Set(17);
22413 THREADED_TEST(FunctionNew) {
22415 v8::Isolate* isolate = env->GetIsolate();
22416 v8::HandleScope scope(isolate);
22417 Local<Object> data = v8::Object::New(isolate);
22418 function_new_expected_env = data;
22419 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22420 env->Global()->Set(v8_str("func"), func);
22421 Local<Value> result = CompileRun("func();");
22422 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22423 // Verify function not cached
22424 int serial_number =
22425 i::Smi::cast(v8::Utils::OpenHandle(*func)
22426 ->shared()->get_api_func_data()->serial_number())->value();
22427 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22428 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22429 i::Handle<i::Object> elm =
22430 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22431 CHECK(elm->IsUndefined());
22432 // Verify that each Function::New creates a new function instance
22433 Local<Object> data2 = v8::Object::New(isolate);
22434 function_new_expected_env = data2;
22435 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22436 CHECK(!func2->IsNull());
22437 CHECK_NE(func, func2);
22438 env->Global()->Set(v8_str("func2"), func2);
22439 Local<Value> result2 = CompileRun("func2();");
22440 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22444 TEST(EscapeableHandleScope) {
22445 HandleScope outer_scope(CcTest::isolate());
22446 LocalContext context;
22447 const int runs = 10;
22448 Local<String> values[runs];
22449 for (int i = 0; i < runs; i++) {
22450 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22451 Local<String> value;
22452 if (i != 0) value = v8_str("escape value");
22453 values[i] = inner_scope.Escape(value);
22455 for (int i = 0; i < runs; i++) {
22456 Local<String> expected;
22458 CHECK_EQ(v8_str("escape value"), values[i]);
22460 CHECK(values[i].IsEmpty());
22466 static void SetterWhichExpectsThisAndHolderToDiffer(
22467 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22468 CHECK(info.Holder() != info.This());
22472 TEST(Regress239669) {
22473 LocalContext context;
22474 v8::Isolate* isolate = context->GetIsolate();
22475 v8::HandleScope scope(isolate);
22476 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22477 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22478 context->Global()->Set(v8_str("P"), templ->NewInstance());
22483 "C1.prototype = P;"
22484 "for (var i = 0; i < 4; i++ ) {"
22490 class ApiCallOptimizationChecker {
22492 static Local<Object> data;
22493 static Local<Object> receiver;
22494 static Local<Object> holder;
22495 static Local<Object> callee;
22498 static void OptimizationCallback(
22499 const v8::FunctionCallbackInfo<v8::Value>& info) {
22500 CHECK(callee == info.Callee());
22501 CHECK(data == info.Data());
22502 CHECK(receiver == info.This());
22503 if (info.Length() == 1) {
22504 CHECK_EQ(v8_num(1), info[0]);
22506 CHECK(holder == info.Holder());
22508 info.GetReturnValue().Set(v8_str("returned"));
22512 enum SignatureType {
22514 kSignatureOnReceiver,
22515 kSignatureOnPrototype
22519 SignatureType signature_types[] =
22520 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22521 for (unsigned i = 0; i < arraysize(signature_types); i++) {
22522 SignatureType signature_type = signature_types[i];
22523 for (int j = 0; j < 2; j++) {
22524 bool global = j == 0;
22525 int key = signature_type +
22526 arraysize(signature_types) * (global ? 1 : 0);
22527 Run(signature_type, global, key);
22532 void Run(SignatureType signature_type, bool global, int key) {
22533 v8::Isolate* isolate = CcTest::isolate();
22534 v8::HandleScope scope(isolate);
22535 // Build a template for signature checks.
22536 Local<v8::ObjectTemplate> signature_template;
22537 Local<v8::Signature> signature;
22539 Local<v8::FunctionTemplate> parent_template =
22540 FunctionTemplate::New(isolate);
22541 parent_template->SetHiddenPrototype(true);
22542 Local<v8::FunctionTemplate> function_template
22543 = FunctionTemplate::New(isolate);
22544 function_template->Inherit(parent_template);
22545 switch (signature_type) {
22548 case kSignatureOnReceiver:
22549 signature = v8::Signature::New(isolate, function_template);
22551 case kSignatureOnPrototype:
22552 signature = v8::Signature::New(isolate, parent_template);
22555 signature_template = function_template->InstanceTemplate();
22557 // Global object must pass checks.
22558 Local<v8::Context> context =
22559 v8::Context::New(isolate, NULL, signature_template);
22560 v8::Context::Scope context_scope(context);
22561 // Install regular object that can pass signature checks.
22562 Local<Object> function_receiver = signature_template->NewInstance();
22563 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22564 // Get the holder objects.
22565 Local<Object> inner_global =
22566 Local<Object>::Cast(context->Global()->GetPrototype());
22567 // Install functions on hidden prototype object if there is one.
22568 data = Object::New(isolate);
22569 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22570 isolate, OptimizationCallback, data, signature);
22571 Local<Function> function = function_template->GetFunction();
22572 Local<Object> global_holder = inner_global;
22573 Local<Object> function_holder = function_receiver;
22574 if (signature_type == kSignatureOnPrototype) {
22575 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22576 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22578 global_holder->Set(v8_str("g_f"), function);
22579 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22580 function_holder->Set(v8_str("f"), function);
22581 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22582 // Initialize expected values.
22586 receiver = context->Global();
22587 holder = inner_global;
22589 holder = function_receiver;
22590 // If not using a signature, add something else to the prototype chain
22591 // to test the case that holder != receiver
22592 if (signature_type == kNoSignature) {
22593 receiver = Local<Object>::Cast(CompileRun(
22594 "var receiver_subclass = {};\n"
22595 "receiver_subclass.__proto__ = function_receiver;\n"
22596 "receiver_subclass"));
22598 receiver = Local<Object>::Cast(CompileRun(
22599 "var receiver_subclass = function_receiver;\n"
22600 "receiver_subclass"));
22603 // With no signature, the holder is not set.
22604 if (signature_type == kNoSignature) holder = receiver;
22605 // build wrap_function
22606 i::ScopedVector<char> wrap_function(200);
22610 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22611 "function wrap_get_%d() { return this.g_acc; }\n"
22612 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22617 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22618 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22619 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22622 // build source string
22623 i::ScopedVector<char> source(1000);
22626 "%s\n" // wrap functions
22627 "function wrap_f() { return wrap_f_%d(); }\n"
22628 "function wrap_get() { return wrap_get_%d(); }\n"
22629 "function wrap_set() { return wrap_set_%d(); }\n"
22630 "check = function(returned) {\n"
22631 " if (returned !== 'returned') { throw returned; }\n"
22634 "check(wrap_f());\n"
22635 "check(wrap_f());\n"
22636 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22637 "check(wrap_f());\n"
22639 "check(wrap_get());\n"
22640 "check(wrap_get());\n"
22641 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22642 "check(wrap_get());\n"
22644 "check = function(returned) {\n"
22645 " if (returned !== 1) { throw returned; }\n"
22647 "check(wrap_set());\n"
22648 "check(wrap_set());\n"
22649 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22650 "check(wrap_set());\n",
22651 wrap_function.start(), key, key, key, key, key, key);
22652 v8::TryCatch try_catch;
22653 CompileRun(source.start());
22654 DCHECK(!try_catch.HasCaught());
22655 CHECK_EQ(9, count);
22660 Local<Object> ApiCallOptimizationChecker::data;
22661 Local<Object> ApiCallOptimizationChecker::receiver;
22662 Local<Object> ApiCallOptimizationChecker::holder;
22663 Local<Object> ApiCallOptimizationChecker::callee;
22664 int ApiCallOptimizationChecker::count = 0;
22667 TEST(TestFunctionCallOptimization) {
22668 i::FLAG_allow_natives_syntax = true;
22669 ApiCallOptimizationChecker checker;
22674 static const char* last_event_message;
22675 static int last_event_status;
22676 void StoringEventLoggerCallback(const char* message, int status) {
22677 last_event_message = message;
22678 last_event_status = status;
22682 TEST(EventLogging) {
22683 v8::Isolate* isolate = CcTest::isolate();
22684 isolate->SetEventLogger(StoringEventLoggerCallback);
22685 v8::internal::HistogramTimer histogramTimer(
22686 "V8.Test", 0, 10000, 50,
22687 reinterpret_cast<v8::internal::Isolate*>(isolate));
22688 histogramTimer.Start();
22689 CHECK_EQ("V8.Test", last_event_message);
22690 CHECK_EQ(0, last_event_status);
22691 histogramTimer.Stop();
22692 CHECK_EQ("V8.Test", last_event_message);
22693 CHECK_EQ(1, last_event_status);
22698 LocalContext context;
22699 v8::Isolate* isolate = context->GetIsolate();
22700 v8::HandleScope scope(isolate);
22701 Handle<Object> global = context->Global();
22704 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22705 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22706 Handle<v8::Promise> p = pr->GetPromise();
22707 Handle<v8::Promise> r = rr->GetPromise();
22709 // IsPromise predicate.
22710 CHECK(p->IsPromise());
22711 CHECK(r->IsPromise());
22712 Handle<Value> o = v8::Object::New(isolate);
22713 CHECK(!o->IsPromise());
22715 // Resolution and rejection.
22716 pr->Resolve(v8::Integer::New(isolate, 1));
22717 CHECK(p->IsPromise());
22718 rr->Reject(v8::Integer::New(isolate, 2));
22719 CHECK(r->IsPromise());
22721 // Chaining non-pending promises.
22725 "function f1(x) { x1 = x; return x+1 };\n"
22726 "function f2(x) { x2 = x; return x+1 };\n");
22727 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22728 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22731 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22732 isolate->RunMicrotasks();
22733 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22736 isolate->RunMicrotasks();
22737 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22740 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22741 isolate->RunMicrotasks();
22742 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22745 isolate->RunMicrotasks();
22746 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22748 // Chaining pending promises.
22749 CompileRun("x1 = x2 = 0;");
22750 pr = v8::Promise::Resolver::New(isolate);
22751 rr = v8::Promise::Resolver::New(isolate);
22753 pr->GetPromise()->Chain(f1);
22754 rr->GetPromise()->Catch(f2);
22755 isolate->RunMicrotasks();
22756 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22757 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22759 pr->Resolve(v8::Integer::New(isolate, 1));
22760 rr->Reject(v8::Integer::New(isolate, 2));
22761 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22762 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22764 isolate->RunMicrotasks();
22765 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22766 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22769 CompileRun("x1 = x2 = 0;");
22770 pr = v8::Promise::Resolver::New(isolate);
22771 pr->GetPromise()->Chain(f1)->Chain(f2);
22772 pr->Resolve(v8::Integer::New(isolate, 3));
22773 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22774 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22775 isolate->RunMicrotasks();
22776 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22777 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22779 CompileRun("x1 = x2 = 0;");
22780 rr = v8::Promise::Resolver::New(isolate);
22781 rr->GetPromise()->Catch(f1)->Chain(f2);
22782 rr->Reject(v8::Integer::New(isolate, 3));
22783 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22784 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22785 isolate->RunMicrotasks();
22786 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22787 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22791 TEST(PromiseThen) {
22792 LocalContext context;
22793 v8::Isolate* isolate = context->GetIsolate();
22794 v8::HandleScope scope(isolate);
22795 Handle<Object> global = context->Global();
22798 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22799 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22800 Handle<v8::Promise> p = pr->GetPromise();
22801 Handle<v8::Promise> q = qr->GetPromise();
22803 CHECK(p->IsPromise());
22804 CHECK(q->IsPromise());
22806 pr->Resolve(v8::Integer::New(isolate, 1));
22809 // Chaining non-pending promises.
22813 "function f1(x) { x1 = x; return x+1 };\n"
22814 "function f2(x) { x2 = x; return x+1 };\n");
22815 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22816 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22820 CHECK(global->Get(v8_str("x1"))->IsNumber());
22821 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22822 isolate->RunMicrotasks();
22823 CHECK(!global->Get(v8_str("x1"))->IsNumber());
22824 CHECK_EQ(p, global->Get(v8_str("x1")));
22827 CompileRun("x1 = x2 = 0;");
22829 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22830 isolate->RunMicrotasks();
22831 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22834 CompileRun("x1 = x2 = 0;");
22835 pr = v8::Promise::Resolver::New(isolate);
22836 qr = v8::Promise::Resolver::New(isolate);
22839 qr->GetPromise()->Then(f1)->Then(f2);
22841 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22842 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22843 isolate->RunMicrotasks();
22844 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22845 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22847 pr->Resolve(v8::Integer::New(isolate, 3));
22849 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22850 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22851 isolate->RunMicrotasks();
22852 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22853 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22857 TEST(DisallowJavascriptExecutionScope) {
22858 LocalContext context;
22859 v8::Isolate* isolate = context->GetIsolate();
22860 v8::HandleScope scope(isolate);
22861 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22862 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22867 TEST(AllowJavascriptExecutionScope) {
22868 LocalContext context;
22869 v8::Isolate* isolate = context->GetIsolate();
22870 v8::HandleScope scope(isolate);
22871 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22872 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22873 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22874 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22875 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22881 TEST(ThrowOnJavascriptExecution) {
22882 LocalContext context;
22883 v8::Isolate* isolate = context->GetIsolate();
22884 v8::HandleScope scope(isolate);
22885 v8::TryCatch try_catch;
22886 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22887 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22889 CHECK(try_catch.HasCaught());
22893 TEST(Regress354123) {
22894 LocalContext current;
22895 v8::Isolate* isolate = current->GetIsolate();
22896 v8::HandleScope scope(isolate);
22898 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22899 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22900 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22902 // Test access using __proto__ from the prototype chain.
22903 named_access_count = 0;
22904 CompileRun("friend.__proto__ = {};");
22905 CHECK_EQ(2, named_access_count);
22906 CompileRun("friend.__proto__;");
22907 CHECK_EQ(4, named_access_count);
22909 // Test access using __proto__ as a hijacked function (A).
22910 named_access_count = 0;
22911 CompileRun("var p = Object.prototype;"
22912 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22913 "f.call(friend, {});");
22914 CHECK_EQ(1, named_access_count);
22915 CompileRun("var p = Object.prototype;"
22916 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22917 "f.call(friend);");
22918 CHECK_EQ(2, named_access_count);
22920 // Test access using __proto__ as a hijacked function (B).
22921 named_access_count = 0;
22922 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22923 "f.call(friend, {});");
22924 CHECK_EQ(1, named_access_count);
22925 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22926 "f.call(friend);");
22927 CHECK_EQ(2, named_access_count);
22929 // Test access using Object.setPrototypeOf reflective method.
22930 named_access_count = 0;
22931 CompileRun("Object.setPrototypeOf(friend, {});");
22932 CHECK_EQ(1, named_access_count);
22933 CompileRun("Object.getPrototypeOf(friend);");
22934 CHECK_EQ(2, named_access_count);
22938 TEST(CaptureStackTraceForStackOverflow) {
22939 v8::internal::FLAG_stack_size = 150;
22940 LocalContext current;
22941 v8::Isolate* isolate = current->GetIsolate();
22942 v8::HandleScope scope(isolate);
22943 V8::SetCaptureStackTraceForUncaughtExceptions(
22944 true, 10, v8::StackTrace::kDetailed);
22945 v8::TryCatch try_catch;
22946 CompileRun("(function f(x) { f(x+1); })(0)");
22947 CHECK(try_catch.HasCaught());
22951 TEST(ScriptNameAndLineNumber) {
22953 v8::Isolate* isolate = env->GetIsolate();
22954 v8::HandleScope scope(isolate);
22955 const char* url = "http://www.foo.com/foo.js";
22956 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22957 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22958 Local<Script> script = v8::ScriptCompiler::Compile(
22959 isolate, &script_source);
22960 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22961 CHECK(!script_name.IsEmpty());
22962 CHECK(script_name->IsString());
22963 String::Utf8Value utf8_name(script_name);
22964 CHECK_EQ(url, *utf8_name);
22965 int line_number = script->GetUnboundScript()->GetLineNumber(0);
22966 CHECK_EQ(13, line_number);
22970 void SourceURLHelper(const char* source, const char* expected_source_url,
22971 const char* expected_source_mapping_url) {
22972 Local<Script> script = v8_compile(source);
22973 if (expected_source_url != NULL) {
22974 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22975 CHECK_EQ(expected_source_url, *url);
22977 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22979 if (expected_source_mapping_url != NULL) {
22980 v8::String::Utf8Value url(
22981 script->GetUnboundScript()->GetSourceMappingURL());
22982 CHECK_EQ(expected_source_mapping_url, *url);
22984 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22989 TEST(ScriptSourceURLAndSourceMappingURL) {
22991 v8::Isolate* isolate = env->GetIsolate();
22992 v8::HandleScope scope(isolate);
22993 SourceURLHelper("function foo() {}\n"
22994 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22995 SourceURLHelper("function foo() {}\n"
22996 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22998 // Both sourceURL and sourceMappingURL.
22999 SourceURLHelper("function foo() {}\n"
23000 "//# sourceURL=bar3.js\n"
23001 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
23003 // Two source URLs; the first one is ignored.
23004 SourceURLHelper("function foo() {}\n"
23005 "//# sourceURL=ignoreme.js\n"
23006 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
23007 SourceURLHelper("function foo() {}\n"
23008 "//# sourceMappingURL=ignoreme.js\n"
23009 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
23011 // SourceURL or sourceMappingURL in the middle of the script.
23012 SourceURLHelper("function foo() {}\n"
23013 "//# sourceURL=bar7.js\n"
23014 "function baz() {}\n", "bar7.js", NULL);
23015 SourceURLHelper("function foo() {}\n"
23016 "//# sourceMappingURL=bar8.js\n"
23017 "function baz() {}\n", NULL, "bar8.js");
23019 // Too much whitespace.
23020 SourceURLHelper("function foo() {}\n"
23021 "//# sourceURL=bar9.js\n"
23022 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
23023 SourceURLHelper("function foo() {}\n"
23024 "//# sourceURL =bar11.js\n"
23025 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
23027 // Disallowed characters in value.
23028 SourceURLHelper("function foo() {}\n"
23029 "//# sourceURL=bar13 .js \n"
23030 "//# sourceMappingURL=bar14 .js \n",
23032 SourceURLHelper("function foo() {}\n"
23033 "//# sourceURL=bar15\t.js \n"
23034 "//# sourceMappingURL=bar16\t.js \n",
23036 SourceURLHelper("function foo() {}\n"
23037 "//# sourceURL=bar17'.js \n"
23038 "//# sourceMappingURL=bar18'.js \n",
23040 SourceURLHelper("function foo() {}\n"
23041 "//# sourceURL=bar19\".js \n"
23042 "//# sourceMappingURL=bar20\".js \n",
23045 // Not too much whitespace.
23046 SourceURLHelper("function foo() {}\n"
23047 "//# sourceURL= bar21.js \n"
23048 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
23052 TEST(GetOwnPropertyDescriptor) {
23054 v8::Isolate* isolate = env->GetIsolate();
23055 v8::HandleScope scope(isolate);
23057 "var x = { value : 13};"
23058 "Object.defineProperty(x, 'p0', {value : 12});"
23059 "Object.defineProperty(x, 'p1', {"
23060 " set : function(value) { this.value = value; },"
23061 " get : function() { return this.value; },"
23063 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
23064 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
23065 CHECK(desc->IsUndefined());
23066 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
23067 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
23068 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
23069 Local<Function> set =
23070 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
23071 Local<Function> get =
23072 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
23073 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
23074 Handle<Value> args[] = { v8_num(14) };
23075 set->Call(x, 1, args);
23076 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
23080 TEST(Regress411877) {
23081 v8::Isolate* isolate = CcTest::isolate();
23082 v8::HandleScope handle_scope(isolate);
23083 v8::Handle<v8::ObjectTemplate> object_template =
23084 v8::ObjectTemplate::New(isolate);
23085 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23086 IndexedAccessCounter);
23088 v8::Handle<Context> context = Context::New(isolate);
23089 v8::Context::Scope context_scope(context);
23091 context->Global()->Set(v8_str("o"), object_template->NewInstance());
23092 CompileRun("Object.getOwnPropertyNames(o)");
23096 TEST(GetHiddenPropertyTableAfterAccessCheck) {
23097 v8::Isolate* isolate = CcTest::isolate();
23098 v8::HandleScope handle_scope(isolate);
23099 v8::Handle<v8::ObjectTemplate> object_template =
23100 v8::ObjectTemplate::New(isolate);
23101 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23102 IndexedAccessCounter);
23104 v8::Handle<Context> context = Context::New(isolate);
23105 v8::Context::Scope context_scope(context);
23107 v8::Handle<v8::Object> obj = object_template->NewInstance();
23108 obj->Set(v8_str("key"), v8_str("value"));
23109 obj->Delete(v8_str("key"));
23111 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23115 TEST(Regress411793) {
23116 v8::Isolate* isolate = CcTest::isolate();
23117 v8::HandleScope handle_scope(isolate);
23118 v8::Handle<v8::ObjectTemplate> object_template =
23119 v8::ObjectTemplate::New(isolate);
23120 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23121 IndexedAccessCounter);
23123 v8::Handle<Context> context = Context::New(isolate);
23124 v8::Context::Scope context_scope(context);
23126 context->Global()->Set(v8_str("o"), object_template->NewInstance());
23128 "Object.defineProperty(o, 'key', "
23129 " { get: function() {}, set: function() {} });");
23132 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23134 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23136 virtual size_t GetMoreData(const uint8_t** src) {
23137 // Unlike in real use cases, this function will never block.
23138 if (chunks_[index_] == NULL) {
23141 // Copy the data, since the caller takes ownership of it.
23142 size_t len = strlen(chunks_[index_]);
23143 // We don't need to zero-terminate since we return the length.
23144 uint8_t* copy = new uint8_t[len];
23145 memcpy(copy, chunks_[index_], len);
23151 // Helper for constructing a string from chunks (the compilation needs it
23153 static char* FullSourceString(const char** chunks) {
23154 size_t total_len = 0;
23155 for (size_t i = 0; chunks[i] != NULL; ++i) {
23156 total_len += strlen(chunks[i]);
23158 char* full_string = new char[total_len + 1];
23160 for (size_t i = 0; chunks[i] != NULL; ++i) {
23161 size_t len = strlen(chunks[i]);
23162 memcpy(full_string + offset, chunks[i], len);
23165 full_string[total_len] = 0;
23166 return full_string;
23170 const char** chunks_;
23175 // Helper function for running streaming tests.
23176 void RunStreamingTest(const char** chunks,
23177 v8::ScriptCompiler::StreamedSource::Encoding encoding =
23178 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23179 bool expected_success = true) {
23181 v8::Isolate* isolate = env->GetIsolate();
23182 v8::HandleScope scope(isolate);
23183 v8::TryCatch try_catch;
23185 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23187 v8::ScriptCompiler::ScriptStreamingTask* task =
23188 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23190 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23191 // task here in the main thread.
23195 v8::ScriptOrigin origin(v8_str("http://foo.com"));
23196 char* full_source = TestSourceStream::FullSourceString(chunks);
23198 // The possible errors are only produced while compiling.
23199 CHECK_EQ(false, try_catch.HasCaught());
23201 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23202 isolate, &source, v8_str(full_source), origin);
23203 if (expected_success) {
23204 CHECK(!script.IsEmpty());
23205 v8::Handle<Value> result(script->Run());
23206 // All scripts are supposed to return the fixed value 13 when ran.
23207 CHECK_EQ(13, result->Int32Value());
23209 CHECK(script.IsEmpty());
23210 CHECK(try_catch.HasCaught());
23212 delete[] full_source;
23216 TEST(StreamingSimpleScript) {
23217 // This script is unrealistically small, since no one chunk is enough to fill
23218 // the backing buffer of Scanner, let alone overflow it.
23219 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23221 RunStreamingTest(chunks);
23225 TEST(StreamingBiggerScript) {
23226 const char* chunk1 =
23227 "function foo() {\n"
23228 " // Make this chunk sufficiently long so that it will overflow the\n"
23229 " // backing buffer of the Scanner.\n"
23231 " var result = 0;\n"
23232 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23234 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23236 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23238 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23239 " return result;\n"
23241 const char* chunks[] = {chunk1, "foo(); ", NULL};
23242 RunStreamingTest(chunks);
23246 TEST(StreamingScriptWithParseError) {
23247 // Test that parse errors from streamed scripts are propagated correctly.
23250 " // This will result in a parse error.\n"
23251 " var if else then foo";
23252 char chunk2[] = " 13\n";
23253 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23255 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23258 // Test that the next script succeeds normally.
23261 " // This will be parsed successfully.\n"
23262 " function foo() { return ";
23263 char chunk2[] = " 13; }\n";
23264 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23266 RunStreamingTest(chunks);
23271 TEST(StreamingUtf8Script) {
23272 // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
23274 const char* chunk1 =
23275 "function foo() {\n"
23276 " // This function will contain an UTF-8 character which is not in\n"
23278 " var foob\xeb\x91\x80r = 13;\n"
23279 " return foob\xeb\x91\x80r;\n"
23281 const char* chunks[] = {chunk1, "foo(); ", NULL};
23282 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23286 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23287 // A sanity check to prove that the approach of splitting UTF-8
23288 // characters is correct. Here is an UTF-8 character which will take three
23290 const char* reference = "\xeb\x91\x80";
23291 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
23294 "function foo() {\n"
23295 " // This function will contain an UTF-8 character which is not in\n"
23300 " return foob\xeb\x91\x80r;\n"
23302 for (int i = 0; i < 3; ++i) {
23303 chunk2[i] = reference[i];
23305 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23306 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23310 TEST(StreamingUtf8ScriptWithSplitCharacters) {
23311 // Stream data where a multi-byte UTF-8 character is split between two data
23313 const char* reference = "\xeb\x91\x80";
23315 "function foo() {\n"
23316 " // This function will contain an UTF-8 character which is not in\n"
23321 " return foob\xeb\x91\x80r;\n"
23323 chunk1[strlen(chunk1) - 1] = reference[0];
23324 chunk2[0] = reference[1];
23325 chunk2[1] = reference[2];
23326 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23327 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23331 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
23332 // Tests edge cases which should still be decoded correctly.
23334 // Case 1: a chunk contains only bytes for a split character (and no other
23335 // data). This kind of a chunk would be exceptionally small, but we should
23336 // still decode it correctly.
23337 const char* reference = "\xeb\x91\x80";
23338 // The small chunk is at the beginning of the split character
23341 "function foo() {\n"
23342 " // This function will contain an UTF-8 character which is not in\n"
23345 char chunk2[] = "XX";
23348 " return foob\xeb\x91\x80r;\n"
23350 chunk2[0] = reference[0];
23351 chunk2[1] = reference[1];
23352 chunk3[0] = reference[2];
23353 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23354 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23356 // The small chunk is at the end of a character
23359 "function foo() {\n"
23360 " // This function will contain an UTF-8 character which is not in\n"
23363 char chunk2[] = "XX";
23366 " return foob\xeb\x91\x80r;\n"
23368 chunk1[strlen(chunk1) - 1] = reference[0];
23369 chunk2[0] = reference[1];
23370 chunk2[1] = reference[2];
23371 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23372 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23374 // Case 2: the script ends with a multi-byte character. Make sure that it's
23375 // decoded correctly and not just ignored.
23378 "var foob\xeb\x91\x80 = 13;\n"
23379 "foob\xeb\x91\x80";
23380 const char* chunks[] = {chunk1, NULL};
23381 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23386 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
23387 // Test cases where a UTF-8 character is split over several chunks. Those
23388 // cases are not supported (the embedder should give the data in big enough
23389 // chunks), but we shouldn't crash, just produce a parse error.
23390 const char* reference = "\xeb\x91\x80";
23392 "function foo() {\n"
23393 " // This function will contain an UTF-8 character which is not in\n"
23396 char chunk2[] = "X";
23399 " return foob\xeb\x91\x80r;\n"
23401 chunk1[strlen(chunk1) - 1] = reference[0];
23402 chunk2[0] = reference[1];
23403 chunk3[0] = reference[2];
23404 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23406 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23410 TEST(StreamingProducesParserCache) {
23411 i::FLAG_min_preparse_length = 0;
23412 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23416 v8::Isolate* isolate = env->GetIsolate();
23417 v8::HandleScope scope(isolate);
23419 v8::ScriptCompiler::StreamedSource source(
23420 new TestSourceStream(chunks),
23421 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
23422 v8::ScriptCompiler::ScriptStreamingTask* task =
23423 v8::ScriptCompiler::StartStreamingScript(
23424 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
23426 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23427 // task here in the main thread.
23431 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
23432 CHECK(cached_data != NULL);
23433 CHECK(cached_data->data != NULL);
23434 CHECK_GT(cached_data->length, 0);
23438 TEST(StreamingScriptWithInvalidUtf8) {
23439 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
23440 // chunk don't produce a crash.
23441 const char* reference = "\xeb\x91\x80\x80\x80";
23443 "function foo() {\n"
23444 " // This function will contain an UTF-8 character which is not in\n"
23446 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
23449 " return foob\xeb\x91\x80\x80\x80r;\n"
23451 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
23453 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23454 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);