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/compilation-cache.h"
43 #include "src/cpu-profiler.h"
44 #include "src/execution.h"
45 #include "src/isolate.h"
46 #include "src/objects.h"
47 #include "src/parser.h"
48 #include "src/platform.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;
67 using ::v8::MessageCallback;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
72 using ::v8::StackTrace;
75 using ::v8::Undefined;
81 #define THREADED_PROFILED_TEST(Name) \
82 static void Test##Name(); \
83 TEST(Name##WithProfiler) { \
84 RunWithProfiler(&Test##Name); \
89 void RunWithProfiler(void (*test)()) {
91 v8::HandleScope scope(env->GetIsolate());
92 v8::Local<v8::String> profile_name =
93 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
96 cpu_profiler->StartProfiling(profile_name);
98 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
102 static int signature_callback_count;
103 static Local<Value> signature_expected_receiver;
104 static void IncrementingSignatureCallback(
105 const v8::FunctionCallbackInfo<v8::Value>& args) {
106 ApiTestFuzzer::Fuzz();
107 signature_callback_count++;
108 CHECK_EQ(signature_expected_receiver, args.Holder());
109 CHECK_EQ(signature_expected_receiver, args.This());
110 v8::Handle<v8::Array> result =
111 v8::Array::New(args.GetIsolate(), args.Length());
112 for (int i = 0; i < args.Length(); i++)
113 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
114 args.GetReturnValue().Set(result);
118 static void SignatureCallback(
119 const v8::FunctionCallbackInfo<v8::Value>& args) {
120 ApiTestFuzzer::Fuzz();
121 v8::Handle<v8::Array> result =
122 v8::Array::New(args.GetIsolate(), args.Length());
123 for (int i = 0; i < args.Length(); i++) {
124 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
126 args.GetReturnValue().Set(result);
130 // Tests that call v8::V8::Dispose() cannot be threaded.
131 TEST(InitializeAndDisposeOnce) {
132 CHECK(v8::V8::Initialize());
133 CHECK(v8::V8::Dispose());
137 // Tests that call v8::V8::Dispose() cannot be threaded.
138 TEST(InitializeAndDisposeMultiple) {
139 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
140 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142 // TODO(mstarzinger): This should fail gracefully instead of asserting.
143 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
148 THREADED_TEST(Handles) {
149 v8::HandleScope scope(CcTest::isolate());
150 Local<Context> local_env;
153 local_env = env.local();
156 // Local context should still be live.
157 CHECK(!local_env.IsEmpty());
160 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
161 CHECK(!undef.IsEmpty());
162 CHECK(undef->IsUndefined());
164 const char* source = "1 + 2 + 3";
165 Local<Script> script = v8_compile(source);
166 CHECK_EQ(6, script->Run()->Int32Value());
172 THREADED_TEST(IsolateOfContext) {
173 v8::HandleScope scope(CcTest::isolate());
174 v8::Handle<Context> env = Context::New(CcTest::isolate());
176 CHECK(!env->GetIsolate()->InContext());
177 CHECK(env->GetIsolate() == CcTest::isolate());
179 CHECK(env->GetIsolate()->InContext());
180 CHECK(env->GetIsolate() == CcTest::isolate());
182 CHECK(!env->GetIsolate()->InContext());
183 CHECK(env->GetIsolate() == CcTest::isolate());
187 static void TestSignature(const char* loop_js, Local<Value> receiver) {
188 i::ScopedVector<char> source(200);
190 "for (var i = 0; i < 10; i++) {"
194 signature_callback_count = 0;
195 signature_expected_receiver = receiver;
196 bool expected_to_throw = receiver.IsEmpty();
197 v8::TryCatch try_catch;
198 CompileRun(source.start());
199 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
200 if (!expected_to_throw) {
201 CHECK_EQ(10, signature_callback_count);
203 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
204 try_catch.Exception()->ToString());
209 THREADED_TEST(ReceiverSignature) {
211 v8::Isolate* isolate = env->GetIsolate();
212 v8::HandleScope scope(isolate);
214 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
215 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
216 v8::Handle<v8::FunctionTemplate> callback_sig =
217 v8::FunctionTemplate::New(
218 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
219 v8::Handle<v8::FunctionTemplate> callback =
220 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
221 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
222 sub_fun->Inherit(fun);
223 v8::Handle<v8::FunctionTemplate> unrel_fun =
224 v8::FunctionTemplate::New(isolate);
225 // Install properties.
226 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
227 fun_proto->Set(v8_str("prop_sig"), callback_sig);
228 fun_proto->Set(v8_str("prop"), callback);
229 fun_proto->SetAccessorProperty(
230 v8_str("accessor_sig"), callback_sig, callback_sig);
231 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
232 // Instantiate templates.
233 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
234 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
235 // Setup global variables.
236 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
237 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
238 env->Global()->Set(v8_str("fun_instance"), fun_instance);
239 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241 "var accessor_sig_key = 'accessor_sig';"
242 "var accessor_key = 'accessor';"
243 "var prop_sig_key = 'prop_sig';"
244 "var prop_key = 'prop';"
246 "function copy_props(obj) {"
247 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
248 " var source = Fun.prototype;"
249 " for (var i in keys) {"
250 " var key = keys[i];"
251 " var desc = Object.getOwnPropertyDescriptor(source, key);"
252 " Object.defineProperty(obj, key, desc);"
258 "var unrel = new UnrelFun();"
259 "copy_props(unrel);");
260 // Test with and without ICs
261 const char* test_objects[] = {
262 "fun_instance", "sub_fun_instance", "obj", "unrel" };
263 unsigned bad_signature_start_offset = 2;
264 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
265 i::ScopedVector<char> source(200);
267 source, "var test_object = %s; test_object", test_objects[i]);
268 Local<Value> test_object = CompileRun(source.start());
269 TestSignature("test_object.prop();", test_object);
270 TestSignature("test_object.accessor;", test_object);
271 TestSignature("test_object[accessor_key];", test_object);
272 TestSignature("test_object.accessor = 1;", test_object);
273 TestSignature("test_object[accessor_key] = 1;", test_object);
274 if (i >= bad_signature_start_offset) test_object = Local<Value>();
275 TestSignature("test_object.prop_sig();", test_object);
276 TestSignature("test_object.accessor_sig;", test_object);
277 TestSignature("test_object[accessor_sig_key];", test_object);
278 TestSignature("test_object.accessor_sig = 1;", test_object);
279 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
284 THREADED_TEST(ArgumentSignature) {
286 v8::Isolate* isolate = env->GetIsolate();
287 v8::HandleScope scope(isolate);
288 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
289 cons->SetClassName(v8_str("Cons"));
290 v8::Handle<v8::Signature> sig = v8::Signature::New(
291 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
292 v8::Handle<v8::FunctionTemplate> fun =
293 v8::FunctionTemplate::New(isolate,
297 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
298 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
301 CHECK(value1->IsTrue());
303 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
304 CHECK(value2->IsTrue());
306 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
307 CHECK(value3->IsTrue());
309 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
310 cons1->SetClassName(v8_str("Cons1"));
311 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
312 cons2->SetClassName(v8_str("Cons2"));
313 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
314 cons3->SetClassName(v8_str("Cons3"));
316 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
317 v8::Handle<v8::Signature> wsig = v8::Signature::New(
318 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
319 v8::Handle<v8::FunctionTemplate> fun2 =
320 v8::FunctionTemplate::New(isolate,
325 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
326 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
327 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
328 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
329 v8::Handle<Value> value4 = CompileRun(
330 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
331 "'[object Cons1],[object Cons2],[object Cons3]'");
332 CHECK(value4->IsTrue());
334 v8::Handle<Value> value5 = CompileRun(
335 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
336 CHECK(value5->IsTrue());
338 v8::Handle<Value> value6 = CompileRun(
339 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
340 CHECK(value6->IsTrue());
342 v8::Handle<Value> value7 = CompileRun(
343 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
344 "'[object Cons1],[object Cons2],[object Cons3],d';");
345 CHECK(value7->IsTrue());
347 v8::Handle<Value> value8 = CompileRun(
348 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
349 CHECK(value8->IsTrue());
353 THREADED_TEST(HulIgennem) {
355 v8::Isolate* isolate = env->GetIsolate();
356 v8::HandleScope scope(isolate);
357 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
358 Local<String> undef_str = undef->ToString();
359 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
360 undef_str->WriteUtf8(value);
361 CHECK_EQ(0, strcmp(value, "undefined"));
362 i::DeleteArray(value);
366 THREADED_TEST(Access) {
368 v8::Isolate* isolate = env->GetIsolate();
369 v8::HandleScope scope(isolate);
370 Local<v8::Object> obj = v8::Object::New(isolate);
371 Local<Value> foo_before = obj->Get(v8_str("foo"));
372 CHECK(foo_before->IsUndefined());
373 Local<String> bar_str = v8_str("bar");
374 obj->Set(v8_str("foo"), bar_str);
375 Local<Value> foo_after = obj->Get(v8_str("foo"));
376 CHECK(!foo_after->IsUndefined());
377 CHECK(foo_after->IsString());
378 CHECK_EQ(bar_str, foo_after);
382 THREADED_TEST(AccessElement) {
384 v8::HandleScope scope(env->GetIsolate());
385 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
386 Local<Value> before = obj->Get(1);
387 CHECK(before->IsUndefined());
388 Local<String> bar_str = v8_str("bar");
389 obj->Set(1, bar_str);
390 Local<Value> after = obj->Get(1);
391 CHECK(!after->IsUndefined());
392 CHECK(after->IsString());
393 CHECK_EQ(bar_str, after);
395 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
396 CHECK_EQ(v8_str("a"), value->Get(0));
397 CHECK_EQ(v8_str("b"), value->Get(1));
401 THREADED_TEST(Script) {
403 v8::HandleScope scope(env->GetIsolate());
404 const char* source = "1 + 2 + 3";
405 Local<Script> script = v8_compile(source);
406 CHECK_EQ(6, script->Run()->Int32Value());
410 class TestResource: public String::ExternalStringResource {
412 TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
413 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
414 while (data[length_]) ++length_;
418 if (owning_data_) i::DeleteArray(data_);
419 if (counter_ != NULL) ++*counter_;
422 const uint16_t* data() const {
426 size_t length() const {
438 class TestAsciiResource: public String::ExternalAsciiStringResource {
440 TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
442 data_(data + offset),
443 length_(strlen(data) - offset),
444 counter_(counter) { }
446 ~TestAsciiResource() {
447 i::DeleteArray(orig_data_);
448 if (counter_ != NULL) ++*counter_;
451 const char* data() const {
455 size_t length() const {
460 const char* orig_data_;
467 THREADED_TEST(ScriptUsingStringResource) {
468 int dispose_count = 0;
469 const char* c_source = "1 + 2 * 3";
470 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
473 v8::HandleScope scope(env->GetIsolate());
474 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
475 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
476 Local<Script> script = v8_compile(source);
477 Local<Value> value = script->Run();
478 CHECK(value->IsNumber());
479 CHECK_EQ(7, value->Int32Value());
480 CHECK(source->IsExternal());
482 static_cast<TestResource*>(source->GetExternalStringResource()));
483 String::Encoding encoding = String::UNKNOWN_ENCODING;
484 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
485 source->GetExternalStringResourceBase(&encoding));
486 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
487 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
488 CHECK_EQ(0, dispose_count);
490 CcTest::i_isolate()->compilation_cache()->Clear();
491 CcTest::heap()->CollectAllAvailableGarbage();
492 CHECK_EQ(1, dispose_count);
496 THREADED_TEST(ScriptUsingAsciiStringResource) {
497 int dispose_count = 0;
498 const char* c_source = "1 + 2 * 3";
501 v8::HandleScope scope(env->GetIsolate());
502 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
504 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
505 CHECK(source->IsExternalAscii());
506 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
507 source->GetExternalAsciiStringResource());
508 String::Encoding encoding = String::UNKNOWN_ENCODING;
509 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510 source->GetExternalStringResourceBase(&encoding));
511 CHECK_EQ(String::ASCII_ENCODING, encoding);
512 Local<Script> script = v8_compile(source);
513 Local<Value> value = script->Run();
514 CHECK(value->IsNumber());
515 CHECK_EQ(7, value->Int32Value());
516 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
517 CHECK_EQ(0, dispose_count);
519 CcTest::i_isolate()->compilation_cache()->Clear();
520 CcTest::heap()->CollectAllAvailableGarbage();
521 CHECK_EQ(1, dispose_count);
525 THREADED_TEST(ScriptMakingExternalString) {
526 int dispose_count = 0;
527 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
530 v8::HandleScope scope(env->GetIsolate());
531 Local<String> source =
532 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
533 // Trigger GCs so that the newly allocated string moves to old gen.
534 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
535 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
536 CHECK_EQ(source->IsExternal(), false);
537 CHECK_EQ(source->IsExternalAscii(), false);
538 String::Encoding encoding = String::UNKNOWN_ENCODING;
539 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
540 CHECK_EQ(String::ASCII_ENCODING, encoding);
541 bool success = source->MakeExternal(new TestResource(two_byte_source,
544 Local<Script> script = v8_compile(source);
545 Local<Value> value = script->Run();
546 CHECK(value->IsNumber());
547 CHECK_EQ(7, value->Int32Value());
548 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
549 CHECK_EQ(0, dispose_count);
551 CcTest::i_isolate()->compilation_cache()->Clear();
552 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
553 CHECK_EQ(1, dispose_count);
557 THREADED_TEST(ScriptMakingExternalAsciiString) {
558 int dispose_count = 0;
559 const char* c_source = "1 + 2 * 3";
562 v8::HandleScope scope(env->GetIsolate());
563 Local<String> source = v8_str(c_source);
564 // Trigger GCs so that the newly allocated string moves to old gen.
565 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
566 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
567 bool success = source->MakeExternal(
568 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
570 Local<Script> script = v8_compile(source);
571 Local<Value> value = script->Run();
572 CHECK(value->IsNumber());
573 CHECK_EQ(7, value->Int32Value());
574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
575 CHECK_EQ(0, dispose_count);
577 CcTest::i_isolate()->compilation_cache()->Clear();
578 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
579 CHECK_EQ(1, dispose_count);
583 TEST(MakingExternalStringConditions) {
585 v8::HandleScope scope(env->GetIsolate());
587 // Free some space in the new space so that we can check freshness.
588 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
589 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
591 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
592 Local<String> small_string =
593 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
594 i::DeleteArray(two_byte_string);
596 // We should refuse to externalize newly created small string.
597 CHECK(!small_string->CanMakeExternal());
598 // Trigger GCs so that the newly allocated string moves to old gen.
599 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
600 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
601 // Old space strings should be accepted.
602 CHECK(small_string->CanMakeExternal());
604 two_byte_string = AsciiToTwoByteString("small string 2");
605 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
606 i::DeleteArray(two_byte_string);
608 // We should refuse externalizing newly created small string.
609 CHECK(!small_string->CanMakeExternal());
610 for (int i = 0; i < 100; i++) {
611 String::Value value(small_string);
613 // Frequently used strings should be accepted.
614 CHECK(small_string->CanMakeExternal());
616 const int buf_size = 10 * 1024;
617 char* buf = i::NewArray<char>(buf_size);
618 memset(buf, 'a', buf_size);
619 buf[buf_size - 1] = '\0';
621 two_byte_string = AsciiToTwoByteString(buf);
622 Local<String> large_string =
623 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
625 i::DeleteArray(two_byte_string);
626 // Large strings should be immediately accepted.
627 CHECK(large_string->CanMakeExternal());
631 TEST(MakingExternalAsciiStringConditions) {
633 v8::HandleScope scope(env->GetIsolate());
635 // Free some space in the new space so that we can check freshness.
636 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
637 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
639 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
640 // We should refuse to externalize newly created small string.
641 CHECK(!small_string->CanMakeExternal());
642 // Trigger GCs so that the newly allocated string moves to old gen.
643 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
644 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
645 // Old space strings should be accepted.
646 CHECK(small_string->CanMakeExternal());
648 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
649 // We should refuse externalizing newly created small string.
650 CHECK(!small_string->CanMakeExternal());
651 for (int i = 0; i < 100; i++) {
652 String::Value value(small_string);
654 // Frequently used strings should be accepted.
655 CHECK(small_string->CanMakeExternal());
657 const int buf_size = 10 * 1024;
658 char* buf = i::NewArray<char>(buf_size);
659 memset(buf, 'a', buf_size);
660 buf[buf_size - 1] = '\0';
661 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
663 // Large strings should be immediately accepted.
664 CHECK(large_string->CanMakeExternal());
668 TEST(MakingExternalUnalignedAsciiString) {
670 v8::HandleScope scope(env->GetIsolate());
672 CompileRun("function cons(a, b) { return a + b; }"
673 "function slice(a) { return a.substring(1); }");
674 // Create a cons string that will land in old pointer space.
675 Local<String> cons = Local<String>::Cast(CompileRun(
676 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
677 // Create a sliced string that will land in old pointer space.
678 Local<String> slice = Local<String>::Cast(CompileRun(
679 "slice('abcdefghijklmnopqrstuvwxyz');"));
681 // Trigger GCs so that the newly allocated string moves to old gen.
682 SimulateFullSpace(CcTest::heap()->old_pointer_space());
683 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
684 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
686 // Turn into external string with unaligned resource data.
687 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
688 bool success = cons->MakeExternal(
689 new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
691 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
692 success = slice->MakeExternal(
693 new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
696 // Trigger GCs and force evacuation.
697 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
698 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
702 THREADED_TEST(UsingExternalString) {
703 i::Factory* factory = CcTest::i_isolate()->factory();
705 v8::HandleScope scope(CcTest::isolate());
706 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
707 Local<String> string = String::NewExternal(
708 CcTest::isolate(), new TestResource(two_byte_string));
709 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
710 // Trigger GCs so that the newly allocated string moves to old gen.
711 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
712 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
713 i::Handle<i::String> isymbol =
714 factory->InternalizeString(istring);
715 CHECK(isymbol->IsInternalizedString());
717 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
718 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 THREADED_TEST(UsingExternalAsciiString) {
723 i::Factory* factory = CcTest::i_isolate()->factory();
725 v8::HandleScope scope(CcTest::isolate());
726 const char* one_byte_string = "test string";
727 Local<String> string = String::NewExternal(
728 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
729 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
730 // Trigger GCs so that the newly allocated string moves to old gen.
731 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
732 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
733 i::Handle<i::String> isymbol =
734 factory->InternalizeString(istring);
735 CHECK(isymbol->IsInternalizedString());
737 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
738 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742 THREADED_TEST(ScavengeExternalString) {
743 i::FLAG_stress_compaction = false;
744 i::FLAG_gc_global = false;
745 int dispose_count = 0;
746 bool in_new_space = false;
748 v8::HandleScope scope(CcTest::isolate());
749 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
750 Local<String> string = String::NewExternal(
751 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
752 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
753 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
754 in_new_space = CcTest::heap()->InNewSpace(*istring);
755 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
756 CHECK_EQ(0, dispose_count);
758 CcTest::heap()->CollectGarbage(
759 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
760 CHECK_EQ(1, dispose_count);
764 THREADED_TEST(ScavengeExternalAsciiString) {
765 i::FLAG_stress_compaction = false;
766 i::FLAG_gc_global = false;
767 int dispose_count = 0;
768 bool in_new_space = false;
770 v8::HandleScope scope(CcTest::isolate());
771 const char* one_byte_string = "test string";
772 Local<String> string = String::NewExternal(
774 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
775 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
776 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
777 in_new_space = CcTest::heap()->InNewSpace(*istring);
778 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
779 CHECK_EQ(0, dispose_count);
781 CcTest::heap()->CollectGarbage(
782 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
783 CHECK_EQ(1, dispose_count);
787 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
789 // Only used by non-threaded tests, so it can use static fields.
790 static int dispose_calls;
791 static int dispose_count;
793 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
794 : TestAsciiResource(data, &dispose_count),
795 dispose_(dispose) { }
799 if (dispose_) delete this;
806 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
807 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
810 TEST(ExternalStringWithDisposeHandling) {
811 const char* c_source = "1 + 2 * 3";
813 // Use a stack allocated external string resource allocated object.
814 TestAsciiResourceWithDisposeControl::dispose_count = 0;
815 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
816 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
819 v8::HandleScope scope(env->GetIsolate());
820 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
821 Local<Script> script = v8_compile(source);
822 Local<Value> value = script->Run();
823 CHECK(value->IsNumber());
824 CHECK_EQ(7, value->Int32Value());
825 CcTest::heap()->CollectAllAvailableGarbage();
826 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
828 CcTest::i_isolate()->compilation_cache()->Clear();
829 CcTest::heap()->CollectAllAvailableGarbage();
830 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
831 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
833 // Use a heap allocated external string resource allocated object.
834 TestAsciiResourceWithDisposeControl::dispose_count = 0;
835 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
836 TestAsciiResource* res_heap =
837 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
840 v8::HandleScope scope(env->GetIsolate());
841 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
842 Local<Script> script = v8_compile(source);
843 Local<Value> value = script->Run();
844 CHECK(value->IsNumber());
845 CHECK_EQ(7, value->Int32Value());
846 CcTest::heap()->CollectAllAvailableGarbage();
847 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
849 CcTest::i_isolate()->compilation_cache()->Clear();
850 CcTest::heap()->CollectAllAvailableGarbage();
851 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
852 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
856 THREADED_TEST(StringConcat) {
859 v8::HandleScope scope(env->GetIsolate());
860 const char* one_byte_string_1 = "function a_times_t";
861 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
862 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
863 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
864 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
865 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
866 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
867 Local<String> left = v8_str(one_byte_string_1);
869 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
870 Local<String> right =
871 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
872 i::DeleteArray(two_byte_source);
874 Local<String> source = String::Concat(left, right);
875 right = String::NewExternal(
876 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
877 source = String::Concat(source, right);
878 right = String::NewExternal(
880 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
881 source = String::Concat(source, right);
882 right = v8_str(one_byte_string_2);
883 source = String::Concat(source, right);
885 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
886 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
887 i::DeleteArray(two_byte_source);
889 source = String::Concat(source, right);
890 right = String::NewExternal(
892 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
893 source = String::Concat(source, right);
894 Local<Script> script = v8_compile(source);
895 Local<Value> value = script->Run();
896 CHECK(value->IsNumber());
897 CHECK_EQ(68, value->Int32Value());
899 CcTest::i_isolate()->compilation_cache()->Clear();
900 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
901 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
905 THREADED_TEST(GlobalProperties) {
907 v8::HandleScope scope(env->GetIsolate());
908 v8::Handle<v8::Object> global = env->Global();
909 global->Set(v8_str("pi"), v8_num(3.1415926));
910 Local<Value> pi = global->Get(v8_str("pi"));
911 CHECK_EQ(3.1415926, pi->NumberValue());
916 static void CheckReturnValue(const T& t, i::Address callback) {
917 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
918 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
919 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
920 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
921 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
923 bool is_runtime = (*o)->IsTheHole();
925 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
926 rv.Set(v8::Handle<v8::Object>());
927 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
928 CHECK_EQ(is_runtime, (*o)->IsTheHole());
930 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
931 // If CPU profiler is active check that when API callback is invoked
932 // VMState is set to EXTERNAL.
933 if (isolate->cpu_profiler()->is_profiling()) {
934 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
935 CHECK(isolate->external_callback_scope());
936 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
941 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
942 i::Address callback) {
943 ApiTestFuzzer::Fuzz();
944 CheckReturnValue(info, callback);
945 info.GetReturnValue().Set(v8_str("bad value"));
946 info.GetReturnValue().Set(v8_num(102));
950 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
951 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
955 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
956 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
959 static void construct_callback(
960 const v8::FunctionCallbackInfo<Value>& info) {
961 ApiTestFuzzer::Fuzz();
962 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
963 info.This()->Set(v8_str("x"), v8_num(1));
964 info.This()->Set(v8_str("y"), v8_num(2));
965 info.GetReturnValue().Set(v8_str("bad value"));
966 info.GetReturnValue().Set(info.This());
970 static void Return239Callback(
971 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
972 ApiTestFuzzer::Fuzz();
973 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
974 info.GetReturnValue().Set(v8_str("bad value"));
975 info.GetReturnValue().Set(v8_num(239));
979 template<typename Handler>
980 static void TestFunctionTemplateInitializer(Handler handler,
982 // Test constructor calls.
985 v8::Isolate* isolate = env->GetIsolate();
986 v8::HandleScope scope(isolate);
988 Local<v8::FunctionTemplate> fun_templ =
989 v8::FunctionTemplate::New(isolate, handler);
990 Local<Function> fun = fun_templ->GetFunction();
991 env->Global()->Set(v8_str("obj"), fun);
992 Local<Script> script = v8_compile("obj()");
993 for (int i = 0; i < 30; i++) {
994 CHECK_EQ(102, script->Run()->Int32Value());
997 // Use SetCallHandler to initialize a function template, should work like
1001 v8::Isolate* isolate = env->GetIsolate();
1002 v8::HandleScope scope(isolate);
1004 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1005 fun_templ->SetCallHandler(handler_2);
1006 Local<Function> fun = fun_templ->GetFunction();
1007 env->Global()->Set(v8_str("obj"), fun);
1008 Local<Script> script = v8_compile("obj()");
1009 for (int i = 0; i < 30; i++) {
1010 CHECK_EQ(102, script->Run()->Int32Value());
1016 template<typename Constructor, typename Accessor>
1017 static void TestFunctionTemplateAccessor(Constructor constructor,
1018 Accessor accessor) {
1020 v8::HandleScope scope(env->GetIsolate());
1022 Local<v8::FunctionTemplate> fun_templ =
1023 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1024 fun_templ->SetClassName(v8_str("funky"));
1025 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1026 Local<Function> fun = fun_templ->GetFunction();
1027 env->Global()->Set(v8_str("obj"), fun);
1028 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1029 CHECK_EQ(v8_str("[object funky]"), result);
1030 CompileRun("var obj_instance = new obj();");
1031 Local<Script> script;
1032 script = v8_compile("obj_instance.x");
1033 for (int i = 0; i < 30; i++) {
1034 CHECK_EQ(1, script->Run()->Int32Value());
1036 script = v8_compile("obj_instance.m");
1037 for (int i = 0; i < 30; i++) {
1038 CHECK_EQ(239, script->Run()->Int32Value());
1043 THREADED_PROFILED_TEST(FunctionTemplate) {
1044 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1045 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1049 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1050 ApiTestFuzzer::Fuzz();
1051 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1052 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1056 template<typename Callback>
1057 static void TestSimpleCallback(Callback callback) {
1059 v8::Isolate* isolate = env->GetIsolate();
1060 v8::HandleScope scope(isolate);
1062 v8::Handle<v8::ObjectTemplate> object_template =
1063 v8::ObjectTemplate::New(isolate);
1064 object_template->Set(isolate, "callback",
1065 v8::FunctionTemplate::New(isolate, callback));
1066 v8::Local<v8::Object> object = object_template->NewInstance();
1067 (*env)->Global()->Set(v8_str("callback_object"), object);
1068 v8::Handle<v8::Script> script;
1069 script = v8_compile("callback_object.callback(17)");
1070 for (int i = 0; i < 30; i++) {
1071 CHECK_EQ(51424, script->Run()->Int32Value());
1073 script = v8_compile("callback_object.callback(17, 24)");
1074 for (int i = 0; i < 30; i++) {
1075 CHECK_EQ(51425, script->Run()->Int32Value());
1080 THREADED_PROFILED_TEST(SimpleCallback) {
1081 TestSimpleCallback(SimpleCallback);
1085 template<typename T>
1086 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1088 // constant return values
1089 static int32_t fast_return_value_int32 = 471;
1090 static uint32_t fast_return_value_uint32 = 571;
1091 static const double kFastReturnValueDouble = 2.7;
1092 // variable return values
1093 static bool fast_return_value_bool = false;
1094 enum ReturnValueOddball {
1096 kUndefinedReturnValue,
1097 kEmptyStringReturnValue
1099 static ReturnValueOddball fast_return_value_void;
1100 static bool fast_return_value_object_is_empty = false;
1102 // Helper function to avoid compiler error: insufficient contextual information
1103 // to determine type when applying FUNCTION_ADDR to a template function.
1104 static i::Address address_of(v8::FunctionCallback callback) {
1105 return FUNCTION_ADDR(callback);
1109 void FastReturnValueCallback<int32_t>(
1110 const v8::FunctionCallbackInfo<v8::Value>& info) {
1111 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1112 info.GetReturnValue().Set(fast_return_value_int32);
1116 void FastReturnValueCallback<uint32_t>(
1117 const v8::FunctionCallbackInfo<v8::Value>& info) {
1118 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1119 info.GetReturnValue().Set(fast_return_value_uint32);
1123 void FastReturnValueCallback<double>(
1124 const v8::FunctionCallbackInfo<v8::Value>& info) {
1125 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1126 info.GetReturnValue().Set(kFastReturnValueDouble);
1130 void FastReturnValueCallback<bool>(
1131 const v8::FunctionCallbackInfo<v8::Value>& info) {
1132 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1133 info.GetReturnValue().Set(fast_return_value_bool);
1137 void FastReturnValueCallback<void>(
1138 const v8::FunctionCallbackInfo<v8::Value>& info) {
1139 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1140 switch (fast_return_value_void) {
1141 case kNullReturnValue:
1142 info.GetReturnValue().SetNull();
1144 case kUndefinedReturnValue:
1145 info.GetReturnValue().SetUndefined();
1147 case kEmptyStringReturnValue:
1148 info.GetReturnValue().SetEmptyString();
1154 void FastReturnValueCallback<Object>(
1155 const v8::FunctionCallbackInfo<v8::Value>& info) {
1156 v8::Handle<v8::Object> object;
1157 if (!fast_return_value_object_is_empty) {
1158 object = Object::New(info.GetIsolate());
1160 info.GetReturnValue().Set(object);
1163 template<typename T>
1164 Handle<Value> TestFastReturnValues() {
1166 v8::Isolate* isolate = env->GetIsolate();
1167 v8::EscapableHandleScope scope(isolate);
1168 v8::Handle<v8::ObjectTemplate> object_template =
1169 v8::ObjectTemplate::New(isolate);
1170 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1171 object_template->Set(isolate, "callback",
1172 v8::FunctionTemplate::New(isolate, callback));
1173 v8::Local<v8::Object> object = object_template->NewInstance();
1174 (*env)->Global()->Set(v8_str("callback_object"), object);
1175 return scope.Escape(CompileRun("callback_object.callback()"));
1179 THREADED_PROFILED_TEST(FastReturnValues) {
1181 v8::HandleScope scope(CcTest::isolate());
1182 v8::Handle<v8::Value> value;
1183 // check int32_t and uint32_t
1184 int32_t int_values[] = {
1186 i::Smi::kMinValue, i::Smi::kMaxValue
1188 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1189 for (int modifier = -1; modifier <= 1; modifier++) {
1190 int int_value = int_values[i] + modifier;
1192 fast_return_value_int32 = int_value;
1193 value = TestFastReturnValues<int32_t>();
1194 CHECK(value->IsInt32());
1195 CHECK(fast_return_value_int32 == value->Int32Value());
1197 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1198 value = TestFastReturnValues<uint32_t>();
1199 CHECK(value->IsUint32());
1200 CHECK(fast_return_value_uint32 == value->Uint32Value());
1204 value = TestFastReturnValues<double>();
1205 CHECK(value->IsNumber());
1206 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1207 // check bool values
1208 for (int i = 0; i < 2; i++) {
1209 fast_return_value_bool = i == 0;
1210 value = TestFastReturnValues<bool>();
1211 CHECK(value->IsBoolean());
1212 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1215 ReturnValueOddball oddballs[] = {
1217 kUndefinedReturnValue,
1218 kEmptyStringReturnValue
1220 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1221 fast_return_value_void = oddballs[i];
1222 value = TestFastReturnValues<void>();
1223 switch (fast_return_value_void) {
1224 case kNullReturnValue:
1225 CHECK(value->IsNull());
1227 case kUndefinedReturnValue:
1228 CHECK(value->IsUndefined());
1230 case kEmptyStringReturnValue:
1231 CHECK(value->IsString());
1232 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1237 fast_return_value_object_is_empty = false;
1238 value = TestFastReturnValues<Object>();
1239 CHECK(value->IsObject());
1240 fast_return_value_object_is_empty = true;
1241 value = TestFastReturnValues<Object>();
1242 CHECK(value->IsUndefined());
1246 THREADED_TEST(FunctionTemplateSetLength) {
1248 v8::Isolate* isolate = env->GetIsolate();
1249 v8::HandleScope scope(isolate);
1251 Local<v8::FunctionTemplate> fun_templ =
1252 v8::FunctionTemplate::New(isolate,
1254 Handle<v8::Value>(),
1255 Handle<v8::Signature>(),
1257 Local<Function> fun = fun_templ->GetFunction();
1258 env->Global()->Set(v8_str("obj"), fun);
1259 Local<Script> script = v8_compile("obj.length");
1260 CHECK_EQ(23, script->Run()->Int32Value());
1263 Local<v8::FunctionTemplate> fun_templ =
1264 v8::FunctionTemplate::New(isolate, handle_callback);
1265 fun_templ->SetLength(22);
1266 Local<Function> fun = fun_templ->GetFunction();
1267 env->Global()->Set(v8_str("obj"), fun);
1268 Local<Script> script = v8_compile("obj.length");
1269 CHECK_EQ(22, script->Run()->Int32Value());
1272 // Without setting length it defaults to 0.
1273 Local<v8::FunctionTemplate> fun_templ =
1274 v8::FunctionTemplate::New(isolate, handle_callback);
1275 Local<Function> fun = fun_templ->GetFunction();
1276 env->Global()->Set(v8_str("obj"), fun);
1277 Local<Script> script = v8_compile("obj.length");
1278 CHECK_EQ(0, script->Run()->Int32Value());
1283 static void* expected_ptr;
1284 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1285 void* ptr = v8::External::Cast(*args.Data())->Value();
1286 CHECK_EQ(expected_ptr, ptr);
1287 args.GetReturnValue().Set(true);
1291 static void TestExternalPointerWrapping() {
1293 v8::Isolate* isolate = env->GetIsolate();
1294 v8::HandleScope scope(isolate);
1296 v8::Handle<v8::Value> data =
1297 v8::External::New(isolate, expected_ptr);
1299 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1300 obj->Set(v8_str("func"),
1301 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1302 env->Global()->Set(v8_str("obj"), obj);
1305 "function foo() {\n"
1306 " for (var i = 0; i < 13; i++) obj.func();\n"
1308 "foo(), true")->BooleanValue());
1312 THREADED_TEST(ExternalWrap) {
1313 // Check heap allocated object.
1316 TestExternalPointerWrapping();
1319 // Check stack allocated object.
1321 expected_ptr = &foo;
1322 TestExternalPointerWrapping();
1324 // Check not aligned addresses.
1326 char* s = new char[n];
1327 for (int i = 0; i < n; i++) {
1328 expected_ptr = s + i;
1329 TestExternalPointerWrapping();
1334 // Check several invalid addresses.
1335 expected_ptr = reinterpret_cast<void*>(1);
1336 TestExternalPointerWrapping();
1338 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1339 TestExternalPointerWrapping();
1341 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1342 TestExternalPointerWrapping();
1344 #if defined(V8_HOST_ARCH_X64)
1345 // Check a value with a leading 1 bit in x64 Smi encoding.
1346 expected_ptr = reinterpret_cast<void*>(0x400000000);
1347 TestExternalPointerWrapping();
1349 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1350 TestExternalPointerWrapping();
1352 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1353 TestExternalPointerWrapping();
1358 THREADED_TEST(FindInstanceInPrototypeChain) {
1360 v8::Isolate* isolate = env->GetIsolate();
1361 v8::HandleScope scope(isolate);
1363 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1364 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1365 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1366 derived->Inherit(base);
1368 Local<v8::Function> base_function = base->GetFunction();
1369 Local<v8::Function> derived_function = derived->GetFunction();
1370 Local<v8::Function> other_function = other->GetFunction();
1372 Local<v8::Object> base_instance = base_function->NewInstance();
1373 Local<v8::Object> derived_instance = derived_function->NewInstance();
1374 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1375 Local<v8::Object> other_instance = other_function->NewInstance();
1376 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1377 other_instance->Set(v8_str("__proto__"), derived_instance2);
1379 // base_instance is only an instance of base.
1380 CHECK_EQ(base_instance,
1381 base_instance->FindInstanceInPrototypeChain(base));
1382 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1383 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1385 // derived_instance is an instance of base and derived.
1386 CHECK_EQ(derived_instance,
1387 derived_instance->FindInstanceInPrototypeChain(base));
1388 CHECK_EQ(derived_instance,
1389 derived_instance->FindInstanceInPrototypeChain(derived));
1390 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1392 // other_instance is an instance of other and its immediate
1393 // prototype derived_instance2 is an instance of base and derived.
1394 // Note, derived_instance is an instance of base and derived too,
1395 // but it comes after derived_instance2 in the prototype chain of
1397 CHECK_EQ(derived_instance2,
1398 other_instance->FindInstanceInPrototypeChain(base));
1399 CHECK_EQ(derived_instance2,
1400 other_instance->FindInstanceInPrototypeChain(derived));
1401 CHECK_EQ(other_instance,
1402 other_instance->FindInstanceInPrototypeChain(other));
1406 THREADED_TEST(TinyInteger) {
1408 v8::Isolate* isolate = env->GetIsolate();
1409 v8::HandleScope scope(isolate);
1411 int32_t value = 239;
1412 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1413 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1415 value_obj = v8::Integer::New(isolate, value);
1416 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1420 THREADED_TEST(BigSmiInteger) {
1422 v8::HandleScope scope(env->GetIsolate());
1423 v8::Isolate* isolate = CcTest::isolate();
1425 int32_t value = i::Smi::kMaxValue;
1426 // We cannot add one to a Smi::kMaxValue without wrapping.
1427 if (i::SmiValuesAre31Bits()) {
1428 CHECK(i::Smi::IsValid(value));
1429 CHECK(!i::Smi::IsValid(value + 1));
1431 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1432 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1434 value_obj = v8::Integer::New(isolate, value);
1435 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1440 THREADED_TEST(BigInteger) {
1442 v8::HandleScope scope(env->GetIsolate());
1443 v8::Isolate* isolate = CcTest::isolate();
1445 // We cannot add one to a Smi::kMaxValue without wrapping.
1446 if (i::SmiValuesAre31Bits()) {
1447 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1448 // The code will not be run in that case, due to the "if" guard.
1450 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1451 CHECK(value > i::Smi::kMaxValue);
1452 CHECK(!i::Smi::IsValid(value));
1454 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1455 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1457 value_obj = v8::Integer::New(isolate, value);
1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1463 THREADED_TEST(TinyUnsignedInteger) {
1465 v8::HandleScope scope(env->GetIsolate());
1466 v8::Isolate* isolate = CcTest::isolate();
1468 uint32_t value = 239;
1470 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1471 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1473 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1474 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1478 THREADED_TEST(BigUnsignedSmiInteger) {
1480 v8::HandleScope scope(env->GetIsolate());
1481 v8::Isolate* isolate = CcTest::isolate();
1483 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1484 CHECK(i::Smi::IsValid(value));
1485 CHECK(!i::Smi::IsValid(value + 1));
1487 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1488 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1490 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1491 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1495 THREADED_TEST(BigUnsignedInteger) {
1497 v8::HandleScope scope(env->GetIsolate());
1498 v8::Isolate* isolate = CcTest::isolate();
1500 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1501 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1502 CHECK(!i::Smi::IsValid(value));
1504 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1505 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1507 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1514 v8::HandleScope scope(env->GetIsolate());
1515 v8::Isolate* isolate = CcTest::isolate();
1517 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1518 uint32_t value = INT32_MAX_AS_UINT + 1;
1519 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1521 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1522 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1524 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1525 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529 THREADED_TEST(IsNativeError) {
1531 v8::HandleScope scope(env->GetIsolate());
1532 v8::Handle<Value> syntax_error = CompileRun(
1533 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1534 CHECK(syntax_error->IsNativeError());
1535 v8::Handle<Value> not_error = CompileRun("{a:42}");
1536 CHECK(!not_error->IsNativeError());
1537 v8::Handle<Value> not_object = CompileRun("42");
1538 CHECK(!not_object->IsNativeError());
1542 THREADED_TEST(StringObject) {
1544 v8::HandleScope scope(env->GetIsolate());
1545 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1546 CHECK(boxed_string->IsStringObject());
1547 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1548 CHECK(!unboxed_string->IsStringObject());
1549 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1550 CHECK(!boxed_not_string->IsStringObject());
1551 v8::Handle<Value> not_object = CompileRun("0");
1552 CHECK(!not_object->IsStringObject());
1553 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1554 CHECK(!as_boxed.IsEmpty());
1555 Local<v8::String> the_string = as_boxed->ValueOf();
1556 CHECK(!the_string.IsEmpty());
1557 ExpectObject("\"test\"", the_string);
1558 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1559 CHECK(new_boxed_string->IsStringObject());
1560 as_boxed = new_boxed_string.As<v8::StringObject>();
1561 the_string = as_boxed->ValueOf();
1562 CHECK(!the_string.IsEmpty());
1563 ExpectObject("\"test\"", the_string);
1567 THREADED_TEST(NumberObject) {
1569 v8::HandleScope scope(env->GetIsolate());
1570 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1571 CHECK(boxed_number->IsNumberObject());
1572 v8::Handle<Value> unboxed_number = CompileRun("42");
1573 CHECK(!unboxed_number->IsNumberObject());
1574 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1575 CHECK(!boxed_not_number->IsNumberObject());
1576 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1577 CHECK(!as_boxed.IsEmpty());
1578 double the_number = as_boxed->ValueOf();
1579 CHECK_EQ(42.0, the_number);
1580 v8::Handle<v8::Value> new_boxed_number =
1581 v8::NumberObject::New(env->GetIsolate(), 43);
1582 CHECK(new_boxed_number->IsNumberObject());
1583 as_boxed = new_boxed_number.As<v8::NumberObject>();
1584 the_number = as_boxed->ValueOf();
1585 CHECK_EQ(43.0, the_number);
1589 THREADED_TEST(BooleanObject) {
1591 v8::HandleScope scope(env->GetIsolate());
1592 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1593 CHECK(boxed_boolean->IsBooleanObject());
1594 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1595 CHECK(!unboxed_boolean->IsBooleanObject());
1596 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1597 CHECK(!boxed_not_boolean->IsBooleanObject());
1598 v8::Handle<v8::BooleanObject> as_boxed =
1599 boxed_boolean.As<v8::BooleanObject>();
1600 CHECK(!as_boxed.IsEmpty());
1601 bool the_boolean = as_boxed->ValueOf();
1602 CHECK_EQ(true, the_boolean);
1603 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1604 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1605 CHECK(boxed_true->IsBooleanObject());
1606 CHECK(boxed_false->IsBooleanObject());
1607 as_boxed = boxed_true.As<v8::BooleanObject>();
1608 CHECK_EQ(true, as_boxed->ValueOf());
1609 as_boxed = boxed_false.As<v8::BooleanObject>();
1610 CHECK_EQ(false, as_boxed->ValueOf());
1614 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1616 v8::HandleScope scope(env->GetIsolate());
1618 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1619 CHECK(primitive_false->IsBoolean());
1620 CHECK(!primitive_false->IsBooleanObject());
1621 CHECK(!primitive_false->BooleanValue());
1622 CHECK(!primitive_false->IsTrue());
1623 CHECK(primitive_false->IsFalse());
1625 Local<Value> false_value = BooleanObject::New(false);
1626 CHECK(!false_value->IsBoolean());
1627 CHECK(false_value->IsBooleanObject());
1628 CHECK(false_value->BooleanValue());
1629 CHECK(!false_value->IsTrue());
1630 CHECK(!false_value->IsFalse());
1632 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1633 CHECK(!false_boolean_object->IsBoolean());
1634 CHECK(false_boolean_object->IsBooleanObject());
1635 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1636 // CHECK(false_boolean_object->BooleanValue());
1637 CHECK(!false_boolean_object->ValueOf());
1638 CHECK(!false_boolean_object->IsTrue());
1639 CHECK(!false_boolean_object->IsFalse());
1641 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1642 CHECK(primitive_true->IsBoolean());
1643 CHECK(!primitive_true->IsBooleanObject());
1644 CHECK(primitive_true->BooleanValue());
1645 CHECK(primitive_true->IsTrue());
1646 CHECK(!primitive_true->IsFalse());
1648 Local<Value> true_value = BooleanObject::New(true);
1649 CHECK(!true_value->IsBoolean());
1650 CHECK(true_value->IsBooleanObject());
1651 CHECK(true_value->BooleanValue());
1652 CHECK(!true_value->IsTrue());
1653 CHECK(!true_value->IsFalse());
1655 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1656 CHECK(!true_boolean_object->IsBoolean());
1657 CHECK(true_boolean_object->IsBooleanObject());
1658 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1659 // CHECK(true_boolean_object->BooleanValue());
1660 CHECK(true_boolean_object->ValueOf());
1661 CHECK(!true_boolean_object->IsTrue());
1662 CHECK(!true_boolean_object->IsFalse());
1666 THREADED_TEST(Number) {
1668 v8::HandleScope scope(env->GetIsolate());
1669 double PI = 3.1415926;
1670 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1671 CHECK_EQ(PI, pi_obj->NumberValue());
1675 THREADED_TEST(ToNumber) {
1677 v8::Isolate* isolate = CcTest::isolate();
1678 v8::HandleScope scope(isolate);
1679 Local<String> str = v8_str("3.1415926");
1680 CHECK_EQ(3.1415926, str->NumberValue());
1681 v8::Handle<v8::Boolean> t = v8::True(isolate);
1682 CHECK_EQ(1.0, t->NumberValue());
1683 v8::Handle<v8::Boolean> f = v8::False(isolate);
1684 CHECK_EQ(0.0, f->NumberValue());
1688 THREADED_TEST(Date) {
1690 v8::HandleScope scope(env->GetIsolate());
1691 double PI = 3.1415926;
1692 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1693 CHECK_EQ(3.0, date->NumberValue());
1694 date.As<v8::Date>()->Set(v8_str("property"),
1695 v8::Integer::New(env->GetIsolate(), 42));
1696 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1700 THREADED_TEST(Boolean) {
1702 v8::Isolate* isolate = env->GetIsolate();
1703 v8::HandleScope scope(isolate);
1704 v8::Handle<v8::Boolean> t = v8::True(isolate);
1706 v8::Handle<v8::Boolean> f = v8::False(isolate);
1708 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1709 CHECK(!u->BooleanValue());
1710 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1711 CHECK(!n->BooleanValue());
1712 v8::Handle<String> str1 = v8_str("");
1713 CHECK(!str1->BooleanValue());
1714 v8::Handle<String> str2 = v8_str("x");
1715 CHECK(str2->BooleanValue());
1716 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1717 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1718 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1719 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1720 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1724 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1725 ApiTestFuzzer::Fuzz();
1726 args.GetReturnValue().Set(v8_num(13.4));
1730 static void GetM(Local<String> name,
1731 const v8::PropertyCallbackInfo<v8::Value>& info) {
1732 ApiTestFuzzer::Fuzz();
1733 info.GetReturnValue().Set(v8_num(876));
1737 THREADED_TEST(GlobalPrototype) {
1738 v8::Isolate* isolate = CcTest::isolate();
1739 v8::HandleScope scope(isolate);
1740 v8::Handle<v8::FunctionTemplate> func_templ =
1741 v8::FunctionTemplate::New(isolate);
1742 func_templ->PrototypeTemplate()->Set(
1743 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1744 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1745 templ->Set(isolate, "x", v8_num(200));
1746 templ->SetAccessor(v8_str("m"), GetM);
1747 LocalContext env(0, templ);
1748 v8::Handle<Script> script(v8_compile("dummy()"));
1749 v8::Handle<Value> result(script->Run());
1750 CHECK_EQ(13.4, result->NumberValue());
1751 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1752 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1756 THREADED_TEST(ObjectTemplate) {
1757 v8::Isolate* isolate = CcTest::isolate();
1758 v8::HandleScope scope(isolate);
1759 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1760 templ1->Set(isolate, "x", v8_num(10));
1761 templ1->Set(isolate, "y", v8_num(13));
1763 Local<v8::Object> instance1 = templ1->NewInstance();
1764 env->Global()->Set(v8_str("p"), instance1);
1765 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1766 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1767 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1768 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1769 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1770 templ2->Set(isolate, "a", v8_num(12));
1771 templ2->Set(isolate, "b", templ1);
1772 Local<v8::Object> instance2 = templ2->NewInstance();
1773 env->Global()->Set(v8_str("q"), instance2);
1774 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1775 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1776 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1777 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1781 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1782 ApiTestFuzzer::Fuzz();
1783 args.GetReturnValue().Set(v8_num(17.2));
1787 static void GetKnurd(Local<String> property,
1788 const v8::PropertyCallbackInfo<v8::Value>& info) {
1789 ApiTestFuzzer::Fuzz();
1790 info.GetReturnValue().Set(v8_num(15.2));
1794 THREADED_TEST(DescriptorInheritance) {
1795 v8::Isolate* isolate = CcTest::isolate();
1796 v8::HandleScope scope(isolate);
1797 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1798 super->PrototypeTemplate()->Set(isolate, "flabby",
1799 v8::FunctionTemplate::New(isolate,
1801 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1803 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1805 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1806 base1->Inherit(super);
1807 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1809 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1810 base2->Inherit(super);
1811 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1815 env->Global()->Set(v8_str("s"), super->GetFunction());
1816 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1817 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1819 // Checks right __proto__ chain.
1820 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1821 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1823 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1825 // Instance accessor should not be visible on function object or its prototype
1826 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1827 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1828 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1830 env->Global()->Set(v8_str("obj"),
1831 base1->GetFunction()->NewInstance());
1832 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1833 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1834 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1835 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1836 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1838 env->Global()->Set(v8_str("obj2"),
1839 base2->GetFunction()->NewInstance());
1840 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1841 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1842 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1843 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1844 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1846 // base1 and base2 cannot cross reference to each's prototype
1847 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1848 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1852 int echo_named_call_count;
1855 static void EchoNamedProperty(Local<String> name,
1856 const v8::PropertyCallbackInfo<v8::Value>& info) {
1857 ApiTestFuzzer::Fuzz();
1858 CHECK_EQ(v8_str("data"), info.Data());
1859 echo_named_call_count++;
1860 info.GetReturnValue().Set(name);
1864 // Helper functions for Interceptor/Accessor interaction tests
1866 void SimpleAccessorGetter(Local<String> name,
1867 const v8::PropertyCallbackInfo<v8::Value>& info) {
1868 Handle<Object> self = Handle<Object>::Cast(info.This());
1869 info.GetReturnValue().Set(
1870 self->Get(String::Concat(v8_str("accessor_"), name)));
1873 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1874 const v8::PropertyCallbackInfo<void>& info) {
1875 Handle<Object> self = Handle<Object>::Cast(info.This());
1876 self->Set(String::Concat(v8_str("accessor_"), name), value);
1879 void EmptyInterceptorGetter(Local<String> name,
1880 const v8::PropertyCallbackInfo<v8::Value>& info) {
1883 void EmptyInterceptorSetter(Local<String> name,
1885 const v8::PropertyCallbackInfo<v8::Value>& info) {
1888 void InterceptorGetter(Local<String> name,
1889 const v8::PropertyCallbackInfo<v8::Value>& info) {
1890 // Intercept names that start with 'interceptor_'.
1891 String::Utf8Value utf8(name);
1892 char* name_str = *utf8;
1893 char prefix[] = "interceptor_";
1895 for (i = 0; name_str[i] && prefix[i]; ++i) {
1896 if (name_str[i] != prefix[i]) return;
1898 Handle<Object> self = Handle<Object>::Cast(info.This());
1899 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1902 void InterceptorSetter(Local<String> name,
1904 const v8::PropertyCallbackInfo<v8::Value>& info) {
1905 // Intercept accesses that set certain integer values, for which the name does
1906 // not start with 'accessor_'.
1907 String::Utf8Value utf8(name);
1908 char* name_str = *utf8;
1909 char prefix[] = "accessor_";
1911 for (i = 0; name_str[i] && prefix[i]; ++i) {
1912 if (name_str[i] != prefix[i]) break;
1914 if (!prefix[i]) return;
1916 if (value->IsInt32() && value->Int32Value() < 10000) {
1917 Handle<Object> self = Handle<Object>::Cast(info.This());
1918 self->SetHiddenValue(name, value);
1919 info.GetReturnValue().Set(value);
1923 void AddAccessor(Handle<FunctionTemplate> templ,
1924 Handle<String> name,
1925 v8::AccessorGetterCallback getter,
1926 v8::AccessorSetterCallback setter) {
1927 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1930 void AddInterceptor(Handle<FunctionTemplate> templ,
1931 v8::NamedPropertyGetterCallback getter,
1932 v8::NamedPropertySetterCallback setter) {
1933 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1937 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1938 v8::HandleScope scope(CcTest::isolate());
1939 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1940 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1941 child->Inherit(parent);
1942 AddAccessor(parent, v8_str("age"),
1943 SimpleAccessorGetter, SimpleAccessorSetter);
1944 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1946 env->Global()->Set(v8_str("Child"), child->GetFunction());
1947 CompileRun("var child = new Child;"
1949 ExpectBoolean("child.hasOwnProperty('age')", false);
1950 ExpectInt32("child.age", 10);
1951 ExpectInt32("child.accessor_age", 10);
1955 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1956 v8::Isolate* isolate = CcTest::isolate();
1957 v8::HandleScope scope(isolate);
1959 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1960 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1961 CHECK(a->map()->instance_descriptors()->IsFixedArray());
1962 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1963 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1964 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1965 // But we should still have an ExecutableAccessorInfo.
1966 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1967 i::LookupResult lookup(i_isolate);
1968 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1969 a->LookupOwnRealNamedProperty(name, &lookup);
1970 CHECK(lookup.IsPropertyCallbacks());
1971 i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate);
1972 CHECK(callback->IsExecutableAccessorInfo());
1976 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1977 v8::HandleScope scope(CcTest::isolate());
1978 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1979 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1981 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1982 CompileRun("var o1 = new Constructor;"
1983 "o1.a = 1;" // Ensure a and x share the descriptor array.
1984 "Object.defineProperty(o1, 'x', {value: 10});");
1985 CompileRun("var o2 = new Constructor;"
1987 "Object.defineProperty(o2, 'x', {value: 10});");
1991 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1992 v8::Isolate* isolate = CcTest::isolate();
1993 v8::HandleScope scope(isolate);
1994 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1995 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1996 child->Inherit(parent);
1997 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1999 env->Global()->Set(v8_str("Child"), child->GetFunction());
2000 CompileRun("var child = new Child;"
2001 "var parent = child.__proto__;"
2002 "Object.defineProperty(parent, 'age', "
2003 " {get: function(){ return this.accessor_age; }, "
2004 " set: function(v){ this.accessor_age = v; }, "
2005 " enumerable: true, configurable: true});"
2007 ExpectBoolean("child.hasOwnProperty('age')", false);
2008 ExpectInt32("child.age", 10);
2009 ExpectInt32("child.accessor_age", 10);
2013 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2014 v8::Isolate* isolate = CcTest::isolate();
2015 v8::HandleScope scope(isolate);
2016 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2017 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2018 child->Inherit(parent);
2019 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2021 env->Global()->Set(v8_str("Child"), child->GetFunction());
2022 CompileRun("var child = new Child;"
2023 "var parent = child.__proto__;"
2024 "parent.name = 'Alice';");
2025 ExpectBoolean("child.hasOwnProperty('name')", false);
2026 ExpectString("child.name", "Alice");
2027 CompileRun("child.name = 'Bob';");
2028 ExpectString("child.name", "Bob");
2029 ExpectBoolean("child.hasOwnProperty('name')", true);
2030 ExpectString("parent.name", "Alice");
2034 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2035 v8::HandleScope scope(CcTest::isolate());
2036 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2037 AddAccessor(templ, v8_str("age"),
2038 SimpleAccessorGetter, SimpleAccessorSetter);
2039 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2041 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2042 CompileRun("var obj = new Obj;"
2043 "function setAge(i){ obj.age = i; };"
2044 "for(var i = 0; i <= 10000; i++) setAge(i);");
2045 // All i < 10000 go to the interceptor.
2046 ExpectInt32("obj.interceptor_age", 9999);
2047 // The last i goes to the accessor.
2048 ExpectInt32("obj.accessor_age", 10000);
2052 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2053 v8::HandleScope scope(CcTest::isolate());
2054 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2055 AddAccessor(templ, v8_str("age"),
2056 SimpleAccessorGetter, SimpleAccessorSetter);
2057 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2059 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2060 CompileRun("var obj = new Obj;"
2061 "function setAge(i){ obj.age = i; };"
2062 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2063 // All i >= 10000 go to the accessor.
2064 ExpectInt32("obj.accessor_age", 10000);
2065 // The last i goes to the interceptor.
2066 ExpectInt32("obj.interceptor_age", 9999);
2070 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2071 v8::HandleScope scope(CcTest::isolate());
2072 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2073 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2074 child->Inherit(parent);
2075 AddAccessor(parent, v8_str("age"),
2076 SimpleAccessorGetter, SimpleAccessorSetter);
2077 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2079 env->Global()->Set(v8_str("Child"), child->GetFunction());
2080 CompileRun("var child = new Child;"
2081 "function setAge(i){ child.age = i; };"
2082 "for(var i = 0; i <= 10000; i++) setAge(i);");
2083 // All i < 10000 go to the interceptor.
2084 ExpectInt32("child.interceptor_age", 9999);
2085 // The last i goes to the accessor.
2086 ExpectInt32("child.accessor_age", 10000);
2090 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
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, InterceptorGetter, InterceptorSetter);
2099 env->Global()->Set(v8_str("Child"), child->GetFunction());
2100 CompileRun("var child = new Child;"
2101 "function setAge(i){ child.age = i; };"
2102 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2103 // All i >= 10000 go to the accessor.
2104 ExpectInt32("child.accessor_age", 10000);
2105 // The last i goes to the interceptor.
2106 ExpectInt32("child.interceptor_age", 9999);
2110 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2111 v8::HandleScope scope(CcTest::isolate());
2112 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2113 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2115 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2116 CompileRun("var obj = new Obj;"
2117 "function setter(i) { this.accessor_age = i; };"
2118 "function getter() { return this.accessor_age; };"
2119 "function setAge(i) { obj.age = i; };"
2120 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2121 "for(var i = 0; i <= 10000; i++) setAge(i);");
2122 // All i < 10000 go to the interceptor.
2123 ExpectInt32("obj.interceptor_age", 9999);
2124 // The last i goes to the JavaScript accessor.
2125 ExpectInt32("obj.accessor_age", 10000);
2126 // The installed JavaScript getter is still intact.
2127 // This last part is a regression test for issue 1651 and relies on the fact
2128 // that both interceptor and accessor are being installed on the same object.
2129 ExpectInt32("obj.age", 10000);
2130 ExpectBoolean("obj.hasOwnProperty('age')", true);
2131 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2135 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2136 v8::HandleScope scope(CcTest::isolate());
2137 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2138 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2140 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2141 CompileRun("var obj = new Obj;"
2142 "function setter(i) { this.accessor_age = i; };"
2143 "function getter() { return this.accessor_age; };"
2144 "function setAge(i) { obj.age = i; };"
2145 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2146 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2147 // All i >= 10000 go to the accessor.
2148 ExpectInt32("obj.accessor_age", 10000);
2149 // The last i goes to the interceptor.
2150 ExpectInt32("obj.interceptor_age", 9999);
2151 // The installed JavaScript getter is still intact.
2152 // This last part is a regression test for issue 1651 and relies on the fact
2153 // that both interceptor and accessor are being installed on the same object.
2154 ExpectInt32("obj.age", 10000);
2155 ExpectBoolean("obj.hasOwnProperty('age')", true);
2156 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2160 THREADED_TEST(SwitchFromInterceptorToProperty) {
2161 v8::HandleScope scope(CcTest::isolate());
2162 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2163 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2164 child->Inherit(parent);
2165 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2167 env->Global()->Set(v8_str("Child"), child->GetFunction());
2168 CompileRun("var child = new Child;"
2169 "function setAge(i){ child.age = i; };"
2170 "for(var i = 0; i <= 10000; i++) setAge(i);");
2171 // All i < 10000 go to the interceptor.
2172 ExpectInt32("child.interceptor_age", 9999);
2173 // The last i goes to child's own property.
2174 ExpectInt32("child.age", 10000);
2178 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2179 v8::HandleScope scope(CcTest::isolate());
2180 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2181 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2182 child->Inherit(parent);
2183 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2185 env->Global()->Set(v8_str("Child"), child->GetFunction());
2186 CompileRun("var child = new Child;"
2187 "function setAge(i){ child.age = i; };"
2188 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2189 // All i >= 10000 go to child's own property.
2190 ExpectInt32("child.age", 10000);
2191 // The last i goes to the interceptor.
2192 ExpectInt32("child.interceptor_age", 9999);
2196 THREADED_TEST(NamedPropertyHandlerGetter) {
2197 echo_named_call_count = 0;
2198 v8::HandleScope scope(CcTest::isolate());
2199 v8::Handle<v8::FunctionTemplate> templ =
2200 v8::FunctionTemplate::New(CcTest::isolate());
2201 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2205 env->Global()->Set(v8_str("obj"),
2206 templ->GetFunction()->NewInstance());
2207 CHECK_EQ(echo_named_call_count, 0);
2208 v8_compile("obj.x")->Run();
2209 CHECK_EQ(echo_named_call_count, 1);
2210 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2211 v8::Handle<Value> str = CompileRun(code);
2212 String::Utf8Value value(str);
2213 CHECK_EQ(*value, "oddlepoddle");
2214 // Check default behavior
2215 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2216 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2217 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2221 int echo_indexed_call_count = 0;
2224 static void EchoIndexedProperty(
2226 const v8::PropertyCallbackInfo<v8::Value>& info) {
2227 ApiTestFuzzer::Fuzz();
2228 CHECK_EQ(v8_num(637), info.Data());
2229 echo_indexed_call_count++;
2230 info.GetReturnValue().Set(v8_num(index));
2234 THREADED_TEST(IndexedPropertyHandlerGetter) {
2235 v8::Isolate* isolate = CcTest::isolate();
2236 v8::HandleScope scope(isolate);
2237 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2238 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2242 env->Global()->Set(v8_str("obj"),
2243 templ->GetFunction()->NewInstance());
2244 Local<Script> script = v8_compile("obj[900]");
2245 CHECK_EQ(script->Run()->Int32Value(), 900);
2249 v8::Handle<v8::Object> bottom;
2251 static void CheckThisIndexedPropertyHandler(
2253 const v8::PropertyCallbackInfo<v8::Value>& info) {
2254 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2255 ApiTestFuzzer::Fuzz();
2256 CHECK(info.This()->Equals(bottom));
2259 static void CheckThisNamedPropertyHandler(
2261 const v8::PropertyCallbackInfo<v8::Value>& info) {
2262 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2263 ApiTestFuzzer::Fuzz();
2264 CHECK(info.This()->Equals(bottom));
2267 void CheckThisIndexedPropertySetter(
2270 const v8::PropertyCallbackInfo<v8::Value>& info) {
2271 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2272 ApiTestFuzzer::Fuzz();
2273 CHECK(info.This()->Equals(bottom));
2277 void CheckThisNamedPropertySetter(
2278 Local<String> property,
2280 const v8::PropertyCallbackInfo<v8::Value>& info) {
2281 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2282 ApiTestFuzzer::Fuzz();
2283 CHECK(info.This()->Equals(bottom));
2286 void CheckThisIndexedPropertyQuery(
2288 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2289 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2290 ApiTestFuzzer::Fuzz();
2291 CHECK(info.This()->Equals(bottom));
2295 void CheckThisNamedPropertyQuery(
2296 Local<String> property,
2297 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2298 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2299 ApiTestFuzzer::Fuzz();
2300 CHECK(info.This()->Equals(bottom));
2304 void CheckThisIndexedPropertyDeleter(
2306 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2307 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2308 ApiTestFuzzer::Fuzz();
2309 CHECK(info.This()->Equals(bottom));
2313 void CheckThisNamedPropertyDeleter(
2314 Local<String> property,
2315 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2316 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2317 ApiTestFuzzer::Fuzz();
2318 CHECK(info.This()->Equals(bottom));
2322 void CheckThisIndexedPropertyEnumerator(
2323 const v8::PropertyCallbackInfo<v8::Array>& info) {
2324 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2325 ApiTestFuzzer::Fuzz();
2326 CHECK(info.This()->Equals(bottom));
2330 void CheckThisNamedPropertyEnumerator(
2331 const v8::PropertyCallbackInfo<v8::Array>& info) {
2332 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2333 ApiTestFuzzer::Fuzz();
2334 CHECK(info.This()->Equals(bottom));
2338 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2340 v8::Isolate* isolate = env->GetIsolate();
2341 v8::HandleScope scope(isolate);
2343 // Set up a prototype chain with three interceptors.
2344 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2345 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2346 CheckThisIndexedPropertyHandler,
2347 CheckThisIndexedPropertySetter,
2348 CheckThisIndexedPropertyQuery,
2349 CheckThisIndexedPropertyDeleter,
2350 CheckThisIndexedPropertyEnumerator);
2352 templ->InstanceTemplate()->SetNamedPropertyHandler(
2353 CheckThisNamedPropertyHandler,
2354 CheckThisNamedPropertySetter,
2355 CheckThisNamedPropertyQuery,
2356 CheckThisNamedPropertyDeleter,
2357 CheckThisNamedPropertyEnumerator);
2359 bottom = templ->GetFunction()->NewInstance();
2360 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2361 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2363 bottom->SetPrototype(middle);
2364 middle->SetPrototype(top);
2365 env->Global()->Set(v8_str("obj"), bottom);
2367 // Indexed and named get.
2368 CompileRun("obj[0]");
2369 CompileRun("obj.x");
2371 // Indexed and named set.
2372 CompileRun("obj[1] = 42");
2373 CompileRun("obj.y = 42");
2375 // Indexed and named query.
2376 CompileRun("0 in obj");
2377 CompileRun("'x' in obj");
2379 // Indexed and named deleter.
2380 CompileRun("delete obj[0]");
2381 CompileRun("delete obj.x");
2384 CompileRun("for (var p in obj) ;");
2388 static void PrePropertyHandlerGet(
2390 const v8::PropertyCallbackInfo<v8::Value>& info) {
2391 ApiTestFuzzer::Fuzz();
2392 if (v8_str("pre")->Equals(key)) {
2393 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2398 static void PrePropertyHandlerQuery(
2400 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2401 if (v8_str("pre")->Equals(key)) {
2402 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2407 THREADED_TEST(PrePropertyHandler) {
2408 v8::Isolate* isolate = CcTest::isolate();
2409 v8::HandleScope scope(isolate);
2410 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2411 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2413 PrePropertyHandlerQuery);
2414 LocalContext env(NULL, desc->InstanceTemplate());
2415 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2416 v8::Handle<Value> result_pre = CompileRun("pre");
2417 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2418 v8::Handle<Value> result_on = CompileRun("on");
2419 CHECK_EQ(v8_str("Object: on"), result_on);
2420 v8::Handle<Value> result_post = CompileRun("post");
2421 CHECK(result_post.IsEmpty());
2425 THREADED_TEST(UndefinedIsNotEnumerable) {
2427 v8::HandleScope scope(env->GetIsolate());
2428 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2429 CHECK(result->IsFalse());
2433 v8::Handle<Script> call_recursively_script;
2434 static const int kTargetRecursionDepth = 200; // near maximum
2437 static void CallScriptRecursivelyCall(
2438 const v8::FunctionCallbackInfo<v8::Value>& args) {
2439 ApiTestFuzzer::Fuzz();
2440 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2441 if (depth == kTargetRecursionDepth) return;
2442 args.This()->Set(v8_str("depth"),
2443 v8::Integer::New(args.GetIsolate(), depth + 1));
2444 args.GetReturnValue().Set(call_recursively_script->Run());
2448 static void CallFunctionRecursivelyCall(
2449 const v8::FunctionCallbackInfo<v8::Value>& args) {
2450 ApiTestFuzzer::Fuzz();
2451 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2452 if (depth == kTargetRecursionDepth) {
2453 printf("[depth = %d]\n", depth);
2456 args.This()->Set(v8_str("depth"),
2457 v8::Integer::New(args.GetIsolate(), depth + 1));
2458 v8::Handle<Value> function =
2459 args.This()->Get(v8_str("callFunctionRecursively"));
2460 args.GetReturnValue().Set(
2461 function.As<Function>()->Call(args.This(), 0, NULL));
2465 THREADED_TEST(DeepCrossLanguageRecursion) {
2466 v8::Isolate* isolate = CcTest::isolate();
2467 v8::HandleScope scope(isolate);
2468 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2469 global->Set(v8_str("callScriptRecursively"),
2470 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2471 global->Set(v8_str("callFunctionRecursively"),
2472 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2473 LocalContext env(NULL, global);
2475 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2476 call_recursively_script = v8_compile("callScriptRecursively()");
2477 call_recursively_script->Run();
2478 call_recursively_script = v8::Handle<Script>();
2480 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2481 CompileRun("callFunctionRecursively()");
2485 static void ThrowingPropertyHandlerGet(
2487 const v8::PropertyCallbackInfo<v8::Value>& info) {
2488 ApiTestFuzzer::Fuzz();
2489 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2493 static void ThrowingPropertyHandlerSet(
2496 const v8::PropertyCallbackInfo<v8::Value>& info) {
2497 info.GetIsolate()->ThrowException(key);
2498 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2502 THREADED_TEST(CallbackExceptionRegression) {
2503 v8::Isolate* isolate = CcTest::isolate();
2504 v8::HandleScope scope(isolate);
2505 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2506 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2507 ThrowingPropertyHandlerSet);
2509 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2510 v8::Handle<Value> otto = CompileRun(
2511 "try { with (obj) { otto; } } catch (e) { e; }");
2512 CHECK_EQ(v8_str("otto"), otto);
2513 v8::Handle<Value> netto = CompileRun(
2514 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2515 CHECK_EQ(v8_str("netto"), netto);
2519 THREADED_TEST(FunctionPrototype) {
2520 v8::Isolate* isolate = CcTest::isolate();
2521 v8::HandleScope scope(isolate);
2522 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2523 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2525 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2526 Local<Script> script = v8_compile("Foo.prototype.plak");
2527 CHECK_EQ(script->Run()->Int32Value(), 321);
2531 THREADED_TEST(InternalFields) {
2533 v8::Isolate* isolate = env->GetIsolate();
2534 v8::HandleScope scope(isolate);
2536 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2537 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2538 instance_templ->SetInternalFieldCount(1);
2539 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2540 CHECK_EQ(1, obj->InternalFieldCount());
2541 CHECK(obj->GetInternalField(0)->IsUndefined());
2542 obj->SetInternalField(0, v8_num(17));
2543 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2547 THREADED_TEST(GlobalObjectInternalFields) {
2548 v8::Isolate* isolate = CcTest::isolate();
2549 v8::HandleScope scope(isolate);
2550 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2551 global_template->SetInternalFieldCount(1);
2552 LocalContext env(NULL, global_template);
2553 v8::Handle<v8::Object> global_proxy = env->Global();
2554 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2555 CHECK_EQ(1, global->InternalFieldCount());
2556 CHECK(global->GetInternalField(0)->IsUndefined());
2557 global->SetInternalField(0, v8_num(17));
2558 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2562 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2564 v8::HandleScope scope(CcTest::isolate());
2566 v8::Local<v8::Object> global = env->Global();
2567 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2568 CHECK(global->HasRealIndexedProperty(0));
2572 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2574 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2575 obj->SetAlignedPointerInInternalField(0, value);
2576 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2577 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2581 THREADED_TEST(InternalFieldsAlignedPointers) {
2583 v8::Isolate* isolate = env->GetIsolate();
2584 v8::HandleScope scope(isolate);
2586 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2587 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2588 instance_templ->SetInternalFieldCount(1);
2589 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2590 CHECK_EQ(1, obj->InternalFieldCount());
2592 CheckAlignedPointerInInternalField(obj, NULL);
2594 int* heap_allocated = new int[100];
2595 CheckAlignedPointerInInternalField(obj, heap_allocated);
2596 delete[] heap_allocated;
2598 int stack_allocated[100];
2599 CheckAlignedPointerInInternalField(obj, stack_allocated);
2601 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2602 CheckAlignedPointerInInternalField(obj, huge);
2604 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2605 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2606 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2610 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2613 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2614 (*env)->SetAlignedPointerInEmbedderData(index, value);
2615 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2616 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2620 static void* AlignedTestPointer(int i) {
2621 return reinterpret_cast<void*>(i * 1234);
2625 THREADED_TEST(EmbedderDataAlignedPointers) {
2627 v8::HandleScope scope(env->GetIsolate());
2629 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2631 int* heap_allocated = new int[100];
2632 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2633 delete[] heap_allocated;
2635 int stack_allocated[100];
2636 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2638 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2639 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2641 // Test growing of the embedder data's backing store.
2642 for (int i = 0; i < 100; i++) {
2643 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2645 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2646 for (int i = 0; i < 100; i++) {
2647 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2652 static void CheckEmbedderData(LocalContext* env,
2654 v8::Handle<Value> data) {
2655 (*env)->SetEmbedderData(index, data);
2656 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2660 THREADED_TEST(EmbedderData) {
2662 v8::Isolate* isolate = env->GetIsolate();
2663 v8::HandleScope scope(isolate);
2667 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2668 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2669 "over the lazy dog."));
2670 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2671 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2675 THREADED_TEST(IdentityHash) {
2677 v8::Isolate* isolate = env->GetIsolate();
2678 v8::HandleScope scope(isolate);
2680 // Ensure that the test starts with an fresh heap to test whether the hash
2681 // code is based on the address.
2682 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2683 Local<v8::Object> obj = v8::Object::New(isolate);
2684 int hash = obj->GetIdentityHash();
2685 int hash1 = obj->GetIdentityHash();
2686 CHECK_EQ(hash, hash1);
2687 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2688 // Since the identity hash is essentially a random number two consecutive
2689 // objects should not be assigned the same hash code. If the test below fails
2690 // the random number generator should be evaluated.
2691 CHECK_NE(hash, hash2);
2692 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2693 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2694 // Make sure that the identity hash is not based on the initial address of
2695 // the object alone. If the test below fails the random number generator
2696 // should be evaluated.
2697 CHECK_NE(hash, hash3);
2698 int hash4 = obj->GetIdentityHash();
2699 CHECK_EQ(hash, hash4);
2701 // Check identity hashes behaviour in the presence of JS accessors.
2702 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2704 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2705 Local<v8::Object> o1 = v8::Object::New(isolate);
2706 Local<v8::Object> o2 = v8::Object::New(isolate);
2707 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2711 "function cnst() { return 42; };\n"
2712 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2713 Local<v8::Object> o1 = v8::Object::New(isolate);
2714 Local<v8::Object> o2 = v8::Object::New(isolate);
2715 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2720 THREADED_TEST(GlobalProxyIdentityHash) {
2722 v8::Isolate* isolate = env->GetIsolate();
2723 v8::HandleScope scope(isolate);
2724 Handle<Object> global_proxy = env->Global();
2725 int hash1 = global_proxy->GetIdentityHash();
2726 // Hash should be retained after being detached.
2727 env->DetachGlobal();
2728 int hash2 = global_proxy->GetIdentityHash();
2729 CHECK_EQ(hash1, hash2);
2731 // Re-attach global proxy to a new context, hash should stay the same.
2732 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2733 int hash3 = global_proxy->GetIdentityHash();
2734 CHECK_EQ(hash1, hash3);
2739 THREADED_TEST(SymbolProperties) {
2740 i::FLAG_harmony_symbols = true;
2743 v8::Isolate* isolate = env->GetIsolate();
2744 v8::HandleScope scope(isolate);
2746 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2747 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2748 v8::Local<v8::Symbol> sym2 =
2749 v8::Symbol::New(isolate, v8_str("my-symbol"));
2751 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2753 // Check basic symbol functionality.
2754 CHECK(sym1->IsSymbol());
2755 CHECK(sym2->IsSymbol());
2756 CHECK(!obj->IsSymbol());
2758 CHECK(sym1->Equals(sym1));
2759 CHECK(sym2->Equals(sym2));
2760 CHECK(!sym1->Equals(sym2));
2761 CHECK(!sym2->Equals(sym1));
2762 CHECK(sym1->StrictEquals(sym1));
2763 CHECK(sym2->StrictEquals(sym2));
2764 CHECK(!sym1->StrictEquals(sym2));
2765 CHECK(!sym2->StrictEquals(sym1));
2767 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2769 v8::Local<v8::Value> sym_val = sym2;
2770 CHECK(sym_val->IsSymbol());
2771 CHECK(sym_val->Equals(sym2));
2772 CHECK(sym_val->StrictEquals(sym2));
2773 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2775 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2776 CHECK(sym_obj->IsSymbolObject());
2777 CHECK(!sym2->IsSymbolObject());
2778 CHECK(!obj->IsSymbolObject());
2779 CHECK(!sym_obj->Equals(sym2));
2780 CHECK(!sym_obj->StrictEquals(sym2));
2781 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2782 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2784 // Make sure delete of a non-existent symbol property works.
2785 CHECK(obj->Delete(sym1));
2786 CHECK(!obj->Has(sym1));
2788 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2789 CHECK(obj->Has(sym1));
2790 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2791 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2792 CHECK(obj->Has(sym1));
2793 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2794 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2796 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2797 int num_props = obj->GetPropertyNames()->Length();
2798 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2799 v8::Integer::New(isolate, 20)));
2800 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2801 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2803 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2805 // Add another property and delete it afterwards to force the object in
2807 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2808 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2809 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2810 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2811 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2813 CHECK(obj->Has(sym1));
2814 CHECK(obj->Has(sym2));
2815 CHECK(obj->Delete(sym2));
2816 CHECK(obj->Has(sym1));
2817 CHECK(!obj->Has(sym2));
2818 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2821 // Symbol properties are inherited.
2822 v8::Local<v8::Object> child = v8::Object::New(isolate);
2823 child->SetPrototype(obj);
2824 CHECK(child->Has(sym1));
2825 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2826 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2830 THREADED_TEST(PrivateProperties) {
2832 v8::Isolate* isolate = env->GetIsolate();
2833 v8::HandleScope scope(isolate);
2835 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2836 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2837 v8::Local<v8::Private> priv2 =
2838 v8::Private::New(isolate, v8_str("my-private"));
2840 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2842 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2844 // Make sure delete of a non-existent private symbol property works.
2845 CHECK(obj->DeletePrivate(priv1));
2846 CHECK(!obj->HasPrivate(priv1));
2848 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2849 CHECK(obj->HasPrivate(priv1));
2850 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2851 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2852 CHECK(obj->HasPrivate(priv1));
2853 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2855 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2856 int num_props = obj->GetPropertyNames()->Length();
2857 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2858 v8::Integer::New(isolate, 20)));
2859 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2860 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2862 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2864 // Add another property and delete it afterwards to force the object in
2866 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2867 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2868 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2869 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2870 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2872 CHECK(obj->HasPrivate(priv1));
2873 CHECK(obj->HasPrivate(priv2));
2874 CHECK(obj->DeletePrivate(priv2));
2875 CHECK(obj->HasPrivate(priv1));
2876 CHECK(!obj->HasPrivate(priv2));
2877 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2878 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2880 // Private properties are inherited (for the time being).
2881 v8::Local<v8::Object> child = v8::Object::New(isolate);
2882 child->SetPrototype(obj);
2883 CHECK(child->HasPrivate(priv1));
2884 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2885 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2889 THREADED_TEST(GlobalSymbols) {
2890 i::FLAG_harmony_symbols = true;
2893 v8::Isolate* isolate = env->GetIsolate();
2894 v8::HandleScope scope(isolate);
2896 v8::Local<String> name = v8_str("my-symbol");
2897 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2898 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2899 CHECK(glob2->SameValue(glob));
2901 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2902 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2903 CHECK(glob_api2->SameValue(glob_api));
2904 CHECK(!glob_api->SameValue(glob));
2906 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2907 CHECK(!sym->SameValue(glob));
2909 CompileRun("var sym2 = Symbol.for('my-symbol')");
2910 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2911 CHECK(sym2->SameValue(glob));
2912 CHECK(!sym2->SameValue(glob_api));
2916 THREADED_TEST(GlobalPrivates) {
2918 v8::Isolate* isolate = env->GetIsolate();
2919 v8::HandleScope scope(isolate);
2921 v8::Local<String> name = v8_str("my-private");
2922 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2923 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2924 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2926 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2927 CHECK(obj->HasPrivate(glob2));
2929 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2930 CHECK(!obj->HasPrivate(priv));
2932 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2933 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2934 CHECK(!obj->Has(intern));
2938 class ScopedArrayBufferContents {
2940 explicit ScopedArrayBufferContents(
2941 const v8::ArrayBuffer::Contents& contents)
2942 : contents_(contents) {}
2943 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2944 void* Data() const { return contents_.Data(); }
2945 size_t ByteLength() const { return contents_.ByteLength(); }
2947 const v8::ArrayBuffer::Contents contents_;
2950 template <typename T>
2951 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2952 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2953 for (int i = 0; i < value->InternalFieldCount(); i++) {
2954 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2959 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2961 v8::Isolate* isolate = env->GetIsolate();
2962 v8::HandleScope handle_scope(isolate);
2964 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2965 CheckInternalFieldsAreZero(ab);
2966 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2967 CHECK(!ab->IsExternal());
2968 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2970 ScopedArrayBufferContents ab_contents(ab->Externalize());
2971 CHECK(ab->IsExternal());
2973 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2974 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2975 ASSERT(data != NULL);
2976 env->Global()->Set(v8_str("ab"), ab);
2978 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2979 CHECK_EQ(1024, result->Int32Value());
2981 result = CompileRun("var u8 = new Uint8Array(ab);"
2985 CHECK_EQ(1024, result->Int32Value());
2986 CHECK_EQ(0xFF, data[0]);
2987 CHECK_EQ(0xAA, data[1]);
2990 result = CompileRun("u8[0] + u8[1]");
2991 CHECK_EQ(0xDD, result->Int32Value());
2995 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2997 v8::Isolate* isolate = env->GetIsolate();
2998 v8::HandleScope handle_scope(isolate);
3001 v8::Local<v8::Value> result =
3002 CompileRun("var ab1 = new ArrayBuffer(2);"
3003 "var u8_a = new Uint8Array(ab1);"
3005 "u8_a[1] = 0xFF; u8_a.buffer");
3006 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3007 CheckInternalFieldsAreZero(ab1);
3008 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3009 CHECK(!ab1->IsExternal());
3010 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3011 CHECK(ab1->IsExternal());
3013 result = CompileRun("ab1.byteLength");
3014 CHECK_EQ(2, result->Int32Value());
3015 result = CompileRun("u8_a[0]");
3016 CHECK_EQ(0xAA, result->Int32Value());
3017 result = CompileRun("u8_a[1]");
3018 CHECK_EQ(0xFF, result->Int32Value());
3019 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3022 CHECK_EQ(0xBB, result->Int32Value());
3023 result = CompileRun("u8_b[1]");
3024 CHECK_EQ(0xFF, result->Int32Value());
3026 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3027 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3028 CHECK_EQ(0xBB, ab1_data[0]);
3029 CHECK_EQ(0xFF, ab1_data[1]);
3032 result = CompileRun("u8_a[0] + u8_a[1]");
3033 CHECK_EQ(0xDD, result->Int32Value());
3037 THREADED_TEST(ArrayBuffer_External) {
3039 v8::Isolate* isolate = env->GetIsolate();
3040 v8::HandleScope handle_scope(isolate);
3042 i::ScopedVector<uint8_t> my_data(100);
3043 memset(my_data.start(), 0, 100);
3044 Local<v8::ArrayBuffer> ab3 =
3045 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3046 CheckInternalFieldsAreZero(ab3);
3047 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3048 CHECK(ab3->IsExternal());
3050 env->Global()->Set(v8_str("ab3"), ab3);
3052 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3053 CHECK_EQ(100, result->Int32Value());
3055 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3059 CHECK_EQ(100, result->Int32Value());
3060 CHECK_EQ(0xBB, my_data[0]);
3061 CHECK_EQ(0xCC, my_data[1]);
3064 result = CompileRun("u8_b[0] + u8_b[1]");
3065 CHECK_EQ(0xDD, result->Int32Value());
3069 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3070 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3071 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3075 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3076 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3077 CHECK_EQ(0, static_cast<int>(ta->Length()));
3078 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3082 static void CheckIsTypedArrayVarNeutered(const char* name) {
3083 i::ScopedVector<char> source(1024);
3085 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3087 CHECK(CompileRun(source.start())->IsTrue());
3088 v8::Handle<v8::TypedArray> ta =
3089 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3090 CheckIsNeutered(ta);
3094 template <typename TypedArray, int kElementSize>
3095 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3098 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3099 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3100 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3101 CHECK_EQ(length, static_cast<int>(ta->Length()));
3102 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3107 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3109 v8::Isolate* isolate = env->GetIsolate();
3110 v8::HandleScope handle_scope(isolate);
3112 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3114 v8::Handle<v8::Uint8Array> u8a =
3115 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3116 v8::Handle<v8::Uint8ClampedArray> u8c =
3117 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3118 v8::Handle<v8::Int8Array> i8a =
3119 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3121 v8::Handle<v8::Uint16Array> u16a =
3122 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3123 v8::Handle<v8::Int16Array> i16a =
3124 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3126 v8::Handle<v8::Uint32Array> u32a =
3127 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3128 v8::Handle<v8::Int32Array> i32a =
3129 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3131 v8::Handle<v8::Float32Array> f32a =
3132 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3133 v8::Handle<v8::Float64Array> f64a =
3134 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3136 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3137 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3138 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3139 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3141 ScopedArrayBufferContents contents(buffer->Externalize());
3143 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3144 CheckIsNeutered(u8a);
3145 CheckIsNeutered(u8c);
3146 CheckIsNeutered(i8a);
3147 CheckIsNeutered(u16a);
3148 CheckIsNeutered(i16a);
3149 CheckIsNeutered(u32a);
3150 CheckIsNeutered(i32a);
3151 CheckIsNeutered(f32a);
3152 CheckIsNeutered(f64a);
3153 CheckDataViewIsNeutered(dv);
3157 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3159 v8::Isolate* isolate = env->GetIsolate();
3160 v8::HandleScope handle_scope(isolate);
3163 "var ab = new ArrayBuffer(1024);"
3164 "var u8a = new Uint8Array(ab, 1, 1023);"
3165 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3166 "var i8a = new Int8Array(ab, 1, 1023);"
3167 "var u16a = new Uint16Array(ab, 2, 511);"
3168 "var i16a = new Int16Array(ab, 2, 511);"
3169 "var u32a = new Uint32Array(ab, 4, 255);"
3170 "var i32a = new Int32Array(ab, 4, 255);"
3171 "var f32a = new Float32Array(ab, 4, 255);"
3172 "var f64a = new Float64Array(ab, 8, 127);"
3173 "var dv = new DataView(ab, 1, 1023);");
3175 v8::Handle<v8::ArrayBuffer> ab =
3176 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3178 v8::Handle<v8::DataView> dv =
3179 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3181 ScopedArrayBufferContents contents(ab->Externalize());
3183 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3184 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3186 CheckIsTypedArrayVarNeutered("u8a");
3187 CheckIsTypedArrayVarNeutered("u8c");
3188 CheckIsTypedArrayVarNeutered("i8a");
3189 CheckIsTypedArrayVarNeutered("u16a");
3190 CheckIsTypedArrayVarNeutered("i16a");
3191 CheckIsTypedArrayVarNeutered("u32a");
3192 CheckIsTypedArrayVarNeutered("i32a");
3193 CheckIsTypedArrayVarNeutered("f32a");
3194 CheckIsTypedArrayVarNeutered("f64a");
3196 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3197 CheckDataViewIsNeutered(dv);
3202 THREADED_TEST(HiddenProperties) {
3204 v8::Isolate* isolate = env->GetIsolate();
3205 v8::HandleScope scope(isolate);
3207 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3208 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3209 v8::Local<v8::String> empty = v8_str("");
3210 v8::Local<v8::String> prop_name = v8_str("prop_name");
3212 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3214 // Make sure delete of a non-existent hidden value works
3215 CHECK(obj->DeleteHiddenValue(key));
3217 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3218 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3219 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3220 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3222 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3224 // Make sure we do not find the hidden property.
3225 CHECK(!obj->Has(empty));
3226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3227 CHECK(obj->Get(empty)->IsUndefined());
3228 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3229 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3230 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3231 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3233 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3235 // Add another property and delete it afterwards to force the object in
3237 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3240 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241 CHECK(obj->Delete(prop_name));
3242 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3244 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3246 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3247 CHECK(obj->GetHiddenValue(key).IsEmpty());
3249 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3250 CHECK(obj->DeleteHiddenValue(key));
3251 CHECK(obj->GetHiddenValue(key).IsEmpty());
3255 THREADED_TEST(Regress97784) {
3256 // Regression test for crbug.com/97784
3257 // Messing with the Object.prototype should not have effect on
3258 // hidden properties.
3260 v8::HandleScope scope(env->GetIsolate());
3262 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3263 v8::Local<v8::String> key = v8_str("hidden");
3266 "set_called = false;"
3267 "Object.defineProperty("
3268 " Object.prototype,"
3270 " {get: function() { return 45; },"
3271 " set: function() { set_called = true; }})");
3273 CHECK(obj->GetHiddenValue(key).IsEmpty());
3274 // Make sure that the getter and setter from Object.prototype is not invoked.
3275 // If it did we would have full access to the hidden properties in
3277 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3278 ExpectFalse("set_called");
3279 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3283 static bool interceptor_for_hidden_properties_called;
3284 static void InterceptorForHiddenProperties(
3285 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3286 interceptor_for_hidden_properties_called = true;
3290 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3291 LocalContext context;
3292 v8::Isolate* isolate = context->GetIsolate();
3293 v8::HandleScope scope(isolate);
3295 interceptor_for_hidden_properties_called = false;
3297 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3299 // Associate an interceptor with an object and start setting hidden values.
3300 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3301 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3302 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3303 Local<v8::Function> function = fun_templ->GetFunction();
3304 Local<v8::Object> obj = function->NewInstance();
3305 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3306 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3307 CHECK(!interceptor_for_hidden_properties_called);
3311 THREADED_TEST(External) {
3312 v8::HandleScope scope(CcTest::isolate());
3314 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3316 env->Global()->Set(v8_str("ext"), ext);
3317 Local<Value> reext_obj = CompileRun("this.ext");
3318 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3319 int* ptr = static_cast<int*>(reext->Value());
3324 // Make sure unaligned pointers are wrapped properly.
3325 char* data = i::StrDup("0123456789");
3326 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3327 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3328 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3329 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3331 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3332 CHECK_EQ('0', *char_ptr);
3333 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3334 CHECK_EQ('1', *char_ptr);
3335 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3336 CHECK_EQ('2', *char_ptr);
3337 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3338 CHECK_EQ('3', *char_ptr);
3339 i::DeleteArray(data);
3343 THREADED_TEST(GlobalHandle) {
3344 v8::Isolate* isolate = CcTest::isolate();
3345 v8::Persistent<String> global;
3347 v8::HandleScope scope(isolate);
3348 global.Reset(isolate, v8_str("str"));
3351 v8::HandleScope scope(isolate);
3352 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3356 v8::HandleScope scope(isolate);
3357 global.Reset(isolate, v8_str("str"));
3360 v8::HandleScope scope(isolate);
3361 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3367 THREADED_TEST(ResettingGlobalHandle) {
3368 v8::Isolate* isolate = CcTest::isolate();
3369 v8::Persistent<String> global;
3371 v8::HandleScope scope(isolate);
3372 global.Reset(isolate, v8_str("str"));
3374 v8::internal::GlobalHandles* global_handles =
3375 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3376 int initial_handle_count = global_handles->global_handles_count();
3378 v8::HandleScope scope(isolate);
3379 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3382 v8::HandleScope scope(isolate);
3383 global.Reset(isolate, v8_str("longer"));
3385 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3387 v8::HandleScope scope(isolate);
3388 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3391 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3395 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3396 v8::Isolate* isolate = CcTest::isolate();
3397 v8::Persistent<String> global;
3399 v8::HandleScope scope(isolate);
3400 global.Reset(isolate, v8_str("str"));
3402 v8::internal::GlobalHandles* global_handles =
3403 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3404 int initial_handle_count = global_handles->global_handles_count();
3406 v8::HandleScope scope(isolate);
3407 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3410 v8::HandleScope scope(isolate);
3411 Local<String> empty;
3412 global.Reset(isolate, empty);
3414 CHECK(global.IsEmpty());
3415 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3420 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3421 return unique.Pass();
3426 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3427 const v8::Persistent<T> & global) {
3428 v8::UniquePersistent<String> unique(isolate, global);
3429 return unique.Pass();
3433 THREADED_TEST(UniquePersistent) {
3434 v8::Isolate* isolate = CcTest::isolate();
3435 v8::Persistent<String> global;
3437 v8::HandleScope scope(isolate);
3438 global.Reset(isolate, v8_str("str"));
3440 v8::internal::GlobalHandles* global_handles =
3441 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3442 int initial_handle_count = global_handles->global_handles_count();
3444 v8::UniquePersistent<String> unique(isolate, global);
3445 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3446 // Test assignment via Pass
3448 v8::UniquePersistent<String> copy = unique.Pass();
3449 CHECK(unique.IsEmpty());
3450 CHECK(copy == global);
3451 CHECK_EQ(initial_handle_count + 1,
3452 global_handles->global_handles_count());
3453 unique = copy.Pass();
3455 // Test ctor via Pass
3457 v8::UniquePersistent<String> copy(unique.Pass());
3458 CHECK(unique.IsEmpty());
3459 CHECK(copy == global);
3460 CHECK_EQ(initial_handle_count + 1,
3461 global_handles->global_handles_count());
3462 unique = copy.Pass();
3464 // Test pass through function call
3466 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3467 CHECK(unique.IsEmpty());
3468 CHECK(copy == global);
3469 CHECK_EQ(initial_handle_count + 1,
3470 global_handles->global_handles_count());
3471 unique = copy.Pass();
3473 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3475 // Test pass from function call
3477 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3478 CHECK(unique == global);
3479 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3481 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3486 template<typename K, typename V>
3487 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3489 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3491 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3492 struct WeakCallbackDataType {
3496 static WeakCallbackDataType* WeakCallbackParameter(
3497 MapType* map, const K& key, Local<V> value) {
3498 WeakCallbackDataType* data = new WeakCallbackDataType;
3503 static MapType* MapFromWeakCallbackData(
3504 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3505 return data.GetParameter()->map;
3507 static K KeyFromWeakCallbackData(
3508 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3509 return data.GetParameter()->key;
3511 static void DisposeCallbackData(WeakCallbackDataType* data) {
3514 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3519 template<typename Map>
3520 static void TestPersistentValueMap() {
3522 v8::Isolate* isolate = env->GetIsolate();
3524 v8::internal::GlobalHandles* global_handles =
3525 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3526 int initial_handle_count = global_handles->global_handles_count();
3527 CHECK_EQ(0, static_cast<int>(map.Size()));
3529 HandleScope scope(isolate);
3530 Local<v8::Object> obj = map.Get(7);
3531 CHECK(obj.IsEmpty());
3532 Local<v8::Object> expected = v8::Object::New(isolate);
3533 map.Set(7, expected);
3534 CHECK_EQ(1, static_cast<int>(map.Size()));
3536 CHECK_EQ(expected, obj);
3538 typename Map::PersistentValueReference ref = map.GetReference(7);
3539 CHECK_EQ(expected, ref.NewLocal(isolate));
3541 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3542 CHECK_EQ(0, static_cast<int>(map.Size()));
3543 CHECK(expected == removed);
3544 removed = map.Remove(7);
3545 CHECK(removed.IsEmpty());
3546 map.Set(8, expected);
3547 CHECK_EQ(1, static_cast<int>(map.Size()));
3548 map.Set(8, expected);
3549 CHECK_EQ(1, static_cast<int>(map.Size()));
3551 typename Map::PersistentValueReference ref;
3552 Local<v8::Object> expected2 = v8::Object::New(isolate);
3553 removed = map.Set(8,
3554 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3555 CHECK_EQ(1, static_cast<int>(map.Size()));
3556 CHECK(expected == removed);
3557 CHECK_EQ(expected2, ref.NewLocal(isolate));
3560 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3562 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3563 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3567 CHECK_EQ(0, static_cast<int>(map.Size()));
3568 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3572 TEST(PersistentValueMap) {
3573 // Default case, w/o weak callbacks:
3574 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3576 // Custom traits with weak callbacks:
3577 typedef v8::PersistentValueMap<int, v8::Object,
3578 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3579 TestPersistentValueMap<WeakPersistentValueMap>();
3583 TEST(PersistentValueVector) {
3585 v8::Isolate* isolate = env->GetIsolate();
3586 v8::internal::GlobalHandles* global_handles =
3587 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3588 int handle_count = global_handles->global_handles_count();
3589 HandleScope scope(isolate);
3591 v8::PersistentValueVector<v8::Object> vector(isolate);
3593 Local<v8::Object> obj1 = v8::Object::New(isolate);
3594 Local<v8::Object> obj2 = v8::Object::New(isolate);
3595 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3597 CHECK(vector.IsEmpty());
3598 CHECK_EQ(0, static_cast<int>(vector.Size()));
3600 vector.ReserveCapacity(3);
3601 CHECK(vector.IsEmpty());
3603 vector.Append(obj1);
3604 vector.Append(obj2);
3605 vector.Append(obj1);
3606 vector.Append(obj3.Pass());
3607 vector.Append(obj1);
3609 CHECK(!vector.IsEmpty());
3610 CHECK_EQ(5, static_cast<int>(vector.Size()));
3611 CHECK(obj3.IsEmpty());
3612 CHECK_EQ(obj1, vector.Get(0));
3613 CHECK_EQ(obj1, vector.Get(2));
3614 CHECK_EQ(obj1, vector.Get(4));
3615 CHECK_EQ(obj2, vector.Get(1));
3617 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3620 CHECK(vector.IsEmpty());
3621 CHECK_EQ(0, static_cast<int>(vector.Size()));
3622 CHECK_EQ(handle_count, global_handles->global_handles_count());
3626 THREADED_TEST(GlobalHandleUpcast) {
3627 v8::Isolate* isolate = CcTest::isolate();
3628 v8::HandleScope scope(isolate);
3629 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3630 v8::Persistent<String> global_string(isolate, local);
3631 v8::Persistent<Value>& global_value =
3632 v8::Persistent<Value>::Cast(global_string);
3633 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3634 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3635 global_string.Reset();
3639 THREADED_TEST(HandleEquality) {
3640 v8::Isolate* isolate = CcTest::isolate();
3641 v8::Persistent<String> global1;
3642 v8::Persistent<String> global2;
3644 v8::HandleScope scope(isolate);
3645 global1.Reset(isolate, v8_str("str"));
3646 global2.Reset(isolate, v8_str("str2"));
3648 CHECK_EQ(global1 == global1, true);
3649 CHECK_EQ(global1 != global1, false);
3651 v8::HandleScope scope(isolate);
3652 Local<String> local1 = Local<String>::New(isolate, global1);
3653 Local<String> local2 = Local<String>::New(isolate, global2);
3655 CHECK_EQ(global1 == local1, true);
3656 CHECK_EQ(global1 != local1, false);
3657 CHECK_EQ(local1 == global1, true);
3658 CHECK_EQ(local1 != global1, false);
3660 CHECK_EQ(global1 == local2, false);
3661 CHECK_EQ(global1 != local2, true);
3662 CHECK_EQ(local2 == global1, false);
3663 CHECK_EQ(local2 != global1, true);
3665 CHECK_EQ(local1 == local2, false);
3666 CHECK_EQ(local1 != local2, true);
3668 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3669 CHECK_EQ(local1 == anotherLocal1, true);
3670 CHECK_EQ(local1 != anotherLocal1, false);
3677 THREADED_TEST(LocalHandle) {
3678 v8::HandleScope scope(CcTest::isolate());
3679 v8::Local<String> local =
3680 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3681 CHECK_EQ(local->Length(), 3);
3685 class WeakCallCounter {
3687 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3688 int id() { return id_; }
3689 void increment() { number_of_weak_calls_++; }
3690 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3693 int number_of_weak_calls_;
3697 template<typename T>
3698 struct WeakCallCounterAndPersistent {
3699 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3700 : counter(counter) {}
3701 WeakCallCounter* counter;
3702 v8::Persistent<T> handle;
3706 template <typename T>
3707 static void WeakPointerCallback(
3708 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3709 CHECK_EQ(1234, data.GetParameter()->counter->id());
3710 data.GetParameter()->counter->increment();
3711 data.GetParameter()->handle.Reset();
3715 template<typename T>
3716 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3717 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3721 THREADED_TEST(ApiObjectGroups) {
3723 v8::Isolate* iso = env->GetIsolate();
3724 HandleScope scope(iso);
3726 WeakCallCounter counter(1234);
3728 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3729 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3730 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3731 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3732 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3733 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3736 HandleScope scope(iso);
3737 g1s1.handle.Reset(iso, Object::New(iso));
3738 g1s2.handle.Reset(iso, Object::New(iso));
3739 g1c1.handle.Reset(iso, Object::New(iso));
3740 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3741 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3742 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3744 g2s1.handle.Reset(iso, Object::New(iso));
3745 g2s2.handle.Reset(iso, Object::New(iso));
3746 g2c1.handle.Reset(iso, Object::New(iso));
3747 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3748 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3749 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3752 WeakCallCounterAndPersistent<Value> root(&counter);
3753 root.handle.Reset(iso, g1s1.handle); // make a root.
3755 // Connect group 1 and 2, make a cycle.
3757 HandleScope scope(iso);
3758 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3759 Set(0, Local<Value>::New(iso, g2s2.handle)));
3760 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3761 Set(0, Local<Value>::New(iso, g1s1.handle)));
3765 UniqueId id1 = MakeUniqueId(g1s1.handle);
3766 UniqueId id2 = MakeUniqueId(g2s2.handle);
3767 iso->SetObjectGroupId(g1s1.handle, id1);
3768 iso->SetObjectGroupId(g1s2.handle, id1);
3769 iso->SetReferenceFromGroup(id1, g1c1.handle);
3770 iso->SetObjectGroupId(g2s1.handle, id2);
3771 iso->SetObjectGroupId(g2s2.handle, id2);
3772 iso->SetReferenceFromGroup(id2, g2c1.handle);
3774 // Do a single full GC, ensure incremental marking is stopped.
3775 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3777 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3779 // All object should be alive.
3780 CHECK_EQ(0, counter.NumberOfWeakCalls());
3783 root.handle.SetWeak(&root, &WeakPointerCallback);
3784 // But make children strong roots---all the objects (except for children)
3785 // should be collectable now.
3786 g1c1.handle.ClearWeak();
3787 g2c1.handle.ClearWeak();
3789 // Groups are deleted, rebuild groups.
3791 UniqueId id1 = MakeUniqueId(g1s1.handle);
3792 UniqueId id2 = MakeUniqueId(g2s2.handle);
3793 iso->SetObjectGroupId(g1s1.handle, id1);
3794 iso->SetObjectGroupId(g1s2.handle, id1);
3795 iso->SetReferenceFromGroup(id1, g1c1.handle);
3796 iso->SetObjectGroupId(g2s1.handle, id2);
3797 iso->SetObjectGroupId(g2s2.handle, id2);
3798 iso->SetReferenceFromGroup(id2, g2c1.handle);
3801 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3803 // All objects should be gone. 5 global handles in total.
3804 CHECK_EQ(5, counter.NumberOfWeakCalls());
3806 // And now make children weak again and collect them.
3807 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3808 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3810 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3811 CHECK_EQ(7, counter.NumberOfWeakCalls());
3815 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3817 v8::Isolate* iso = env->GetIsolate();
3818 HandleScope scope(iso);
3820 WeakCallCounter counter(1234);
3822 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3823 WeakCallCounterAndPersistent<String> g1s2(&counter);
3824 WeakCallCounterAndPersistent<String> g1c1(&counter);
3825 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3826 WeakCallCounterAndPersistent<String> g2s2(&counter);
3827 WeakCallCounterAndPersistent<String> g2c1(&counter);
3830 HandleScope scope(iso);
3831 g1s1.handle.Reset(iso, Object::New(iso));
3832 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3833 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3834 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3835 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3836 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3838 g2s1.handle.Reset(iso, Object::New(iso));
3839 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3840 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3841 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3842 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3843 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3846 WeakCallCounterAndPersistent<Value> root(&counter);
3847 root.handle.Reset(iso, g1s1.handle); // make a root.
3849 // Connect group 1 and 2, make a cycle.
3851 HandleScope scope(iso);
3852 CHECK(Local<Object>::New(iso, g1s1.handle)
3853 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3854 CHECK(Local<Object>::New(iso, g2s1.handle)
3855 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3859 UniqueId id1 = MakeUniqueId(g1s1.handle);
3860 UniqueId id2 = MakeUniqueId(g2s2.handle);
3861 iso->SetObjectGroupId(g1s1.handle, id1);
3862 iso->SetObjectGroupId(g1s2.handle, id1);
3863 iso->SetReference(g1s1.handle, g1c1.handle);
3864 iso->SetObjectGroupId(g2s1.handle, id2);
3865 iso->SetObjectGroupId(g2s2.handle, id2);
3866 iso->SetReferenceFromGroup(id2, g2c1.handle);
3868 // Do a single full GC, ensure incremental marking is stopped.
3869 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3871 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3873 // All object should be alive.
3874 CHECK_EQ(0, counter.NumberOfWeakCalls());
3877 root.handle.SetWeak(&root, &WeakPointerCallback);
3878 // But make children strong roots---all the objects (except for children)
3879 // should be collectable now.
3880 g1c1.handle.ClearWeak();
3881 g2c1.handle.ClearWeak();
3883 // Groups are deleted, rebuild groups.
3885 UniqueId id1 = MakeUniqueId(g1s1.handle);
3886 UniqueId id2 = MakeUniqueId(g2s2.handle);
3887 iso->SetObjectGroupId(g1s1.handle, id1);
3888 iso->SetObjectGroupId(g1s2.handle, id1);
3889 iso->SetReference(g1s1.handle, g1c1.handle);
3890 iso->SetObjectGroupId(g2s1.handle, id2);
3891 iso->SetObjectGroupId(g2s2.handle, id2);
3892 iso->SetReferenceFromGroup(id2, g2c1.handle);
3895 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3897 // All objects should be gone. 5 global handles in total.
3898 CHECK_EQ(5, counter.NumberOfWeakCalls());
3900 // And now make children weak again and collect them.
3901 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3902 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3904 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3905 CHECK_EQ(7, counter.NumberOfWeakCalls());
3909 THREADED_TEST(ApiObjectGroupsCycle) {
3911 v8::Isolate* iso = env->GetIsolate();
3912 HandleScope scope(iso);
3914 WeakCallCounter counter(1234);
3916 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3917 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3918 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3919 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3920 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3921 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3922 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3923 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3926 HandleScope scope(iso);
3927 g1s1.handle.Reset(iso, Object::New(iso));
3928 g1s2.handle.Reset(iso, Object::New(iso));
3929 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3930 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3931 CHECK(g1s1.handle.IsWeak());
3932 CHECK(g1s2.handle.IsWeak());
3934 g2s1.handle.Reset(iso, Object::New(iso));
3935 g2s2.handle.Reset(iso, Object::New(iso));
3936 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3937 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3938 CHECK(g2s1.handle.IsWeak());
3939 CHECK(g2s2.handle.IsWeak());
3941 g3s1.handle.Reset(iso, Object::New(iso));
3942 g3s2.handle.Reset(iso, Object::New(iso));
3943 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3944 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3945 CHECK(g3s1.handle.IsWeak());
3946 CHECK(g3s2.handle.IsWeak());
3948 g4s1.handle.Reset(iso, Object::New(iso));
3949 g4s2.handle.Reset(iso, Object::New(iso));
3950 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3951 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3952 CHECK(g4s1.handle.IsWeak());
3953 CHECK(g4s2.handle.IsWeak());
3956 WeakCallCounterAndPersistent<Value> root(&counter);
3957 root.handle.Reset(iso, g1s1.handle); // make a root.
3959 // Connect groups. We're building the following cycle:
3960 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3963 UniqueId id1 = MakeUniqueId(g1s1.handle);
3964 UniqueId id2 = MakeUniqueId(g2s1.handle);
3965 UniqueId id3 = MakeUniqueId(g3s1.handle);
3966 UniqueId id4 = MakeUniqueId(g4s1.handle);
3967 iso->SetObjectGroupId(g1s1.handle, id1);
3968 iso->SetObjectGroupId(g1s2.handle, id1);
3969 iso->SetReferenceFromGroup(id1, g2s1.handle);
3970 iso->SetObjectGroupId(g2s1.handle, id2);
3971 iso->SetObjectGroupId(g2s2.handle, id2);
3972 iso->SetReferenceFromGroup(id2, g3s1.handle);
3973 iso->SetObjectGroupId(g3s1.handle, id3);
3974 iso->SetObjectGroupId(g3s2.handle, id3);
3975 iso->SetReferenceFromGroup(id3, g4s1.handle);
3976 iso->SetObjectGroupId(g4s1.handle, id4);
3977 iso->SetObjectGroupId(g4s2.handle, id4);
3978 iso->SetReferenceFromGroup(id4, g1s1.handle);
3980 // Do a single full GC
3981 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3983 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3985 // All object should be alive.
3986 CHECK_EQ(0, counter.NumberOfWeakCalls());
3989 root.handle.SetWeak(&root, &WeakPointerCallback);
3991 // Groups are deleted, rebuild groups.
3993 UniqueId id1 = MakeUniqueId(g1s1.handle);
3994 UniqueId id2 = MakeUniqueId(g2s1.handle);
3995 UniqueId id3 = MakeUniqueId(g3s1.handle);
3996 UniqueId id4 = MakeUniqueId(g4s1.handle);
3997 iso->SetObjectGroupId(g1s1.handle, id1);
3998 iso->SetObjectGroupId(g1s2.handle, id1);
3999 iso->SetReferenceFromGroup(id1, g2s1.handle);
4000 iso->SetObjectGroupId(g2s1.handle, id2);
4001 iso->SetObjectGroupId(g2s2.handle, id2);
4002 iso->SetReferenceFromGroup(id2, g3s1.handle);
4003 iso->SetObjectGroupId(g3s1.handle, id3);
4004 iso->SetObjectGroupId(g3s2.handle, id3);
4005 iso->SetReferenceFromGroup(id3, g4s1.handle);
4006 iso->SetObjectGroupId(g4s1.handle, id4);
4007 iso->SetObjectGroupId(g4s2.handle, id4);
4008 iso->SetReferenceFromGroup(id4, g1s1.handle);
4011 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4013 // All objects should be gone. 9 global handles in total.
4014 CHECK_EQ(9, counter.NumberOfWeakCalls());
4018 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4019 // on the buildbots, so was made non-threaded for the time being.
4020 TEST(ApiObjectGroupsCycleForScavenger) {
4021 i::FLAG_stress_compaction = false;
4022 i::FLAG_gc_global = false;
4024 v8::Isolate* iso = env->GetIsolate();
4025 HandleScope scope(iso);
4027 WeakCallCounter counter(1234);
4029 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4030 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4031 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4032 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4033 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4034 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4037 HandleScope scope(iso);
4038 g1s1.handle.Reset(iso, Object::New(iso));
4039 g1s2.handle.Reset(iso, Object::New(iso));
4040 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4041 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4043 g2s1.handle.Reset(iso, Object::New(iso));
4044 g2s2.handle.Reset(iso, Object::New(iso));
4045 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4046 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4048 g3s1.handle.Reset(iso, Object::New(iso));
4049 g3s2.handle.Reset(iso, Object::New(iso));
4050 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4051 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4055 WeakCallCounterAndPersistent<Value> root(&counter);
4056 root.handle.Reset(iso, g1s1.handle);
4057 root.handle.MarkPartiallyDependent();
4059 // Connect groups. We're building the following cycle:
4060 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4063 HandleScope handle_scope(iso);
4064 g1s1.handle.MarkPartiallyDependent();
4065 g1s2.handle.MarkPartiallyDependent();
4066 g2s1.handle.MarkPartiallyDependent();
4067 g2s2.handle.MarkPartiallyDependent();
4068 g3s1.handle.MarkPartiallyDependent();
4069 g3s2.handle.MarkPartiallyDependent();
4070 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4071 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4072 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4073 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4074 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4075 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4076 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4077 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4078 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4079 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4080 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4081 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4084 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4086 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4088 // All objects should be alive.
4089 CHECK_EQ(0, counter.NumberOfWeakCalls());
4092 root.handle.SetWeak(&root, &WeakPointerCallback);
4093 root.handle.MarkPartiallyDependent();
4095 // Groups are deleted, rebuild groups.
4097 HandleScope handle_scope(iso);
4098 g1s1.handle.MarkPartiallyDependent();
4099 g1s2.handle.MarkPartiallyDependent();
4100 g2s1.handle.MarkPartiallyDependent();
4101 g2s2.handle.MarkPartiallyDependent();
4102 g3s1.handle.MarkPartiallyDependent();
4103 g3s2.handle.MarkPartiallyDependent();
4104 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4105 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4106 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4107 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4108 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4109 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4110 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4111 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4112 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4113 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4114 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4115 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4118 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4120 // All objects should be gone. 7 global handles in total.
4121 CHECK_EQ(7, counter.NumberOfWeakCalls());
4125 THREADED_TEST(ScriptException) {
4127 v8::HandleScope scope(env->GetIsolate());
4128 Local<Script> script = v8_compile("throw 'panama!';");
4129 v8::TryCatch try_catch;
4130 Local<Value> result = script->Run();
4131 CHECK(result.IsEmpty());
4132 CHECK(try_catch.HasCaught());
4133 String::Utf8Value exception_value(try_catch.Exception());
4134 CHECK_EQ(*exception_value, "panama!");
4138 TEST(TryCatchCustomException) {
4140 v8::HandleScope scope(env->GetIsolate());
4141 v8::TryCatch try_catch;
4142 CompileRun("function CustomError() { this.a = 'b'; }"
4143 "(function f() { throw new CustomError(); })();");
4144 CHECK(try_catch.HasCaught());
4145 CHECK(try_catch.Exception()->ToObject()->
4146 Get(v8_str("a"))->Equals(v8_str("b")));
4150 bool message_received;
4153 static void check_message_0(v8::Handle<v8::Message> message,
4154 v8::Handle<Value> data) {
4155 CHECK_EQ(5.76, data->NumberValue());
4156 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4157 CHECK(!message->IsSharedCrossOrigin());
4158 message_received = true;
4162 THREADED_TEST(MessageHandler0) {
4163 message_received = false;
4164 v8::HandleScope scope(CcTest::isolate());
4165 CHECK(!message_received);
4166 LocalContext context;
4167 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4168 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4170 CHECK(message_received);
4171 // clear out the message listener
4172 v8::V8::RemoveMessageListeners(check_message_0);
4176 static void check_message_1(v8::Handle<v8::Message> message,
4177 v8::Handle<Value> data) {
4178 CHECK(data->IsNumber());
4179 CHECK_EQ(1337, data->Int32Value());
4180 CHECK(!message->IsSharedCrossOrigin());
4181 message_received = true;
4185 TEST(MessageHandler1) {
4186 message_received = false;
4187 v8::HandleScope scope(CcTest::isolate());
4188 CHECK(!message_received);
4189 v8::V8::AddMessageListener(check_message_1);
4190 LocalContext context;
4191 CompileRun("throw 1337;");
4192 CHECK(message_received);
4193 // clear out the message listener
4194 v8::V8::RemoveMessageListeners(check_message_1);
4198 static void check_message_2(v8::Handle<v8::Message> message,
4199 v8::Handle<Value> data) {
4200 LocalContext context;
4201 CHECK(data->IsObject());
4202 v8::Local<v8::Value> hidden_property =
4203 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4204 CHECK(v8_str("hidden value")->Equals(hidden_property));
4205 CHECK(!message->IsSharedCrossOrigin());
4206 message_received = true;
4210 TEST(MessageHandler2) {
4211 message_received = false;
4212 v8::HandleScope scope(CcTest::isolate());
4213 CHECK(!message_received);
4214 v8::V8::AddMessageListener(check_message_2);
4215 LocalContext context;
4216 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4217 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4218 v8_str("hidden value"));
4219 context->Global()->Set(v8_str("error"), error);
4220 CompileRun("throw error;");
4221 CHECK(message_received);
4222 // clear out the message listener
4223 v8::V8::RemoveMessageListeners(check_message_2);
4227 static void check_message_3(v8::Handle<v8::Message> message,
4228 v8::Handle<Value> data) {
4229 CHECK(message->IsSharedCrossOrigin());
4230 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4231 message_received = true;
4235 TEST(MessageHandler3) {
4236 message_received = false;
4237 v8::Isolate* isolate = CcTest::isolate();
4238 v8::HandleScope scope(isolate);
4239 CHECK(!message_received);
4240 v8::V8::AddMessageListener(check_message_3);
4241 LocalContext context;
4242 v8::ScriptOrigin origin =
4243 v8::ScriptOrigin(v8_str("6.75"),
4244 v8::Integer::New(isolate, 1),
4245 v8::Integer::New(isolate, 2),
4247 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4250 CHECK(message_received);
4251 // clear out the message listener
4252 v8::V8::RemoveMessageListeners(check_message_3);
4256 static void check_message_4(v8::Handle<v8::Message> message,
4257 v8::Handle<Value> data) {
4258 CHECK(!message->IsSharedCrossOrigin());
4259 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4260 message_received = true;
4264 TEST(MessageHandler4) {
4265 message_received = false;
4266 v8::Isolate* isolate = CcTest::isolate();
4267 v8::HandleScope scope(isolate);
4268 CHECK(!message_received);
4269 v8::V8::AddMessageListener(check_message_4);
4270 LocalContext context;
4271 v8::ScriptOrigin origin =
4272 v8::ScriptOrigin(v8_str("6.75"),
4273 v8::Integer::New(isolate, 1),
4274 v8::Integer::New(isolate, 2),
4275 v8::False(isolate));
4276 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4279 CHECK(message_received);
4280 // clear out the message listener
4281 v8::V8::RemoveMessageListeners(check_message_4);
4285 static void check_message_5a(v8::Handle<v8::Message> message,
4286 v8::Handle<Value> data) {
4287 CHECK(message->IsSharedCrossOrigin());
4288 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4289 message_received = true;
4293 static void check_message_5b(v8::Handle<v8::Message> message,
4294 v8::Handle<Value> data) {
4295 CHECK(!message->IsSharedCrossOrigin());
4296 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4297 message_received = true;
4301 TEST(MessageHandler5) {
4302 message_received = false;
4303 v8::Isolate* isolate = CcTest::isolate();
4304 v8::HandleScope scope(isolate);
4305 CHECK(!message_received);
4306 v8::V8::AddMessageListener(check_message_5a);
4307 LocalContext context;
4308 v8::ScriptOrigin origin =
4309 v8::ScriptOrigin(v8_str("6.75"),
4310 v8::Integer::New(isolate, 1),
4311 v8::Integer::New(isolate, 2),
4313 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4316 CHECK(message_received);
4317 // clear out the message listener
4318 v8::V8::RemoveMessageListeners(check_message_5a);
4320 message_received = false;
4321 v8::V8::AddMessageListener(check_message_5b);
4323 v8::ScriptOrigin(v8_str("6.75"),
4324 v8::Integer::New(isolate, 1),
4325 v8::Integer::New(isolate, 2),
4326 v8::False(isolate));
4327 script = Script::Compile(v8_str("throw 'error'"),
4330 CHECK(message_received);
4331 // clear out the message listener
4332 v8::V8::RemoveMessageListeners(check_message_5b);
4336 THREADED_TEST(GetSetProperty) {
4337 LocalContext context;
4338 v8::Isolate* isolate = context->GetIsolate();
4339 v8::HandleScope scope(isolate);
4340 context->Global()->Set(v8_str("foo"), v8_num(14));
4341 context->Global()->Set(v8_str("12"), v8_num(92));
4342 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4343 context->Global()->Set(v8_num(13), v8_num(56));
4344 Local<Value> foo = CompileRun("this.foo");
4345 CHECK_EQ(14, foo->Int32Value());
4346 Local<Value> twelve = CompileRun("this[12]");
4347 CHECK_EQ(92, twelve->Int32Value());
4348 Local<Value> sixteen = CompileRun("this[16]");
4349 CHECK_EQ(32, sixteen->Int32Value());
4350 Local<Value> thirteen = CompileRun("this[13]");
4351 CHECK_EQ(56, thirteen->Int32Value());
4353 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4354 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4355 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4357 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4358 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4359 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4361 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4362 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4363 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4367 THREADED_TEST(PropertyAttributes) {
4368 LocalContext context;
4369 v8::HandleScope scope(context->GetIsolate());
4371 Local<String> prop = v8_str("none");
4372 context->Global()->Set(prop, v8_num(7));
4373 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4375 prop = v8_str("read_only");
4376 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4377 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4378 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4379 CompileRun("read_only = 9");
4380 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4381 context->Global()->Set(prop, v8_num(10));
4382 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4384 prop = v8_str("dont_delete");
4385 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4386 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4387 CompileRun("delete dont_delete");
4388 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4389 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4391 prop = v8_str("dont_enum");
4392 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4393 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4395 prop = v8_str("absent");
4396 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4397 Local<Value> fake_prop = v8_num(1);
4398 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4401 Local<Value> exception =
4402 CompileRun("({ toString: function() { throw 'exception';} })");
4403 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4404 CHECK(try_catch.HasCaught());
4405 String::Utf8Value exception_value(try_catch.Exception());
4406 CHECK_EQ("exception", *exception_value);
4411 THREADED_TEST(Array) {
4412 LocalContext context;
4413 v8::HandleScope scope(context->GetIsolate());
4414 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4415 CHECK_EQ(0, array->Length());
4416 CHECK(array->Get(0)->IsUndefined());
4417 CHECK(!array->Has(0));
4418 CHECK(array->Get(100)->IsUndefined());
4419 CHECK(!array->Has(100));
4420 array->Set(2, v8_num(7));
4421 CHECK_EQ(3, array->Length());
4422 CHECK(!array->Has(0));
4423 CHECK(!array->Has(1));
4424 CHECK(array->Has(2));
4425 CHECK_EQ(7, array->Get(2)->Int32Value());
4426 Local<Value> obj = CompileRun("[1, 2, 3]");
4427 Local<v8::Array> arr = obj.As<v8::Array>();
4428 CHECK_EQ(3, arr->Length());
4429 CHECK_EQ(1, arr->Get(0)->Int32Value());
4430 CHECK_EQ(2, arr->Get(1)->Int32Value());
4431 CHECK_EQ(3, arr->Get(2)->Int32Value());
4432 array = v8::Array::New(context->GetIsolate(), 27);
4433 CHECK_EQ(27, array->Length());
4434 array = v8::Array::New(context->GetIsolate(), -27);
4435 CHECK_EQ(0, array->Length());
4439 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4440 v8::EscapableHandleScope scope(args.GetIsolate());
4441 ApiTestFuzzer::Fuzz();
4442 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4443 for (int i = 0; i < args.Length(); i++)
4444 result->Set(i, args[i]);
4445 args.GetReturnValue().Set(scope.Escape(result));
4449 THREADED_TEST(Vector) {
4450 v8::Isolate* isolate = CcTest::isolate();
4451 v8::HandleScope scope(isolate);
4452 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4453 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4454 LocalContext context(0, global);
4456 const char* fun = "f()";
4457 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4458 CHECK_EQ(0, a0->Length());
4460 const char* fun2 = "f(11)";
4461 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4462 CHECK_EQ(1, a1->Length());
4463 CHECK_EQ(11, a1->Get(0)->Int32Value());
4465 const char* fun3 = "f(12, 13)";
4466 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4467 CHECK_EQ(2, a2->Length());
4468 CHECK_EQ(12, a2->Get(0)->Int32Value());
4469 CHECK_EQ(13, a2->Get(1)->Int32Value());
4471 const char* fun4 = "f(14, 15, 16)";
4472 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4473 CHECK_EQ(3, a3->Length());
4474 CHECK_EQ(14, a3->Get(0)->Int32Value());
4475 CHECK_EQ(15, a3->Get(1)->Int32Value());
4476 CHECK_EQ(16, a3->Get(2)->Int32Value());
4478 const char* fun5 = "f(17, 18, 19, 20)";
4479 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4480 CHECK_EQ(4, a4->Length());
4481 CHECK_EQ(17, a4->Get(0)->Int32Value());
4482 CHECK_EQ(18, a4->Get(1)->Int32Value());
4483 CHECK_EQ(19, a4->Get(2)->Int32Value());
4484 CHECK_EQ(20, a4->Get(3)->Int32Value());
4488 THREADED_TEST(FunctionCall) {
4489 LocalContext context;
4490 v8::Isolate* isolate = context->GetIsolate();
4491 v8::HandleScope scope(isolate);
4495 " for (var i = 0; i < arguments.length; i++) {"
4496 " result.push(arguments[i]);"
4500 "function ReturnThisSloppy() {"
4503 "function ReturnThisStrict() {"
4507 Local<Function> Foo =
4508 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4509 Local<Function> ReturnThisSloppy =
4510 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4511 Local<Function> ReturnThisStrict =
4512 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4514 v8::Handle<Value>* args0 = NULL;
4515 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4516 CHECK_EQ(0, a0->Length());
4518 v8::Handle<Value> args1[] = { v8_num(1.1) };
4519 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4520 CHECK_EQ(1, a1->Length());
4521 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4523 v8::Handle<Value> args2[] = { v8_num(2.2),
4525 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4526 CHECK_EQ(2, a2->Length());
4527 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4528 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4530 v8::Handle<Value> args3[] = { v8_num(4.4),
4533 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4534 CHECK_EQ(3, a3->Length());
4535 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4536 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4537 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4539 v8::Handle<Value> args4[] = { v8_num(7.7),
4543 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4544 CHECK_EQ(4, a4->Length());
4545 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4546 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4547 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4548 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4550 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4551 CHECK(r1->StrictEquals(context->Global()));
4552 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4553 CHECK(r2->StrictEquals(context->Global()));
4554 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4555 CHECK(r3->IsNumberObject());
4556 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4557 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4558 CHECK(r4->IsStringObject());
4559 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4560 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4561 CHECK(r5->IsBooleanObject());
4562 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4564 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4565 CHECK(r6->IsUndefined());
4566 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4567 CHECK(r7->IsNull());
4568 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4569 CHECK(r8->StrictEquals(v8_num(42)));
4570 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4571 CHECK(r9->StrictEquals(v8_str("hello")));
4572 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4573 CHECK(r10->StrictEquals(v8::True(isolate)));
4577 THREADED_TEST(ConstructCall) {
4578 LocalContext context;
4579 v8::Isolate* isolate = context->GetIsolate();
4580 v8::HandleScope scope(isolate);
4584 " for (var i = 0; i < arguments.length; i++) {"
4585 " result.push(arguments[i]);"
4589 Local<Function> Foo =
4590 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4592 v8::Handle<Value>* args0 = NULL;
4593 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4594 CHECK_EQ(0, a0->Length());
4596 v8::Handle<Value> args1[] = { v8_num(1.1) };
4597 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4598 CHECK_EQ(1, a1->Length());
4599 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4601 v8::Handle<Value> args2[] = { v8_num(2.2),
4603 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4604 CHECK_EQ(2, a2->Length());
4605 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4606 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4608 v8::Handle<Value> args3[] = { v8_num(4.4),
4611 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4612 CHECK_EQ(3, a3->Length());
4613 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4614 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4615 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4617 v8::Handle<Value> args4[] = { v8_num(7.7),
4621 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4622 CHECK_EQ(4, a4->Length());
4623 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4624 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4625 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4626 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4630 static void CheckUncle(v8::TryCatch* try_catch) {
4631 CHECK(try_catch->HasCaught());
4632 String::Utf8Value str_value(try_catch->Exception());
4633 CHECK_EQ(*str_value, "uncle?");
4638 THREADED_TEST(ConversionNumber) {
4640 v8::HandleScope scope(env->GetIsolate());
4641 // Very large number.
4642 CompileRun("var obj = Math.pow(2,32) * 1237;");
4643 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4644 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4645 CHECK_EQ(0, obj->ToInt32()->Value());
4646 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4648 CompileRun("var obj = -1234567890123;");
4649 obj = env->Global()->Get(v8_str("obj"));
4650 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4651 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4652 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4653 // Small positive integer.
4654 CompileRun("var obj = 42;");
4655 obj = env->Global()->Get(v8_str("obj"));
4656 CHECK_EQ(42.0, obj->ToNumber()->Value());
4657 CHECK_EQ(42, obj->ToInt32()->Value());
4658 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4659 // Negative integer.
4660 CompileRun("var obj = -37;");
4661 obj = env->Global()->Get(v8_str("obj"));
4662 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4663 CHECK_EQ(-37, obj->ToInt32()->Value());
4664 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4665 // Positive non-int32 integer.
4666 CompileRun("var obj = 0x81234567;");
4667 obj = env->Global()->Get(v8_str("obj"));
4668 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4669 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4670 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4672 CompileRun("var obj = 42.3;");
4673 obj = env->Global()->Get(v8_str("obj"));
4674 CHECK_EQ(42.3, obj->ToNumber()->Value());
4675 CHECK_EQ(42, obj->ToInt32()->Value());
4676 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4677 // Large negative fraction.
4678 CompileRun("var obj = -5726623061.75;");
4679 obj = env->Global()->Get(v8_str("obj"));
4680 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4681 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4682 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4686 THREADED_TEST(isNumberType) {
4688 v8::HandleScope scope(env->GetIsolate());
4689 // Very large number.
4690 CompileRun("var obj = Math.pow(2,32) * 1237;");
4691 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4692 CHECK(!obj->IsInt32());
4693 CHECK(!obj->IsUint32());
4694 // Large negative number.
4695 CompileRun("var obj = -1234567890123;");
4696 obj = env->Global()->Get(v8_str("obj"));
4697 CHECK(!obj->IsInt32());
4698 CHECK(!obj->IsUint32());
4699 // Small positive integer.
4700 CompileRun("var obj = 42;");
4701 obj = env->Global()->Get(v8_str("obj"));
4702 CHECK(obj->IsInt32());
4703 CHECK(obj->IsUint32());
4704 // Negative integer.
4705 CompileRun("var obj = -37;");
4706 obj = env->Global()->Get(v8_str("obj"));
4707 CHECK(obj->IsInt32());
4708 CHECK(!obj->IsUint32());
4709 // Positive non-int32 integer.
4710 CompileRun("var obj = 0x81234567;");
4711 obj = env->Global()->Get(v8_str("obj"));
4712 CHECK(!obj->IsInt32());
4713 CHECK(obj->IsUint32());
4715 CompileRun("var obj = 42.3;");
4716 obj = env->Global()->Get(v8_str("obj"));
4717 CHECK(!obj->IsInt32());
4718 CHECK(!obj->IsUint32());
4719 // Large negative fraction.
4720 CompileRun("var obj = -5726623061.75;");
4721 obj = env->Global()->Get(v8_str("obj"));
4722 CHECK(!obj->IsInt32());
4723 CHECK(!obj->IsUint32());
4725 CompileRun("var obj = 0.0;");
4726 obj = env->Global()->Get(v8_str("obj"));
4727 CHECK(obj->IsInt32());
4728 CHECK(obj->IsUint32());
4730 CompileRun("var obj = -0.0;");
4731 obj = env->Global()->Get(v8_str("obj"));
4732 CHECK(!obj->IsInt32());
4733 CHECK(!obj->IsUint32());
4737 THREADED_TEST(ConversionException) {
4739 v8::Isolate* isolate = env->GetIsolate();
4740 v8::HandleScope scope(isolate);
4742 "function TestClass() { };"
4743 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4744 "var obj = new TestClass();");
4745 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4747 v8::TryCatch try_catch;
4749 Local<Value> to_string_result = obj->ToString();
4750 CHECK(to_string_result.IsEmpty());
4751 CheckUncle(&try_catch);
4753 Local<Value> to_number_result = obj->ToNumber();
4754 CHECK(to_number_result.IsEmpty());
4755 CheckUncle(&try_catch);
4757 Local<Value> to_integer_result = obj->ToInteger();
4758 CHECK(to_integer_result.IsEmpty());
4759 CheckUncle(&try_catch);
4761 Local<Value> to_uint32_result = obj->ToUint32();
4762 CHECK(to_uint32_result.IsEmpty());
4763 CheckUncle(&try_catch);
4765 Local<Value> to_int32_result = obj->ToInt32();
4766 CHECK(to_int32_result.IsEmpty());
4767 CheckUncle(&try_catch);
4769 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4770 CHECK(to_object_result.IsEmpty());
4771 CHECK(try_catch.HasCaught());
4774 int32_t int32_value = obj->Int32Value();
4775 CHECK_EQ(0, int32_value);
4776 CheckUncle(&try_catch);
4778 uint32_t uint32_value = obj->Uint32Value();
4779 CHECK_EQ(0, uint32_value);
4780 CheckUncle(&try_catch);
4782 double number_value = obj->NumberValue();
4783 CHECK_NE(0, std::isnan(number_value));
4784 CheckUncle(&try_catch);
4786 int64_t integer_value = obj->IntegerValue();
4787 CHECK_EQ(0.0, static_cast<double>(integer_value));
4788 CheckUncle(&try_catch);
4792 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4793 ApiTestFuzzer::Fuzz();
4794 args.GetIsolate()->ThrowException(v8_str("konto"));
4798 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4799 if (args.Length() < 1) {
4800 args.GetReturnValue().Set(false);
4803 v8::HandleScope scope(args.GetIsolate());
4804 v8::TryCatch try_catch;
4805 Local<Value> result = CompileRun(args[0]->ToString());
4806 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4807 args.GetReturnValue().Set(try_catch.HasCaught());
4811 THREADED_TEST(APICatch) {
4812 v8::Isolate* isolate = CcTest::isolate();
4813 v8::HandleScope scope(isolate);
4814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4815 templ->Set(v8_str("ThrowFromC"),
4816 v8::FunctionTemplate::New(isolate, ThrowFromC));
4817 LocalContext context(0, templ);
4819 "var thrown = false;"
4825 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4826 CHECK(thrown->BooleanValue());
4830 THREADED_TEST(APIThrowTryCatch) {
4831 v8::Isolate* isolate = CcTest::isolate();
4832 v8::HandleScope scope(isolate);
4833 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4834 templ->Set(v8_str("ThrowFromC"),
4835 v8::FunctionTemplate::New(isolate, ThrowFromC));
4836 LocalContext context(0, templ);
4837 v8::TryCatch try_catch;
4838 CompileRun("ThrowFromC();");
4839 CHECK(try_catch.HasCaught());
4843 // Test that a try-finally block doesn't shadow a try-catch block
4844 // when setting up an external handler.
4846 // BUG(271): Some of the exception propagation does not work on the
4847 // ARM simulator because the simulator separates the C++ stack and the
4848 // JS stack. This test therefore fails on the simulator. The test is
4849 // not threaded to allow the threading tests to run on the simulator.
4850 TEST(TryCatchInTryFinally) {
4851 v8::Isolate* isolate = CcTest::isolate();
4852 v8::HandleScope scope(isolate);
4853 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4854 templ->Set(v8_str("CCatcher"),
4855 v8::FunctionTemplate::New(isolate, CCatcher));
4856 LocalContext context(0, templ);
4857 Local<Value> result = CompileRun("try {"
4859 " CCatcher('throw 7;');"
4864 CHECK(result->IsTrue());
4868 static void check_reference_error_message(
4869 v8::Handle<v8::Message> message,
4870 v8::Handle<v8::Value> data) {
4871 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4872 CHECK(message->Get()->Equals(v8_str(reference_error)));
4876 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4877 ApiTestFuzzer::Fuzz();
4882 // Test that overwritten methods are not invoked on uncaught exception
4883 // formatting. However, they are invoked when performing normal error
4884 // string conversions.
4885 TEST(APIThrowMessageOverwrittenToString) {
4886 v8::Isolate* isolate = CcTest::isolate();
4887 v8::HandleScope scope(isolate);
4888 v8::V8::AddMessageListener(check_reference_error_message);
4889 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4890 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4891 LocalContext context(NULL, templ);
4892 CompileRun("asdf;");
4893 CompileRun("var limit = {};"
4894 "limit.valueOf = fail;"
4895 "Error.stackTraceLimit = limit;");
4897 CompileRun("Array.prototype.pop = fail;");
4898 CompileRun("Object.prototype.hasOwnProperty = fail;");
4899 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4900 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4901 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4902 CompileRun("ReferenceError.prototype.toString ="
4903 " function() { return 'Whoops' }");
4904 CompileRun("asdf;");
4905 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4906 CompileRun("asdf;");
4907 CompileRun("ReferenceError.prototype.constructor = void 0;");
4908 CompileRun("asdf;");
4909 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4910 CompileRun("asdf;");
4911 CompileRun("ReferenceError.prototype = new Object();");
4912 CompileRun("asdf;");
4913 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4914 CHECK(string->Equals(v8_str("Whoops")));
4915 CompileRun("ReferenceError.prototype.constructor = new Object();"
4916 "ReferenceError.prototype.constructor.name = 1;"
4917 "Number.prototype.toString = function() { return 'Whoops'; };"
4918 "ReferenceError.prototype.toString = Object.prototype.toString;");
4919 CompileRun("asdf;");
4920 v8::V8::RemoveMessageListeners(check_reference_error_message);
4924 static void check_custom_error_tostring(
4925 v8::Handle<v8::Message> message,
4926 v8::Handle<v8::Value> data) {
4927 const char* uncaught_error = "Uncaught MyError toString";
4928 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4932 TEST(CustomErrorToString) {
4933 LocalContext context;
4934 v8::HandleScope scope(context->GetIsolate());
4935 v8::V8::AddMessageListener(check_custom_error_tostring);
4937 "function MyError(name, message) { "
4938 " this.name = name; "
4939 " this.message = message; "
4941 "MyError.prototype = Object.create(Error.prototype); "
4942 "MyError.prototype.toString = function() { "
4943 " return 'MyError toString'; "
4945 "throw new MyError('my name', 'my message'); ");
4946 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4950 static void check_custom_error_message(
4951 v8::Handle<v8::Message> message,
4952 v8::Handle<v8::Value> data) {
4953 const char* uncaught_error = "Uncaught MyError: my message";
4954 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4955 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4959 TEST(CustomErrorMessage) {
4960 LocalContext context;
4961 v8::HandleScope scope(context->GetIsolate());
4962 v8::V8::AddMessageListener(check_custom_error_message);
4966 "function MyError(msg) { "
4967 " this.name = 'MyError'; "
4968 " this.message = msg; "
4970 "MyError.prototype = new Error(); "
4971 "throw new MyError('my message'); ");
4975 "function MyError(msg) { "
4976 " this.name = 'MyError'; "
4977 " this.message = msg; "
4979 "inherits = function(childCtor, parentCtor) { "
4980 " function tempCtor() {}; "
4981 " tempCtor.prototype = parentCtor.prototype; "
4982 " childCtor.superClass_ = parentCtor.prototype; "
4983 " childCtor.prototype = new tempCtor(); "
4984 " childCtor.prototype.constructor = childCtor; "
4986 "inherits(MyError, Error); "
4987 "throw new MyError('my message'); ");
4991 "function MyError(msg) { "
4992 " this.name = 'MyError'; "
4993 " this.message = msg; "
4995 "MyError.prototype = Object.create(Error.prototype); "
4996 "throw new MyError('my message'); ");
4998 v8::V8::RemoveMessageListeners(check_custom_error_message);
5002 static void receive_message(v8::Handle<v8::Message> message,
5003 v8::Handle<v8::Value> data) {
5005 message_received = true;
5009 TEST(APIThrowMessage) {
5010 message_received = false;
5011 v8::Isolate* isolate = CcTest::isolate();
5012 v8::HandleScope scope(isolate);
5013 v8::V8::AddMessageListener(receive_message);
5014 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5015 templ->Set(v8_str("ThrowFromC"),
5016 v8::FunctionTemplate::New(isolate, ThrowFromC));
5017 LocalContext context(0, templ);
5018 CompileRun("ThrowFromC();");
5019 CHECK(message_received);
5020 v8::V8::RemoveMessageListeners(receive_message);
5024 TEST(APIThrowMessageAndVerboseTryCatch) {
5025 message_received = false;
5026 v8::Isolate* isolate = CcTest::isolate();
5027 v8::HandleScope scope(isolate);
5028 v8::V8::AddMessageListener(receive_message);
5029 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5030 templ->Set(v8_str("ThrowFromC"),
5031 v8::FunctionTemplate::New(isolate, ThrowFromC));
5032 LocalContext context(0, templ);
5033 v8::TryCatch try_catch;
5034 try_catch.SetVerbose(true);
5035 Local<Value> result = CompileRun("ThrowFromC();");
5036 CHECK(try_catch.HasCaught());
5037 CHECK(result.IsEmpty());
5038 CHECK(message_received);
5039 v8::V8::RemoveMessageListeners(receive_message);
5043 TEST(APIStackOverflowAndVerboseTryCatch) {
5044 message_received = false;
5045 LocalContext context;
5046 v8::HandleScope scope(context->GetIsolate());
5047 v8::V8::AddMessageListener(receive_message);
5048 v8::TryCatch try_catch;
5049 try_catch.SetVerbose(true);
5050 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5051 CHECK(try_catch.HasCaught());
5052 CHECK(result.IsEmpty());
5053 CHECK(message_received);
5054 v8::V8::RemoveMessageListeners(receive_message);
5058 THREADED_TEST(ExternalScriptException) {
5059 v8::Isolate* isolate = CcTest::isolate();
5060 v8::HandleScope scope(isolate);
5061 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5062 templ->Set(v8_str("ThrowFromC"),
5063 v8::FunctionTemplate::New(isolate, ThrowFromC));
5064 LocalContext context(0, templ);
5066 v8::TryCatch try_catch;
5067 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5068 CHECK(result.IsEmpty());
5069 CHECK(try_catch.HasCaught());
5070 String::Utf8Value exception_value(try_catch.Exception());
5071 CHECK_EQ("konto", *exception_value);
5076 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5077 ApiTestFuzzer::Fuzz();
5078 CHECK_EQ(4, args.Length());
5079 int count = args[0]->Int32Value();
5080 int cInterval = args[2]->Int32Value();
5082 args.GetIsolate()->ThrowException(v8_str("FromC"));
5085 Local<v8::Object> global =
5086 args.GetIsolate()->GetCurrentContext()->Global();
5087 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5088 v8::Handle<Value> argv[] = { v8_num(count - 1),
5092 if (count % cInterval == 0) {
5093 v8::TryCatch try_catch;
5094 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5095 int expected = args[3]->Int32Value();
5096 if (try_catch.HasCaught()) {
5097 CHECK_EQ(expected, count);
5098 CHECK(result.IsEmpty());
5099 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5101 CHECK_NE(expected, count);
5103 args.GetReturnValue().Set(result);
5106 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5113 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5114 ApiTestFuzzer::Fuzz();
5115 CHECK_EQ(3, args.Length());
5116 bool equality = args[0]->BooleanValue();
5117 int count = args[1]->Int32Value();
5118 int expected = args[2]->Int32Value();
5120 CHECK_EQ(count, expected);
5122 CHECK_NE(count, expected);
5127 THREADED_TEST(EvalInTryFinally) {
5128 LocalContext context;
5129 v8::HandleScope scope(context->GetIsolate());
5130 v8::TryCatch try_catch;
5131 CompileRun("(function() {"
5133 " eval('asldkf (*&^&*^');"
5138 CHECK(!try_catch.HasCaught());
5142 // This test works by making a stack of alternating JavaScript and C
5143 // activations. These activations set up exception handlers with regular
5144 // intervals, one interval for C activations and another for JavaScript
5145 // activations. When enough activations have been created an exception is
5146 // thrown and we check that the right activation catches the exception and that
5147 // no other activations do. The right activation is always the topmost one with
5148 // a handler, regardless of whether it is in JavaScript or C.
5150 // The notation used to describe a test case looks like this:
5152 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5154 // Each entry is an activation, either JS or C. The index is the count at that
5155 // level. Stars identify activations with exception handlers, the @ identifies
5156 // the exception handler that should catch the exception.
5158 // BUG(271): Some of the exception propagation does not work on the
5159 // ARM simulator because the simulator separates the C++ stack and the
5160 // JS stack. This test therefore fails on the simulator. The test is
5161 // not threaded to allow the threading tests to run on the simulator.
5162 TEST(ExceptionOrder) {
5163 v8::Isolate* isolate = CcTest::isolate();
5164 v8::HandleScope scope(isolate);
5165 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5166 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5167 templ->Set(v8_str("CThrowCountDown"),
5168 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5169 LocalContext context(0, templ);
5171 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5172 " if (count == 0) throw 'FromJS';"
5173 " if (count % jsInterval == 0) {"
5175 " var value = CThrowCountDown(count - 1,"
5179 " check(false, count, expected);"
5182 " check(true, count, expected);"
5185 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5188 Local<Function> fun =
5189 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5192 // count jsInterval cInterval expected
5194 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5195 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5196 fun->Call(fun, argc, a0);
5198 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5199 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5200 fun->Call(fun, argc, a1);
5202 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5203 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5204 fun->Call(fun, argc, a2);
5206 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5207 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5208 fun->Call(fun, argc, a3);
5210 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5211 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5212 fun->Call(fun, argc, a4);
5214 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5215 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5216 fun->Call(fun, argc, a5);
5220 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5221 ApiTestFuzzer::Fuzz();
5222 CHECK_EQ(1, args.Length());
5223 args.GetIsolate()->ThrowException(args[0]);
5227 THREADED_TEST(ThrowValues) {
5228 v8::Isolate* isolate = CcTest::isolate();
5229 v8::HandleScope scope(isolate);
5230 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5231 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5232 LocalContext context(0, templ);
5233 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5234 "function Run(obj) {"
5240 " return 'no exception';"
5242 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5243 CHECK_EQ(5, result->Length());
5244 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5245 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5246 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5247 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5248 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5249 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5250 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5254 THREADED_TEST(CatchZero) {
5255 LocalContext context;
5256 v8::HandleScope scope(context->GetIsolate());
5257 v8::TryCatch try_catch;
5258 CHECK(!try_catch.HasCaught());
5259 CompileRun("throw 10");
5260 CHECK(try_catch.HasCaught());
5261 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5263 CHECK(!try_catch.HasCaught());
5264 CompileRun("throw 0");
5265 CHECK(try_catch.HasCaught());
5266 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5270 THREADED_TEST(CatchExceptionFromWith) {
5271 LocalContext context;
5272 v8::HandleScope scope(context->GetIsolate());
5273 v8::TryCatch try_catch;
5274 CHECK(!try_catch.HasCaught());
5275 CompileRun("var o = {}; with (o) { throw 42; }");
5276 CHECK(try_catch.HasCaught());
5280 THREADED_TEST(TryCatchAndFinallyHidingException) {
5281 LocalContext context;
5282 v8::HandleScope scope(context->GetIsolate());
5283 v8::TryCatch try_catch;
5284 CHECK(!try_catch.HasCaught());
5285 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5286 CompileRun("f({toString: function() { throw 42; }});");
5287 CHECK(!try_catch.HasCaught());
5291 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5292 v8::TryCatch try_catch;
5296 THREADED_TEST(TryCatchAndFinally) {
5297 LocalContext context;
5298 v8::Isolate* isolate = context->GetIsolate();
5299 v8::HandleScope scope(isolate);
5300 context->Global()->Set(
5301 v8_str("native_with_try_catch"),
5302 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5303 v8::TryCatch try_catch;
5304 CHECK(!try_catch.HasCaught());
5307 " throw new Error('a');\n"
5309 " native_with_try_catch();\n"
5311 CHECK(try_catch.HasCaught());
5315 static void TryCatchNestedHelper(int depth) {
5317 v8::TryCatch try_catch;
5318 try_catch.SetVerbose(true);
5319 TryCatchNestedHelper(depth - 1);
5320 CHECK(try_catch.HasCaught());
5321 try_catch.ReThrow();
5323 CcTest::isolate()->ThrowException(v8_str("back"));
5328 TEST(TryCatchNested) {
5329 v8::V8::Initialize();
5330 LocalContext context;
5331 v8::HandleScope scope(context->GetIsolate());
5332 v8::TryCatch try_catch;
5333 TryCatchNestedHelper(5);
5334 CHECK(try_catch.HasCaught());
5335 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5339 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5340 CHECK(try_catch->HasCaught());
5341 Handle<Message> message = try_catch->Message();
5342 Handle<Value> resource = message->GetScriptResourceName();
5343 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5344 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5345 "Uncaught Error: a"));
5346 CHECK_EQ(1, message->GetLineNumber());
5347 CHECK_EQ(6, message->GetStartColumn());
5351 void TryCatchMixedNestingHelper(
5352 const v8::FunctionCallbackInfo<v8::Value>& args) {
5353 ApiTestFuzzer::Fuzz();
5354 v8::TryCatch try_catch;
5355 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5356 CHECK(try_catch.HasCaught());
5357 TryCatchMixedNestingCheck(&try_catch);
5358 try_catch.ReThrow();
5362 // This test ensures that an outer TryCatch in the following situation:
5363 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5364 // does not clobber the Message object generated for the inner TryCatch.
5365 // This exercises the ability of TryCatch.ReThrow() to restore the
5366 // inner pending Message before throwing the exception again.
5367 TEST(TryCatchMixedNesting) {
5368 v8::Isolate* isolate = CcTest::isolate();
5369 v8::HandleScope scope(isolate);
5370 v8::V8::Initialize();
5371 v8::TryCatch try_catch;
5372 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5373 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5374 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5375 LocalContext context(0, templ);
5376 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5377 TryCatchMixedNestingCheck(&try_catch);
5381 THREADED_TEST(Equality) {
5382 LocalContext context;
5383 v8::Isolate* isolate = context->GetIsolate();
5384 v8::HandleScope scope(context->GetIsolate());
5385 // Check that equality works at all before relying on CHECK_EQ
5386 CHECK(v8_str("a")->Equals(v8_str("a")));
5387 CHECK(!v8_str("a")->Equals(v8_str("b")));
5389 CHECK_EQ(v8_str("a"), v8_str("a"));
5390 CHECK_NE(v8_str("a"), v8_str("b"));
5391 CHECK_EQ(v8_num(1), v8_num(1));
5392 CHECK_EQ(v8_num(1.00), v8_num(1));
5393 CHECK_NE(v8_num(1), v8_num(2));
5395 // Assume String is not internalized.
5396 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5397 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5398 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5399 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5400 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5401 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5402 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5403 CHECK(!not_a_number->StrictEquals(not_a_number));
5404 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5405 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5407 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5408 v8::Persistent<v8::Object> alias(isolate, obj);
5409 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5412 CHECK(v8_str("a")->SameValue(v8_str("a")));
5413 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5414 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5415 CHECK(v8_num(1)->SameValue(v8_num(1)));
5416 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5417 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5418 CHECK(not_a_number->SameValue(not_a_number));
5419 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5420 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5424 THREADED_TEST(MultiRun) {
5425 LocalContext context;
5426 v8::HandleScope scope(context->GetIsolate());
5427 Local<Script> script = v8_compile("x");
5428 for (int i = 0; i < 10; i++)
5433 static void GetXValue(Local<String> name,
5434 const v8::PropertyCallbackInfo<v8::Value>& info) {
5435 ApiTestFuzzer::Fuzz();
5436 CHECK_EQ(info.Data(), v8_str("donut"));
5437 CHECK_EQ(name, v8_str("x"));
5438 info.GetReturnValue().Set(name);
5442 THREADED_TEST(SimplePropertyRead) {
5443 LocalContext context;
5444 v8::Isolate* isolate = context->GetIsolate();
5445 v8::HandleScope scope(isolate);
5446 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5447 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5448 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5449 Local<Script> script = v8_compile("obj.x");
5450 for (int i = 0; i < 10; i++) {
5451 Local<Value> result = script->Run();
5452 CHECK_EQ(result, v8_str("x"));
5457 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5458 LocalContext context;
5459 v8::Isolate* isolate = context->GetIsolate();
5460 v8::HandleScope scope(isolate);
5461 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5462 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5463 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5465 // Uses getOwnPropertyDescriptor to check the configurable status
5466 Local<Script> script_desc = v8_compile(
5467 "var prop = Object.getOwnPropertyDescriptor( "
5469 "prop.configurable;");
5470 Local<Value> result = script_desc->Run();
5471 CHECK_EQ(result->BooleanValue(), true);
5473 // Redefine get - but still configurable
5474 Local<Script> script_define = v8_compile(
5475 "var desc = { get: function(){return 42; },"
5476 " configurable: true };"
5477 "Object.defineProperty(obj, 'x', desc);"
5479 result = script_define->Run();
5480 CHECK_EQ(result, v8_num(42));
5482 // Check that the accessor is still configurable
5483 result = script_desc->Run();
5484 CHECK_EQ(result->BooleanValue(), true);
5486 // Redefine to a non-configurable
5487 script_define = v8_compile(
5488 "var desc = { get: function(){return 43; },"
5489 " configurable: false };"
5490 "Object.defineProperty(obj, 'x', desc);"
5492 result = script_define->Run();
5493 CHECK_EQ(result, v8_num(43));
5494 result = script_desc->Run();
5495 CHECK_EQ(result->BooleanValue(), false);
5497 // Make sure that it is not possible to redefine again
5498 v8::TryCatch try_catch;
5499 result = script_define->Run();
5500 CHECK(try_catch.HasCaught());
5501 String::Utf8Value exception_value(try_catch.Exception());
5502 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5506 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5507 v8::Isolate* isolate = CcTest::isolate();
5508 v8::HandleScope scope(isolate);
5509 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5510 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5511 LocalContext context;
5512 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5514 Local<Script> script_desc = v8_compile(
5516 "Object.getOwnPropertyDescriptor( "
5518 "prop.configurable;");
5519 Local<Value> result = script_desc->Run();
5520 CHECK_EQ(result->BooleanValue(), true);
5522 Local<Script> script_define = v8_compile(
5523 "var desc = {get: function(){return 42; },"
5524 " configurable: true };"
5525 "Object.defineProperty(obj, 'x', desc);"
5527 result = script_define->Run();
5528 CHECK_EQ(result, v8_num(42));
5531 result = script_desc->Run();
5532 CHECK_EQ(result->BooleanValue(), true);
5535 script_define = v8_compile(
5536 "var desc = {get: function(){return 43; },"
5537 " configurable: false };"
5538 "Object.defineProperty(obj, 'x', desc);"
5540 result = script_define->Run();
5541 CHECK_EQ(result, v8_num(43));
5542 result = script_desc->Run();
5544 CHECK_EQ(result->BooleanValue(), false);
5546 v8::TryCatch try_catch;
5547 result = script_define->Run();
5548 CHECK(try_catch.HasCaught());
5549 String::Utf8Value exception_value(try_catch.Exception());
5550 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5554 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5556 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5560 THREADED_TEST(DefineAPIAccessorOnObject) {
5561 v8::Isolate* isolate = CcTest::isolate();
5562 v8::HandleScope scope(isolate);
5563 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5564 LocalContext context;
5566 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5567 CompileRun("var obj2 = {};");
5569 CHECK(CompileRun("obj1.x")->IsUndefined());
5570 CHECK(CompileRun("obj2.x")->IsUndefined());
5572 CHECK(GetGlobalProperty(&context, "obj1")->
5573 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5575 ExpectString("obj1.x", "x");
5576 CHECK(CompileRun("obj2.x")->IsUndefined());
5578 CHECK(GetGlobalProperty(&context, "obj2")->
5579 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5581 ExpectString("obj1.x", "x");
5582 ExpectString("obj2.x", "x");
5584 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5585 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5587 CompileRun("Object.defineProperty(obj1, 'x',"
5588 "{ get: function() { return 'y'; }, configurable: true })");
5590 ExpectString("obj1.x", "y");
5591 ExpectString("obj2.x", "x");
5593 CompileRun("Object.defineProperty(obj2, 'x',"
5594 "{ get: function() { return 'y'; }, configurable: true })");
5596 ExpectString("obj1.x", "y");
5597 ExpectString("obj2.x", "y");
5599 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5600 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5602 CHECK(GetGlobalProperty(&context, "obj1")->
5603 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5604 CHECK(GetGlobalProperty(&context, "obj2")->
5605 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5607 ExpectString("obj1.x", "x");
5608 ExpectString("obj2.x", "x");
5610 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5611 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5613 // Define getters/setters, but now make them not configurable.
5614 CompileRun("Object.defineProperty(obj1, 'x',"
5615 "{ get: function() { return 'z'; }, configurable: false })");
5616 CompileRun("Object.defineProperty(obj2, 'x',"
5617 "{ get: function() { return 'z'; }, configurable: false })");
5619 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5620 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5622 ExpectString("obj1.x", "z");
5623 ExpectString("obj2.x", "z");
5625 CHECK(!GetGlobalProperty(&context, "obj1")->
5626 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5627 CHECK(!GetGlobalProperty(&context, "obj2")->
5628 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5630 ExpectString("obj1.x", "z");
5631 ExpectString("obj2.x", "z");
5635 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5636 v8::Isolate* isolate = CcTest::isolate();
5637 v8::HandleScope scope(isolate);
5638 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5639 LocalContext context;
5641 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5642 CompileRun("var obj2 = {};");
5644 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5647 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5648 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5651 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5653 ExpectString("obj1.x", "x");
5654 ExpectString("obj2.x", "x");
5656 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5657 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5659 CHECK(!GetGlobalProperty(&context, "obj1")->
5660 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5661 CHECK(!GetGlobalProperty(&context, "obj2")->
5662 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5665 v8::TryCatch try_catch;
5666 CompileRun("Object.defineProperty(obj1, 'x',"
5667 "{get: function() { return 'func'; }})");
5668 CHECK(try_catch.HasCaught());
5669 String::Utf8Value exception_value(try_catch.Exception());
5670 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5673 v8::TryCatch try_catch;
5674 CompileRun("Object.defineProperty(obj2, 'x',"
5675 "{get: function() { return 'func'; }})");
5676 CHECK(try_catch.HasCaught());
5677 String::Utf8Value exception_value(try_catch.Exception());
5678 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5683 static void Get239Value(Local<String> name,
5684 const v8::PropertyCallbackInfo<v8::Value>& info) {
5685 ApiTestFuzzer::Fuzz();
5686 CHECK_EQ(info.Data(), v8_str("donut"));
5687 CHECK_EQ(name, v8_str("239"));
5688 info.GetReturnValue().Set(name);
5692 THREADED_TEST(ElementAPIAccessor) {
5693 v8::Isolate* isolate = CcTest::isolate();
5694 v8::HandleScope scope(isolate);
5695 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5696 LocalContext context;
5698 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5699 CompileRun("var obj2 = {};");
5701 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5705 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5710 ExpectString("obj1[239]", "239");
5711 ExpectString("obj2[239]", "239");
5712 ExpectString("obj1['239']", "239");
5713 ExpectString("obj2['239']", "239");
5717 v8::Persistent<Value> xValue;
5720 static void SetXValue(Local<String> name,
5722 const v8::PropertyCallbackInfo<void>& info) {
5723 CHECK_EQ(value, v8_num(4));
5724 CHECK_EQ(info.Data(), v8_str("donut"));
5725 CHECK_EQ(name, v8_str("x"));
5726 CHECK(xValue.IsEmpty());
5727 xValue.Reset(info.GetIsolate(), value);
5731 THREADED_TEST(SimplePropertyWrite) {
5732 v8::Isolate* isolate = CcTest::isolate();
5733 v8::HandleScope scope(isolate);
5734 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5735 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5736 LocalContext context;
5737 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5738 Local<Script> script = v8_compile("obj.x = 4");
5739 for (int i = 0; i < 10; i++) {
5740 CHECK(xValue.IsEmpty());
5742 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5748 THREADED_TEST(SetterOnly) {
5749 v8::Isolate* isolate = CcTest::isolate();
5750 v8::HandleScope scope(isolate);
5751 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5752 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5753 LocalContext context;
5754 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5755 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5756 for (int i = 0; i < 10; i++) {
5757 CHECK(xValue.IsEmpty());
5759 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5765 THREADED_TEST(NoAccessors) {
5766 v8::Isolate* isolate = CcTest::isolate();
5767 v8::HandleScope scope(isolate);
5768 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5769 templ->SetAccessor(v8_str("x"),
5770 static_cast<v8::AccessorGetterCallback>(NULL),
5773 LocalContext context;
5774 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5775 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5776 for (int i = 0; i < 10; i++) {
5782 static void XPropertyGetter(Local<String> property,
5783 const v8::PropertyCallbackInfo<v8::Value>& info) {
5784 ApiTestFuzzer::Fuzz();
5785 CHECK(info.Data()->IsUndefined());
5786 info.GetReturnValue().Set(property);
5790 THREADED_TEST(NamedInterceptorPropertyRead) {
5791 v8::Isolate* isolate = CcTest::isolate();
5792 v8::HandleScope scope(isolate);
5793 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5794 templ->SetNamedPropertyHandler(XPropertyGetter);
5795 LocalContext context;
5796 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5797 Local<Script> script = v8_compile("obj.x");
5798 for (int i = 0; i < 10; i++) {
5799 Local<Value> result = script->Run();
5800 CHECK_EQ(result, v8_str("x"));
5805 THREADED_TEST(NamedInterceptorDictionaryIC) {
5806 v8::Isolate* isolate = CcTest::isolate();
5807 v8::HandleScope scope(isolate);
5808 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5809 templ->SetNamedPropertyHandler(XPropertyGetter);
5810 LocalContext context;
5811 // Create an object with a named interceptor.
5812 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5813 Local<Script> script = v8_compile("interceptor_obj.x");
5814 for (int i = 0; i < 10; i++) {
5815 Local<Value> result = script->Run();
5816 CHECK_EQ(result, v8_str("x"));
5818 // Create a slow case object and a function accessing a property in
5819 // that slow case object (with dictionary probing in generated
5820 // code). Then force object with a named interceptor into slow-case,
5821 // pass it to the function, and check that the interceptor is called
5822 // instead of accessing the local property.
5823 Local<Value> result =
5824 CompileRun("function get_x(o) { return o.x; };"
5825 "var obj = { x : 42, y : 0 };"
5827 "for (var i = 0; i < 10; i++) get_x(obj);"
5828 "interceptor_obj.x = 42;"
5829 "interceptor_obj.y = 10;"
5830 "delete interceptor_obj.y;"
5831 "get_x(interceptor_obj)");
5832 CHECK_EQ(result, v8_str("x"));
5836 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5837 v8::Isolate* isolate = CcTest::isolate();
5838 v8::HandleScope scope(isolate);
5839 v8::Local<Context> context1 = Context::New(isolate);
5842 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5843 templ->SetNamedPropertyHandler(XPropertyGetter);
5844 // Create an object with a named interceptor.
5845 v8::Local<v8::Object> object = templ->NewInstance();
5846 context1->Global()->Set(v8_str("interceptor_obj"), object);
5848 // Force the object into the slow case.
5849 CompileRun("interceptor_obj.y = 0;"
5850 "delete interceptor_obj.y;");
5854 // Introduce the object into a different context.
5855 // Repeat named loads to exercise ICs.
5856 LocalContext context2;
5857 context2->Global()->Set(v8_str("interceptor_obj"), object);
5858 Local<Value> result =
5859 CompileRun("function get_x(o) { return o.x; }"
5860 "interceptor_obj.x = 42;"
5861 "for (var i=0; i != 10; i++) {"
5862 " get_x(interceptor_obj);"
5864 "get_x(interceptor_obj)");
5865 // Check that the interceptor was actually invoked.
5866 CHECK_EQ(result, v8_str("x"));
5869 // Return to the original context and force some object to the slow case
5870 // to cause the NormalizedMapCache to verify.
5872 CompileRun("var obj = { x : 0 }; delete obj.x;");
5877 static void SetXOnPrototypeGetter(
5878 Local<String> property,
5879 const v8::PropertyCallbackInfo<v8::Value>& info) {
5880 // Set x on the prototype object and do not handle the get request.
5881 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5882 proto.As<v8::Object>()->Set(v8_str("x"),
5883 v8::Integer::New(info.GetIsolate(), 23));
5887 // This is a regression test for http://crbug.com/20104. Map
5888 // transitions should not interfere with post interceptor lookup.
5889 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5890 v8::Isolate* isolate = CcTest::isolate();
5891 v8::HandleScope scope(isolate);
5892 Local<v8::FunctionTemplate> function_template =
5893 v8::FunctionTemplate::New(isolate);
5894 Local<v8::ObjectTemplate> instance_template
5895 = function_template->InstanceTemplate();
5896 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5897 LocalContext context;
5898 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5899 // Create an instance of F and introduce a map transition for x.
5900 CompileRun("var o = new F(); o.x = 23;");
5901 // Create an instance of F and invoke the getter. The result should be 23.
5902 Local<Value> result = CompileRun("o = new F(); o.x");
5903 CHECK_EQ(result->Int32Value(), 23);
5907 static void IndexedPropertyGetter(
5909 const v8::PropertyCallbackInfo<v8::Value>& info) {
5910 ApiTestFuzzer::Fuzz();
5912 info.GetReturnValue().Set(v8_num(625));
5917 static void IndexedPropertySetter(
5920 const v8::PropertyCallbackInfo<v8::Value>& info) {
5921 ApiTestFuzzer::Fuzz();
5923 info.GetReturnValue().Set(value);
5928 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5929 v8::Isolate* isolate = CcTest::isolate();
5930 v8::HandleScope scope(isolate);
5931 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5932 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5933 IndexedPropertySetter);
5934 LocalContext context;
5935 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5936 Local<Script> getter_script = v8_compile(
5937 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5938 Local<Script> setter_script = v8_compile(
5939 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5942 Local<Script> interceptor_setter_script = v8_compile(
5943 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5945 "obj.foo;"); // This setter should not run, due to the interceptor.
5946 Local<Script> interceptor_getter_script = v8_compile(
5948 Local<Value> result = getter_script->Run();
5949 CHECK_EQ(v8_num(5), result);
5950 result = setter_script->Run();
5951 CHECK_EQ(v8_num(23), result);
5952 result = interceptor_setter_script->Run();
5953 CHECK_EQ(v8_num(23), result);
5954 result = interceptor_getter_script->Run();
5955 CHECK_EQ(v8_num(625), result);
5959 static void UnboxedDoubleIndexedPropertyGetter(
5961 const v8::PropertyCallbackInfo<v8::Value>& info) {
5962 ApiTestFuzzer::Fuzz();
5964 info.GetReturnValue().Set(v8_num(index));
5969 static void UnboxedDoubleIndexedPropertySetter(
5972 const v8::PropertyCallbackInfo<v8::Value>& info) {
5973 ApiTestFuzzer::Fuzz();
5975 info.GetReturnValue().Set(v8_num(index));
5980 void UnboxedDoubleIndexedPropertyEnumerator(
5981 const v8::PropertyCallbackInfo<v8::Array>& info) {
5982 // Force the list of returned keys to be stored in a FastDoubleArray.
5983 Local<Script> indexed_property_names_script = v8_compile(
5984 "keys = new Array(); keys[125000] = 1;"
5985 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5986 "keys.length = 25; keys;");
5987 Local<Value> result = indexed_property_names_script->Run();
5988 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5992 // Make sure that the the interceptor code in the runtime properly handles
5993 // merging property name lists for double-array-backed arrays.
5994 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5995 v8::Isolate* isolate = CcTest::isolate();
5996 v8::HandleScope scope(isolate);
5997 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5998 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5999 UnboxedDoubleIndexedPropertySetter,
6002 UnboxedDoubleIndexedPropertyEnumerator);
6003 LocalContext context;
6004 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6005 // When obj is created, force it to be Stored in a FastDoubleArray.
6006 Local<Script> create_unboxed_double_script = v8_compile(
6007 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6009 "for (x in obj) {key_count++;};"
6011 Local<Value> result = create_unboxed_double_script->Run();
6012 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6013 Local<Script> key_count_check = v8_compile("key_count;");
6014 result = key_count_check->Run();
6015 CHECK_EQ(v8_num(40013), result);
6019 void SloppyArgsIndexedPropertyEnumerator(
6020 const v8::PropertyCallbackInfo<v8::Array>& info) {
6021 // Force the list of returned keys to be stored in a Arguments object.
6022 Local<Script> indexed_property_names_script = v8_compile(
6024 " return arguments;"
6026 "keys = f(0, 1, 2, 3);"
6028 Local<Object> result =
6029 Local<Object>::Cast(indexed_property_names_script->Run());
6030 // Have to populate the handle manually, as it's not Cast-able.
6031 i::Handle<i::JSObject> o =
6032 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6033 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6034 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6038 static void SloppyIndexedPropertyGetter(
6040 const v8::PropertyCallbackInfo<v8::Value>& info) {
6041 ApiTestFuzzer::Fuzz();
6043 info.GetReturnValue().Set(v8_num(index));
6048 // Make sure that the the interceptor code in the runtime properly handles
6049 // merging property name lists for non-string arguments arrays.
6050 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6051 v8::Isolate* isolate = CcTest::isolate();
6052 v8::HandleScope scope(isolate);
6053 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6054 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6058 SloppyArgsIndexedPropertyEnumerator);
6059 LocalContext context;
6060 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6061 Local<Script> create_args_script = v8_compile(
6062 "var key_count = 0;"
6063 "for (x in obj) {key_count++;} key_count;");
6064 Local<Value> result = create_args_script->Run();
6065 CHECK_EQ(v8_num(4), result);
6069 static void IdentityIndexedPropertyGetter(
6071 const v8::PropertyCallbackInfo<v8::Value>& info) {
6072 info.GetReturnValue().Set(index);
6076 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6077 v8::Isolate* isolate = CcTest::isolate();
6078 v8::HandleScope scope(isolate);
6079 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6080 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6082 LocalContext context;
6083 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6085 // Check fast object case.
6086 const char* fast_case_code =
6087 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6088 ExpectString(fast_case_code, "0");
6091 const char* slow_case_code =
6092 "obj.x = 1; delete obj.x;"
6093 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6094 ExpectString(slow_case_code, "1");
6098 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6099 v8::Isolate* isolate = CcTest::isolate();
6100 v8::HandleScope scope(isolate);
6101 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6102 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6104 LocalContext context;
6105 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6110 " for (var i = 0; i < 100; i++) {"
6112 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6118 ExpectString(code, "PASSED");
6122 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6123 v8::Isolate* isolate = CcTest::isolate();
6124 v8::HandleScope scope(isolate);
6125 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6126 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6128 LocalContext context;
6129 Local<v8::Object> obj = templ->NewInstance();
6130 obj->TurnOnAccessCheck();
6131 context->Global()->Set(v8_str("obj"), obj);
6135 " for (var i = 0; i < 100; i++) {"
6137 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6143 ExpectString(code, "PASSED");
6147 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6148 i::FLAG_allow_natives_syntax = true;
6149 v8::Isolate* isolate = CcTest::isolate();
6150 v8::HandleScope scope(isolate);
6151 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6152 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6154 LocalContext context;
6155 Local<v8::Object> obj = templ->NewInstance();
6156 context->Global()->Set(v8_str("obj"), obj);
6160 " for (var i = 0; i < 100; i++) {"
6161 " var expected = i;"
6163 " %EnableAccessChecks(obj);"
6164 " expected = undefined;"
6167 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6168 " if (i == 5) %DisableAccessChecks(obj);"
6174 ExpectString(code, "PASSED");
6178 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6179 v8::Isolate* isolate = CcTest::isolate();
6180 v8::HandleScope scope(isolate);
6181 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6182 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6184 LocalContext context;
6185 Local<v8::Object> obj = templ->NewInstance();
6186 context->Global()->Set(v8_str("obj"), obj);
6190 " for (var i = 0; i < 100; i++) {"
6192 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6198 ExpectString(code, "PASSED");
6202 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6203 v8::Isolate* isolate = CcTest::isolate();
6204 v8::HandleScope scope(isolate);
6205 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6206 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6208 LocalContext context;
6209 Local<v8::Object> obj = templ->NewInstance();
6210 context->Global()->Set(v8_str("obj"), obj);
6214 " for (var i = 0; i < 100; i++) {"
6215 " var expected = i;"
6219 " expected = undefined;"
6222 " /* probe minimal Smi number on 32-bit platforms */"
6223 " key = -(1 << 30);"
6224 " expected = undefined;"
6227 " /* probe minimal Smi number on 64-bit platforms */"
6229 " expected = undefined;"
6231 " var v = obj[key];"
6232 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6238 ExpectString(code, "PASSED");
6242 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6243 v8::Isolate* isolate = CcTest::isolate();
6244 v8::HandleScope scope(isolate);
6245 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6246 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6248 LocalContext context;
6249 Local<v8::Object> obj = templ->NewInstance();
6250 context->Global()->Set(v8_str("obj"), obj);
6254 " for (var i = 0; i < 100; i++) {"
6255 " var expected = i;"
6259 " expected = undefined;"
6261 " var v = obj[key];"
6262 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6268 ExpectString(code, "PASSED");
6272 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6273 v8::Isolate* isolate = CcTest::isolate();
6274 v8::HandleScope scope(isolate);
6275 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6276 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6278 LocalContext context;
6279 Local<v8::Object> obj = templ->NewInstance();
6280 context->Global()->Set(v8_str("obj"), obj);
6283 "var original = obj;"
6285 " for (var i = 0; i < 100; i++) {"
6286 " var expected = i;"
6288 " obj = {50: 'foobar'};"
6289 " expected = 'foobar';"
6292 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6293 " if (i == 50) obj = original;"
6299 ExpectString(code, "PASSED");
6303 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6304 v8::Isolate* isolate = CcTest::isolate();
6305 v8::HandleScope scope(isolate);
6306 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6307 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6309 LocalContext context;
6310 Local<v8::Object> obj = templ->NewInstance();
6311 context->Global()->Set(v8_str("obj"), obj);
6314 "var original = obj;"
6316 " for (var i = 0; i < 100; i++) {"
6317 " var expected = i;"
6320 " expected = undefined;"
6323 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6324 " if (i == 5) obj = original;"
6330 ExpectString(code, "PASSED");
6334 THREADED_TEST(IndexedInterceptorOnProto) {
6335 v8::Isolate* isolate = CcTest::isolate();
6336 v8::HandleScope scope(isolate);
6337 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6338 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6340 LocalContext context;
6341 Local<v8::Object> obj = templ->NewInstance();
6342 context->Global()->Set(v8_str("obj"), obj);
6345 "var o = {__proto__: obj};"
6347 " for (var i = 0; i < 100; i++) {"
6349 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6355 ExpectString(code, "PASSED");
6359 THREADED_TEST(MultiContexts) {
6360 v8::Isolate* isolate = CcTest::isolate();
6361 v8::HandleScope scope(isolate);
6362 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6363 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6366 Local<String> password = v8_str("Password");
6368 // Create an environment
6369 LocalContext context0(0, templ);
6370 context0->SetSecurityToken(password);
6371 v8::Handle<v8::Object> global0 = context0->Global();
6372 global0->Set(v8_str("custom"), v8_num(1234));
6373 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6375 // Create an independent environment
6376 LocalContext context1(0, templ);
6377 context1->SetSecurityToken(password);
6378 v8::Handle<v8::Object> global1 = context1->Global();
6379 global1->Set(v8_str("custom"), v8_num(1234));
6380 CHECK_NE(global0, global1);
6381 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6382 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6384 // Now create a new context with the old global
6385 LocalContext context2(0, templ, global1);
6386 context2->SetSecurityToken(password);
6387 v8::Handle<v8::Object> global2 = context2->Global();
6388 CHECK_EQ(global1, global2);
6389 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6390 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6394 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6395 // Make sure that functions created by cloning boilerplates cannot
6396 // communicate through their __proto__ field.
6398 v8::HandleScope scope(CcTest::isolate());
6401 v8::Handle<v8::Object> global0 =
6403 v8::Handle<v8::Object> object0 =
6404 global0->Get(v8_str("Object")).As<v8::Object>();
6405 v8::Handle<v8::Object> tostring0 =
6406 object0->Get(v8_str("toString")).As<v8::Object>();
6407 v8::Handle<v8::Object> proto0 =
6408 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6409 proto0->Set(v8_str("custom"), v8_num(1234));
6412 v8::Handle<v8::Object> global1 =
6414 v8::Handle<v8::Object> object1 =
6415 global1->Get(v8_str("Object")).As<v8::Object>();
6416 v8::Handle<v8::Object> tostring1 =
6417 object1->Get(v8_str("toString")).As<v8::Object>();
6418 v8::Handle<v8::Object> proto1 =
6419 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6420 CHECK(!proto1->Has(v8_str("custom")));
6424 THREADED_TEST(Regress892105) {
6425 // Make sure that object and array literals created by cloning
6426 // boilerplates cannot communicate through their __proto__
6427 // field. This is rather difficult to check, but we try to add stuff
6428 // to Object.prototype and Array.prototype and create a new
6429 // environment. This should succeed.
6431 v8::HandleScope scope(CcTest::isolate());
6433 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6434 "Array.prototype.arr = 4567;"
6438 Local<Script> script0 = v8_compile(source);
6439 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6442 Local<Script> script1 = v8_compile(source);
6443 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6447 THREADED_TEST(UndetectableObject) {
6449 v8::HandleScope scope(env->GetIsolate());
6451 Local<v8::FunctionTemplate> desc =
6452 v8::FunctionTemplate::New(env->GetIsolate());
6453 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6455 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6456 env->Global()->Set(v8_str("undetectable"), obj);
6458 ExpectString("undetectable.toString()", "[object Object]");
6459 ExpectString("typeof undetectable", "undefined");
6460 ExpectString("typeof(undetectable)", "undefined");
6461 ExpectBoolean("typeof undetectable == 'undefined'", true);
6462 ExpectBoolean("typeof undetectable == 'object'", false);
6463 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6464 ExpectBoolean("!undetectable", true);
6466 ExpectObject("true&&undetectable", obj);
6467 ExpectBoolean("false&&undetectable", false);
6468 ExpectBoolean("true||undetectable", true);
6469 ExpectObject("false||undetectable", obj);
6471 ExpectObject("undetectable&&true", obj);
6472 ExpectObject("undetectable&&false", obj);
6473 ExpectBoolean("undetectable||true", true);
6474 ExpectBoolean("undetectable||false", false);
6476 ExpectBoolean("undetectable==null", true);
6477 ExpectBoolean("null==undetectable", true);
6478 ExpectBoolean("undetectable==undefined", true);
6479 ExpectBoolean("undefined==undetectable", true);
6480 ExpectBoolean("undetectable==undetectable", true);
6483 ExpectBoolean("undetectable===null", false);
6484 ExpectBoolean("null===undetectable", false);
6485 ExpectBoolean("undetectable===undefined", false);
6486 ExpectBoolean("undefined===undetectable", false);
6487 ExpectBoolean("undetectable===undetectable", true);
6491 THREADED_TEST(VoidLiteral) {
6493 v8::Isolate* isolate = env->GetIsolate();
6494 v8::HandleScope scope(isolate);
6496 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6497 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6499 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6500 env->Global()->Set(v8_str("undetectable"), obj);
6502 ExpectBoolean("undefined == void 0", true);
6503 ExpectBoolean("undetectable == void 0", true);
6504 ExpectBoolean("null == void 0", true);
6505 ExpectBoolean("undefined === void 0", true);
6506 ExpectBoolean("undetectable === void 0", false);
6507 ExpectBoolean("null === void 0", false);
6509 ExpectBoolean("void 0 == undefined", true);
6510 ExpectBoolean("void 0 == undetectable", true);
6511 ExpectBoolean("void 0 == null", true);
6512 ExpectBoolean("void 0 === undefined", true);
6513 ExpectBoolean("void 0 === undetectable", false);
6514 ExpectBoolean("void 0 === null", false);
6516 ExpectString("(function() {"
6518 " return x === void 0;"
6520 " return e.toString();"
6523 "ReferenceError: x is not defined");
6524 ExpectString("(function() {"
6526 " return void 0 === x;"
6528 " return e.toString();"
6531 "ReferenceError: x is not defined");
6535 THREADED_TEST(ExtensibleOnUndetectable) {
6537 v8::Isolate* isolate = env->GetIsolate();
6538 v8::HandleScope scope(isolate);
6540 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6541 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6543 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6544 env->Global()->Set(v8_str("undetectable"), obj);
6546 Local<String> source = v8_str("undetectable.x = 42;"
6549 Local<Script> script = v8_compile(source);
6551 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6553 ExpectBoolean("Object.isExtensible(undetectable)", true);
6555 source = v8_str("Object.preventExtensions(undetectable);");
6556 script = v8_compile(source);
6558 ExpectBoolean("Object.isExtensible(undetectable)", false);
6560 source = v8_str("undetectable.y = 2000;");
6561 script = v8_compile(source);
6563 ExpectBoolean("undetectable.y == undefined", true);
6568 THREADED_TEST(UndetectableString) {
6570 v8::HandleScope scope(env->GetIsolate());
6572 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6573 String::kUndetectableString);
6574 env->Global()->Set(v8_str("undetectable"), obj);
6576 ExpectString("undetectable", "foo");
6577 ExpectString("typeof undetectable", "undefined");
6578 ExpectString("typeof(undetectable)", "undefined");
6579 ExpectBoolean("typeof undetectable == 'undefined'", true);
6580 ExpectBoolean("typeof undetectable == 'string'", false);
6581 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6582 ExpectBoolean("!undetectable", true);
6584 ExpectObject("true&&undetectable", obj);
6585 ExpectBoolean("false&&undetectable", false);
6586 ExpectBoolean("true||undetectable", true);
6587 ExpectObject("false||undetectable", obj);
6589 ExpectObject("undetectable&&true", obj);
6590 ExpectObject("undetectable&&false", obj);
6591 ExpectBoolean("undetectable||true", true);
6592 ExpectBoolean("undetectable||false", false);
6594 ExpectBoolean("undetectable==null", true);
6595 ExpectBoolean("null==undetectable", true);
6596 ExpectBoolean("undetectable==undefined", true);
6597 ExpectBoolean("undefined==undetectable", true);
6598 ExpectBoolean("undetectable==undetectable", true);
6601 ExpectBoolean("undetectable===null", false);
6602 ExpectBoolean("null===undetectable", false);
6603 ExpectBoolean("undetectable===undefined", false);
6604 ExpectBoolean("undefined===undetectable", false);
6605 ExpectBoolean("undetectable===undetectable", true);
6609 TEST(UndetectableOptimized) {
6610 i::FLAG_allow_natives_syntax = true;
6612 v8::HandleScope scope(env->GetIsolate());
6614 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6615 String::kUndetectableString);
6616 env->Global()->Set(v8_str("undetectable"), obj);
6617 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6620 "function testBranch() {"
6621 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6622 " if (%_IsUndetectableObject(detectable)) throw 2;"
6624 "function testBool() {"
6625 " var b1 = !%_IsUndetectableObject(undetectable);"
6626 " var b2 = %_IsUndetectableObject(detectable);"
6631 "%OptimizeFunctionOnNextCall(testBranch);"
6632 "%OptimizeFunctionOnNextCall(testBool);"
6633 "for (var i = 0; i < 10; i++) {"
6642 // The point of this test is type checking. We run it only so compilers
6643 // don't complain about an unused function.
6644 TEST(PersistentHandles) {
6646 v8::Isolate* isolate = CcTest::isolate();
6647 v8::HandleScope scope(isolate);
6648 Local<String> str = v8_str("foo");
6649 v8::Persistent<String> p_str(isolate, str);
6651 Local<Script> scr = v8_compile("");
6652 v8::Persistent<Script> p_scr(isolate, scr);
6654 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6655 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6660 static void HandleLogDelegator(
6661 const v8::FunctionCallbackInfo<v8::Value>& args) {
6662 ApiTestFuzzer::Fuzz();
6666 THREADED_TEST(GlobalObjectTemplate) {
6667 v8::Isolate* isolate = CcTest::isolate();
6668 v8::HandleScope handle_scope(isolate);
6669 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6670 global_template->Set(v8_str("JSNI_Log"),
6671 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6672 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6673 Context::Scope context_scope(context);
6674 CompileRun("JSNI_Log('LOG')");
6678 static const char* kSimpleExtensionSource =
6684 TEST(SimpleExtensions) {
6685 v8::HandleScope handle_scope(CcTest::isolate());
6686 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6687 const char* extension_names[] = { "simpletest" };
6688 v8::ExtensionConfiguration extensions(1, extension_names);
6689 v8::Handle<Context> context =
6690 Context::New(CcTest::isolate(), &extensions);
6691 Context::Scope lock(context);
6692 v8::Handle<Value> result = CompileRun("Foo()");
6693 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6697 TEST(NullExtensions) {
6698 v8::HandleScope handle_scope(CcTest::isolate());
6699 v8::RegisterExtension(new Extension("nulltest", NULL));
6700 const char* extension_names[] = { "nulltest" };
6701 v8::ExtensionConfiguration extensions(1, extension_names);
6702 v8::Handle<Context> context =
6703 Context::New(CcTest::isolate(), &extensions);
6704 Context::Scope lock(context);
6705 v8::Handle<Value> result = CompileRun("1+3");
6706 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6710 static const char* kEmbeddedExtensionSource =
6711 "function Ret54321(){return 54321;}~~@@$"
6712 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6713 static const int kEmbeddedExtensionSourceValidLen = 34;
6716 TEST(ExtensionMissingSourceLength) {
6717 v8::HandleScope handle_scope(CcTest::isolate());
6718 v8::RegisterExtension(new Extension("srclentest_fail",
6719 kEmbeddedExtensionSource));
6720 const char* extension_names[] = { "srclentest_fail" };
6721 v8::ExtensionConfiguration extensions(1, extension_names);
6722 v8::Handle<Context> context =
6723 Context::New(CcTest::isolate(), &extensions);
6724 CHECK_EQ(0, *context);
6728 TEST(ExtensionWithSourceLength) {
6729 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6730 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6731 v8::HandleScope handle_scope(CcTest::isolate());
6732 i::ScopedVector<char> extension_name(32);
6733 i::SNPrintF(extension_name, "ext #%d", source_len);
6734 v8::RegisterExtension(new Extension(extension_name.start(),
6735 kEmbeddedExtensionSource, 0, 0,
6737 const char* extension_names[1] = { extension_name.start() };
6738 v8::ExtensionConfiguration extensions(1, extension_names);
6739 v8::Handle<Context> context =
6740 Context::New(CcTest::isolate(), &extensions);
6741 if (source_len == kEmbeddedExtensionSourceValidLen) {
6742 Context::Scope lock(context);
6743 v8::Handle<Value> result = CompileRun("Ret54321()");
6744 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6746 // Anything but exactly the right length should fail to compile.
6747 CHECK_EQ(0, *context);
6753 static const char* kEvalExtensionSource1 =
6754 "function UseEval1() {"
6756 " return eval('x');"
6760 static const char* kEvalExtensionSource2 =
6764 " return eval('x');"
6766 " this.UseEval2 = e;"
6770 TEST(UseEvalFromExtension) {
6771 v8::HandleScope handle_scope(CcTest::isolate());
6772 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6773 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6774 const char* extension_names[] = { "evaltest1", "evaltest2" };
6775 v8::ExtensionConfiguration extensions(2, extension_names);
6776 v8::Handle<Context> context =
6777 Context::New(CcTest::isolate(), &extensions);
6778 Context::Scope lock(context);
6779 v8::Handle<Value> result = CompileRun("UseEval1()");
6780 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6781 result = CompileRun("UseEval2()");
6782 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6786 static const char* kWithExtensionSource1 =
6787 "function UseWith1() {"
6789 " with({x:87}) { return x; }"
6794 static const char* kWithExtensionSource2 =
6798 " with ({x:87}) { return x; }"
6800 " this.UseWith2 = e;"
6804 TEST(UseWithFromExtension) {
6805 v8::HandleScope handle_scope(CcTest::isolate());
6806 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6807 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6808 const char* extension_names[] = { "withtest1", "withtest2" };
6809 v8::ExtensionConfiguration extensions(2, extension_names);
6810 v8::Handle<Context> context =
6811 Context::New(CcTest::isolate(), &extensions);
6812 Context::Scope lock(context);
6813 v8::Handle<Value> result = CompileRun("UseWith1()");
6814 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6815 result = CompileRun("UseWith2()");
6816 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6820 TEST(AutoExtensions) {
6821 v8::HandleScope handle_scope(CcTest::isolate());
6822 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6823 extension->set_auto_enable(true);
6824 v8::RegisterExtension(extension);
6825 v8::Handle<Context> context =
6826 Context::New(CcTest::isolate());
6827 Context::Scope lock(context);
6828 v8::Handle<Value> result = CompileRun("Foo()");
6829 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6833 static const char* kSyntaxErrorInExtensionSource =
6837 // Test that a syntax error in an extension does not cause a fatal
6838 // error but results in an empty context.
6839 TEST(SyntaxErrorExtensions) {
6840 v8::HandleScope handle_scope(CcTest::isolate());
6841 v8::RegisterExtension(new Extension("syntaxerror",
6842 kSyntaxErrorInExtensionSource));
6843 const char* extension_names[] = { "syntaxerror" };
6844 v8::ExtensionConfiguration extensions(1, extension_names);
6845 v8::Handle<Context> context =
6846 Context::New(CcTest::isolate(), &extensions);
6847 CHECK(context.IsEmpty());
6851 static const char* kExceptionInExtensionSource =
6855 // Test that an exception when installing an extension does not cause
6856 // a fatal error but results in an empty context.
6857 TEST(ExceptionExtensions) {
6858 v8::HandleScope handle_scope(CcTest::isolate());
6859 v8::RegisterExtension(new Extension("exception",
6860 kExceptionInExtensionSource));
6861 const char* extension_names[] = { "exception" };
6862 v8::ExtensionConfiguration extensions(1, extension_names);
6863 v8::Handle<Context> context =
6864 Context::New(CcTest::isolate(), &extensions);
6865 CHECK(context.IsEmpty());
6869 static const char* kNativeCallInExtensionSource =
6870 "function call_runtime_last_index_of(x) {"
6871 " return %StringLastIndexOf(x, 'bob', 10);"
6875 static const char* kNativeCallTest =
6876 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6878 // Test that a native runtime calls are supported in extensions.
6879 TEST(NativeCallInExtensions) {
6880 v8::HandleScope handle_scope(CcTest::isolate());
6881 v8::RegisterExtension(new Extension("nativecall",
6882 kNativeCallInExtensionSource));
6883 const char* extension_names[] = { "nativecall" };
6884 v8::ExtensionConfiguration extensions(1, extension_names);
6885 v8::Handle<Context> context =
6886 Context::New(CcTest::isolate(), &extensions);
6887 Context::Scope lock(context);
6888 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6889 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6893 class NativeFunctionExtension : public Extension {
6895 NativeFunctionExtension(const char* name,
6897 v8::FunctionCallback fun = &Echo)
6898 : Extension(name, source),
6901 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6902 v8::Isolate* isolate,
6903 v8::Handle<v8::String> name) {
6904 return v8::FunctionTemplate::New(isolate, function_);
6907 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6908 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6911 v8::FunctionCallback function_;
6915 TEST(NativeFunctionDeclaration) {
6916 v8::HandleScope handle_scope(CcTest::isolate());
6917 const char* name = "nativedecl";
6918 v8::RegisterExtension(new NativeFunctionExtension(name,
6919 "native function foo();"));
6920 const char* extension_names[] = { name };
6921 v8::ExtensionConfiguration extensions(1, extension_names);
6922 v8::Handle<Context> context =
6923 Context::New(CcTest::isolate(), &extensions);
6924 Context::Scope lock(context);
6925 v8::Handle<Value> result = CompileRun("foo(42);");
6926 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6930 TEST(NativeFunctionDeclarationError) {
6931 v8::HandleScope handle_scope(CcTest::isolate());
6932 const char* name = "nativedeclerr";
6933 // Syntax error in extension code.
6934 v8::RegisterExtension(new NativeFunctionExtension(name,
6935 "native\nfunction foo();"));
6936 const char* extension_names[] = { name };
6937 v8::ExtensionConfiguration extensions(1, extension_names);
6938 v8::Handle<Context> context =
6939 Context::New(CcTest::isolate(), &extensions);
6940 CHECK(context.IsEmpty());
6944 TEST(NativeFunctionDeclarationErrorEscape) {
6945 v8::HandleScope handle_scope(CcTest::isolate());
6946 const char* name = "nativedeclerresc";
6947 // Syntax error in extension code - escape code in "native" means that
6948 // it's not treated as a keyword.
6949 v8::RegisterExtension(new NativeFunctionExtension(
6951 "nativ\\u0065 function foo();"));
6952 const char* extension_names[] = { name };
6953 v8::ExtensionConfiguration extensions(1, extension_names);
6954 v8::Handle<Context> context =
6955 Context::New(CcTest::isolate(), &extensions);
6956 CHECK(context.IsEmpty());
6960 static void CheckDependencies(const char* name, const char* expected) {
6961 v8::HandleScope handle_scope(CcTest::isolate());
6962 v8::ExtensionConfiguration config(1, &name);
6963 LocalContext context(&config);
6964 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6965 context->Global()->Get(v8_str("loaded")));
6976 THREADED_TEST(ExtensionDependency) {
6977 static const char* kEDeps[] = { "D" };
6978 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6979 static const char* kDDeps[] = { "B", "C" };
6980 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6981 static const char* kBCDeps[] = { "A" };
6982 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6983 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6984 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6985 CheckDependencies("A", "undefinedA");
6986 CheckDependencies("B", "undefinedAB");
6987 CheckDependencies("C", "undefinedAC");
6988 CheckDependencies("D", "undefinedABCD");
6989 CheckDependencies("E", "undefinedABCDE");
6990 v8::HandleScope handle_scope(CcTest::isolate());
6991 static const char* exts[2] = { "C", "E" };
6992 v8::ExtensionConfiguration config(2, exts);
6993 LocalContext context(&config);
6994 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6998 static const char* kExtensionTestScript =
6999 "native function A();"
7000 "native function B();"
7001 "native function C();"
7003 " if (i == 0) return A();"
7004 " if (i == 1) return B();"
7005 " if (i == 2) return C();"
7009 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7010 ApiTestFuzzer::Fuzz();
7011 if (args.IsConstructCall()) {
7012 args.This()->Set(v8_str("data"), args.Data());
7013 args.GetReturnValue().SetNull();
7016 args.GetReturnValue().Set(args.Data());
7020 class FunctionExtension : public Extension {
7022 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7023 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7024 v8::Isolate* isolate,
7025 v8::Handle<String> name);
7029 static int lookup_count = 0;
7030 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7031 v8::Isolate* isolate, v8::Handle<String> name) {
7033 if (name->Equals(v8_str("A"))) {
7034 return v8::FunctionTemplate::New(
7035 isolate, CallFun, v8::Integer::New(isolate, 8));
7036 } else if (name->Equals(v8_str("B"))) {
7037 return v8::FunctionTemplate::New(
7038 isolate, CallFun, v8::Integer::New(isolate, 7));
7039 } else if (name->Equals(v8_str("C"))) {
7040 return v8::FunctionTemplate::New(
7041 isolate, CallFun, v8::Integer::New(isolate, 6));
7043 return v8::Handle<v8::FunctionTemplate>();
7048 THREADED_TEST(FunctionLookup) {
7049 v8::RegisterExtension(new FunctionExtension());
7050 v8::HandleScope handle_scope(CcTest::isolate());
7051 static const char* exts[1] = { "functiontest" };
7052 v8::ExtensionConfiguration config(1, exts);
7053 LocalContext context(&config);
7054 CHECK_EQ(3, lookup_count);
7055 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7056 CompileRun("Foo(0)"));
7057 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7058 CompileRun("Foo(1)"));
7059 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7060 CompileRun("Foo(2)"));
7064 THREADED_TEST(NativeFunctionConstructCall) {
7065 v8::RegisterExtension(new FunctionExtension());
7066 v8::HandleScope handle_scope(CcTest::isolate());
7067 static const char* exts[1] = { "functiontest" };
7068 v8::ExtensionConfiguration config(1, exts);
7069 LocalContext context(&config);
7070 for (int i = 0; i < 10; i++) {
7071 // Run a few times to ensure that allocation of objects doesn't
7072 // change behavior of a constructor function.
7073 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7074 CompileRun("(new A()).data"));
7075 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7076 CompileRun("(new B()).data"));
7077 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7078 CompileRun("(new C()).data"));
7083 static const char* last_location;
7084 static const char* last_message;
7085 void StoringErrorCallback(const char* location, const char* message) {
7086 if (last_location == NULL) {
7087 last_location = location;
7088 last_message = message;
7093 // ErrorReporting creates a circular extensions configuration and
7094 // tests that the fatal error handler gets called. This renders V8
7095 // unusable and therefore this test cannot be run in parallel.
7096 TEST(ErrorReporting) {
7097 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7098 static const char* aDeps[] = { "B" };
7099 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7100 static const char* bDeps[] = { "A" };
7101 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7102 last_location = NULL;
7103 v8::ExtensionConfiguration config(1, bDeps);
7104 v8::Handle<Context> context =
7105 Context::New(CcTest::isolate(), &config);
7106 CHECK(context.IsEmpty());
7107 CHECK_NE(last_location, NULL);
7111 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7112 v8::Handle<Value> data) {
7113 CHECK(message->GetScriptResourceName()->IsUndefined());
7114 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7115 message->GetLineNumber();
7116 message->GetSourceLine();
7120 THREADED_TEST(ErrorWithMissingScriptInfo) {
7121 LocalContext context;
7122 v8::HandleScope scope(context->GetIsolate());
7123 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7124 CompileRun("throw Error()");
7125 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7129 struct FlagAndPersistent {
7131 v8::Persistent<v8::Object> handle;
7135 static void DisposeAndSetFlag(
7136 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7137 data.GetParameter()->handle.Reset();
7138 data.GetParameter()->flag = true;
7142 THREADED_TEST(IndependentWeakHandle) {
7143 v8::Isolate* iso = CcTest::isolate();
7144 v8::HandleScope scope(iso);
7145 v8::Handle<Context> context = Context::New(iso);
7146 Context::Scope context_scope(context);
7148 FlagAndPersistent object_a, object_b;
7151 v8::HandleScope handle_scope(iso);
7152 object_a.handle.Reset(iso, v8::Object::New(iso));
7153 object_b.handle.Reset(iso, v8::Object::New(iso));
7156 object_a.flag = false;
7157 object_b.flag = false;
7158 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7159 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7160 CHECK(!object_b.handle.IsIndependent());
7161 object_a.handle.MarkIndependent();
7162 object_b.handle.MarkIndependent();
7163 CHECK(object_b.handle.IsIndependent());
7164 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7165 CHECK(object_a.flag);
7166 CHECK(object_b.flag);
7170 static void InvokeScavenge() {
7171 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7175 static void InvokeMarkSweep() {
7176 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7180 static void ForceScavenge(
7181 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7182 data.GetParameter()->handle.Reset();
7183 data.GetParameter()->flag = true;
7188 static void ForceMarkSweep(
7189 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7190 data.GetParameter()->handle.Reset();
7191 data.GetParameter()->flag = true;
7196 THREADED_TEST(GCFromWeakCallbacks) {
7197 v8::Isolate* isolate = CcTest::isolate();
7198 v8::HandleScope scope(isolate);
7199 v8::Handle<Context> context = Context::New(isolate);
7200 Context::Scope context_scope(context);
7202 static const int kNumberOfGCTypes = 2;
7203 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7205 Callback gc_forcing_callback[kNumberOfGCTypes] =
7206 {&ForceScavenge, &ForceMarkSweep};
7208 typedef void (*GCInvoker)();
7209 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7211 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7212 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7213 FlagAndPersistent object;
7215 v8::HandleScope handle_scope(isolate);
7216 object.handle.Reset(isolate, v8::Object::New(isolate));
7218 object.flag = false;
7219 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7220 object.handle.MarkIndependent();
7221 invoke_gc[outer_gc]();
7228 static void RevivingCallback(
7229 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7230 data.GetParameter()->handle.ClearWeak();
7231 data.GetParameter()->flag = true;
7235 THREADED_TEST(IndependentHandleRevival) {
7236 v8::Isolate* isolate = CcTest::isolate();
7237 v8::HandleScope scope(isolate);
7238 v8::Handle<Context> context = Context::New(isolate);
7239 Context::Scope context_scope(context);
7241 FlagAndPersistent object;
7243 v8::HandleScope handle_scope(isolate);
7244 v8::Local<v8::Object> o = v8::Object::New(isolate);
7245 object.handle.Reset(isolate, o);
7246 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7247 v8::Local<String> y_str = v8_str("y");
7248 o->Set(y_str, y_str);
7250 object.flag = false;
7251 object.handle.SetWeak(&object, &RevivingCallback);
7252 object.handle.MarkIndependent();
7253 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7255 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7257 v8::HandleScope handle_scope(isolate);
7258 v8::Local<v8::Object> o =
7259 v8::Local<v8::Object>::New(isolate, object.handle);
7260 v8::Local<String> y_str = v8_str("y");
7261 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7262 CHECK(o->Get(y_str)->Equals(y_str));
7267 v8::Handle<Function> args_fun;
7270 static void ArgumentsTestCallback(
7271 const v8::FunctionCallbackInfo<v8::Value>& args) {
7272 ApiTestFuzzer::Fuzz();
7273 v8::Isolate* isolate = args.GetIsolate();
7274 CHECK_EQ(args_fun, args.Callee());
7275 CHECK_EQ(3, args.Length());
7276 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7277 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7278 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7279 CHECK_EQ(v8::Undefined(isolate), args[3]);
7280 v8::HandleScope scope(args.GetIsolate());
7281 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7285 THREADED_TEST(Arguments) {
7286 v8::Isolate* isolate = CcTest::isolate();
7287 v8::HandleScope scope(isolate);
7288 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7289 global->Set(v8_str("f"),
7290 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7291 LocalContext context(NULL, global);
7292 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7293 v8_compile("f(1, 2, 3)")->Run();
7297 static void NoBlockGetterX(Local<String> name,
7298 const v8::PropertyCallbackInfo<v8::Value>&) {
7302 static void NoBlockGetterI(uint32_t index,
7303 const v8::PropertyCallbackInfo<v8::Value>&) {
7307 static void PDeleter(Local<String> name,
7308 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7309 if (!name->Equals(v8_str("foo"))) {
7310 return; // not intercepted
7313 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7317 static void IDeleter(uint32_t index,
7318 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7320 return; // not intercepted
7323 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7327 THREADED_TEST(Deleter) {
7328 v8::Isolate* isolate = CcTest::isolate();
7329 v8::HandleScope scope(isolate);
7330 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7331 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7332 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7333 LocalContext context;
7334 context->Global()->Set(v8_str("k"), obj->NewInstance());
7340 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7341 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7343 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7344 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7346 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7347 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7349 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7350 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7354 static void GetK(Local<String> name,
7355 const v8::PropertyCallbackInfo<v8::Value>& info) {
7356 ApiTestFuzzer::Fuzz();
7357 if (name->Equals(v8_str("foo")) ||
7358 name->Equals(v8_str("bar")) ||
7359 name->Equals(v8_str("baz"))) {
7360 info.GetReturnValue().SetUndefined();
7365 static void IndexedGetK(uint32_t index,
7366 const v8::PropertyCallbackInfo<v8::Value>& info) {
7367 ApiTestFuzzer::Fuzz();
7368 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7372 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7373 ApiTestFuzzer::Fuzz();
7374 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7375 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7376 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7377 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7378 info.GetReturnValue().Set(result);
7382 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7383 ApiTestFuzzer::Fuzz();
7384 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7385 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7386 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7387 info.GetReturnValue().Set(result);
7391 THREADED_TEST(Enumerators) {
7392 v8::Isolate* isolate = CcTest::isolate();
7393 v8::HandleScope scope(isolate);
7394 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7395 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7396 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7397 LocalContext context;
7398 context->Global()->Set(v8_str("k"), obj->NewInstance());
7399 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7404 "k[4294967295] = 0;"
7406 "k[4294967296] = 0;"
7410 "k[30000000000] = 0;"
7413 "for (var prop in k) {"
7414 " result.push(prop);"
7417 // Check that we get all the property names returned including the
7418 // ones from the enumerators in the right order: indexed properties
7419 // in numerical order, indexed interceptor properties, named
7420 // properties in insertion order, named interceptor properties.
7421 // This order is not mandated by the spec, so this test is just
7422 // documenting our behavior.
7423 CHECK_EQ(17, result->Length());
7424 // Indexed properties in numerical order.
7425 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7426 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7427 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7428 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7429 // Indexed interceptor properties in the order they are returned
7430 // from the enumerator interceptor.
7431 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7432 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7433 // Named properties in insertion order.
7434 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7435 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7436 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7437 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7438 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7439 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7440 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7441 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7442 // Named interceptor properties.
7443 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7444 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7445 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7450 int p_getter_count2;
7453 static void PGetter(Local<String> name,
7454 const v8::PropertyCallbackInfo<v8::Value>& info) {
7455 ApiTestFuzzer::Fuzz();
7457 v8::Handle<v8::Object> global =
7458 info.GetIsolate()->GetCurrentContext()->Global();
7459 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7460 if (name->Equals(v8_str("p1"))) {
7461 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7462 } else if (name->Equals(v8_str("p2"))) {
7463 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7464 } else if (name->Equals(v8_str("p3"))) {
7465 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7466 } else if (name->Equals(v8_str("p4"))) {
7467 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7472 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7473 ApiTestFuzzer::Fuzz();
7474 LocalContext context;
7475 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7477 "o1.__proto__ = { };"
7478 "var o2 = { __proto__: o1 };"
7479 "var o3 = { __proto__: o2 };"
7480 "var o4 = { __proto__: o3 };"
7481 "for (var i = 0; i < 10; i++) o4.p4;"
7482 "for (var i = 0; i < 10; i++) o3.p3;"
7483 "for (var i = 0; i < 10; i++) o2.p2;"
7484 "for (var i = 0; i < 10; i++) o1.p1;");
7488 static void PGetter2(Local<String> name,
7489 const v8::PropertyCallbackInfo<v8::Value>& info) {
7490 ApiTestFuzzer::Fuzz();
7492 v8::Handle<v8::Object> global =
7493 info.GetIsolate()->GetCurrentContext()->Global();
7494 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7495 if (name->Equals(v8_str("p1"))) {
7496 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7497 } else if (name->Equals(v8_str("p2"))) {
7498 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7499 } else if (name->Equals(v8_str("p3"))) {
7500 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7501 } else if (name->Equals(v8_str("p4"))) {
7502 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7507 THREADED_TEST(GetterHolders) {
7508 v8::Isolate* isolate = CcTest::isolate();
7509 v8::HandleScope scope(isolate);
7510 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7511 obj->SetAccessor(v8_str("p1"), PGetter);
7512 obj->SetAccessor(v8_str("p2"), PGetter);
7513 obj->SetAccessor(v8_str("p3"), PGetter);
7514 obj->SetAccessor(v8_str("p4"), PGetter);
7517 CHECK_EQ(40, p_getter_count);
7521 THREADED_TEST(PreInterceptorHolders) {
7522 v8::Isolate* isolate = CcTest::isolate();
7523 v8::HandleScope scope(isolate);
7524 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7525 obj->SetNamedPropertyHandler(PGetter2);
7526 p_getter_count2 = 0;
7528 CHECK_EQ(40, p_getter_count2);
7532 THREADED_TEST(ObjectInstantiation) {
7533 v8::Isolate* isolate = CcTest::isolate();
7534 v8::HandleScope scope(isolate);
7535 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7536 templ->SetAccessor(v8_str("t"), PGetter2);
7537 LocalContext context;
7538 context->Global()->Set(v8_str("o"), templ->NewInstance());
7539 for (int i = 0; i < 100; i++) {
7540 v8::HandleScope inner_scope(CcTest::isolate());
7541 v8::Handle<v8::Object> obj = templ->NewInstance();
7542 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7543 context->Global()->Set(v8_str("o2"), obj);
7544 v8::Handle<Value> value =
7545 CompileRun("o.__proto__ === o2.__proto__");
7546 CHECK_EQ(v8::True(isolate), value);
7547 context->Global()->Set(v8_str("o"), obj);
7552 static int StrCmp16(uint16_t* a, uint16_t* b) {
7554 if (*a == 0 && *b == 0) return 0;
7555 if (*a != *b) return 0 + *a - *b;
7562 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7564 if (n-- == 0) return 0;
7565 if (*a == 0 && *b == 0) return 0;
7566 if (*a != *b) return 0 + *a - *b;
7573 int GetUtf8Length(Handle<String> str) {
7574 int len = str->Utf8Length();
7576 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7577 i::String::Flatten(istr);
7578 len = str->Utf8Length();
7584 THREADED_TEST(StringWrite) {
7585 LocalContext context;
7586 v8::HandleScope scope(context->GetIsolate());
7587 v8::Handle<String> str = v8_str("abcde");
7588 // abc<Icelandic eth><Unicode snowman>.
7589 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7590 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7591 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7592 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7593 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7594 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7595 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7596 // single lead surrogate
7597 uint16_t lead[1] = { 0xd800 };
7598 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7599 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7600 // single trail surrogate
7601 uint16_t trail[1] = { 0xdc00 };
7602 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7603 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7605 uint16_t pair[2] = { 0xd800, 0xdc00 };
7606 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7607 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7608 const int kStride = 4; // Must match stride in for loops in JS below.
7611 "for (var i = 0; i < 0xd800; i += 4) {"
7612 " left = left + String.fromCharCode(i);"
7616 "for (var i = 0; i < 0xd800; i += 4) {"
7617 " right = String.fromCharCode(i) + right;"
7619 v8::Handle<v8::Object> global = context->Global();
7620 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7621 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7623 CHECK_EQ(5, str2->Length());
7624 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7625 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7628 char utf8buf[0xd800 * 3];
7633 memset(utf8buf, 0x1, 1000);
7634 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7636 CHECK_EQ(5, charlen);
7637 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7639 memset(utf8buf, 0x1, 1000);
7640 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7642 CHECK_EQ(5, charlen);
7643 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7645 memset(utf8buf, 0x1, 1000);
7646 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7648 CHECK_EQ(4, charlen);
7649 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7651 memset(utf8buf, 0x1, 1000);
7652 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7654 CHECK_EQ(4, charlen);
7655 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7657 memset(utf8buf, 0x1, 1000);
7658 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7660 CHECK_EQ(4, charlen);
7661 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7663 memset(utf8buf, 0x1, 1000);
7664 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7666 CHECK_EQ(3, charlen);
7667 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7669 memset(utf8buf, 0x1, 1000);
7670 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7672 CHECK_EQ(3, charlen);
7673 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7675 memset(utf8buf, 0x1, 1000);
7676 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7678 CHECK_EQ(2, charlen);
7679 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7681 // allow orphan surrogates by default
7682 memset(utf8buf, 0x1, 1000);
7683 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7685 CHECK_EQ(8, charlen);
7686 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7688 // replace orphan surrogates with unicode replacement character
7689 memset(utf8buf, 0x1, 1000);
7690 len = orphans_str->WriteUtf8(utf8buf,
7693 String::REPLACE_INVALID_UTF8);
7695 CHECK_EQ(8, charlen);
7696 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7698 // replace single lead surrogate with unicode replacement character
7699 memset(utf8buf, 0x1, 1000);
7700 len = lead_str->WriteUtf8(utf8buf,
7703 String::REPLACE_INVALID_UTF8);
7705 CHECK_EQ(1, charlen);
7706 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7708 // replace single trail surrogate with unicode replacement character
7709 memset(utf8buf, 0x1, 1000);
7710 len = trail_str->WriteUtf8(utf8buf,
7713 String::REPLACE_INVALID_UTF8);
7715 CHECK_EQ(1, charlen);
7716 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7718 // do not replace / write anything if surrogate pair does not fit the buffer
7720 memset(utf8buf, 0x1, 1000);
7721 len = pair_str->WriteUtf8(utf8buf,
7724 String::REPLACE_INVALID_UTF8);
7726 CHECK_EQ(0, charlen);
7728 memset(utf8buf, 0x1, sizeof(utf8buf));
7729 len = GetUtf8Length(left_tree);
7731 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7732 CHECK_EQ(utf8_expected, len);
7733 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7734 CHECK_EQ(utf8_expected, len);
7735 CHECK_EQ(0xd800 / kStride, charlen);
7736 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7737 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7738 CHECK_EQ(0xc0 - kStride,
7739 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7740 CHECK_EQ(1, utf8buf[utf8_expected]);
7742 memset(utf8buf, 0x1, sizeof(utf8buf));
7743 len = GetUtf8Length(right_tree);
7744 CHECK_EQ(utf8_expected, len);
7745 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7746 CHECK_EQ(utf8_expected, len);
7747 CHECK_EQ(0xd800 / kStride, charlen);
7748 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7749 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7750 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7751 CHECK_EQ(1, utf8buf[utf8_expected]);
7753 memset(buf, 0x1, sizeof(buf));
7754 memset(wbuf, 0x1, sizeof(wbuf));
7755 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7757 len = str->Write(wbuf);
7759 CHECK_EQ(0, strcmp("abcde", buf));
7760 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7761 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7763 memset(buf, 0x1, sizeof(buf));
7764 memset(wbuf, 0x1, sizeof(wbuf));
7765 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7767 len = str->Write(wbuf, 0, 4);
7769 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7770 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7771 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7773 memset(buf, 0x1, sizeof(buf));
7774 memset(wbuf, 0x1, sizeof(wbuf));
7775 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7777 len = str->Write(wbuf, 0, 5);
7779 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7780 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7781 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7783 memset(buf, 0x1, sizeof(buf));
7784 memset(wbuf, 0x1, sizeof(wbuf));
7785 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7787 len = str->Write(wbuf, 0, 6);
7789 CHECK_EQ(0, strcmp("abcde", buf));
7790 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7791 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7793 memset(buf, 0x1, sizeof(buf));
7794 memset(wbuf, 0x1, sizeof(wbuf));
7795 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7797 len = str->Write(wbuf, 4, -1);
7799 CHECK_EQ(0, strcmp("e", buf));
7800 uint16_t answer5[] = {'e', '\0'};
7801 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7803 memset(buf, 0x1, sizeof(buf));
7804 memset(wbuf, 0x1, sizeof(wbuf));
7805 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7807 len = str->Write(wbuf, 4, 6);
7809 CHECK_EQ(0, strcmp("e", buf));
7810 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7812 memset(buf, 0x1, sizeof(buf));
7813 memset(wbuf, 0x1, sizeof(wbuf));
7814 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7816 len = str->Write(wbuf, 4, 1);
7818 CHECK_EQ(0, strncmp("e\1", buf, 2));
7819 uint16_t answer6[] = {'e', 0x101};
7820 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7822 memset(buf, 0x1, sizeof(buf));
7823 memset(wbuf, 0x1, sizeof(wbuf));
7824 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7826 len = str->Write(wbuf, 3, 1);
7828 CHECK_EQ(0, strncmp("d\1", buf, 2));
7829 uint16_t answer7[] = {'d', 0x101};
7830 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7832 memset(wbuf, 0x1, sizeof(wbuf));
7834 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7836 CHECK_EQ('X', wbuf[5]);
7837 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7838 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7839 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7840 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7842 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7844 memset(buf, 0x1, sizeof(buf));
7846 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7849 String::NO_NULL_TERMINATION);
7851 CHECK_EQ('X', buf[5]);
7852 CHECK_EQ(0, strncmp("abcde", buf, 5));
7853 CHECK_NE(0, strcmp("abcde", buf));
7855 CHECK_EQ(0, strcmp("abcde", buf));
7857 memset(utf8buf, 0x1, sizeof(utf8buf));
7859 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7860 String::NO_NULL_TERMINATION);
7862 CHECK_EQ('X', utf8buf[8]);
7863 CHECK_EQ(5, charlen);
7864 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7865 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7867 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7869 memset(utf8buf, 0x1, sizeof(utf8buf));
7871 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7872 String::NO_NULL_TERMINATION);
7874 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7875 CHECK_EQ(5, charlen);
7877 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7879 memset(buf, 0x1, sizeof(buf));
7880 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7882 CHECK_EQ(0, strcmp("abc", buf));
7883 CHECK_EQ(0, buf[3]);
7884 CHECK_EQ(0, strcmp("def", buf + 4));
7886 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7887 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7888 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7892 static void Utf16Helper(
7893 LocalContext& context, // NOLINT
7895 const char* lengths_name,
7897 Local<v8::Array> a =
7898 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7899 Local<v8::Array> alens =
7900 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7901 for (int i = 0; i < len; i++) {
7902 Local<v8::String> string =
7903 Local<v8::String>::Cast(a->Get(i));
7904 Local<v8::Number> expected_len =
7905 Local<v8::Number>::Cast(alens->Get(i));
7906 int length = GetUtf8Length(string);
7907 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7912 static uint16_t StringGet(Handle<String> str, int index) {
7913 i::Handle<i::String> istring =
7914 v8::Utils::OpenHandle(String::Cast(*str));
7915 return istring->Get(index);
7919 static void WriteUtf8Helper(
7920 LocalContext& context, // NOLINT
7922 const char* lengths_name,
7924 Local<v8::Array> b =
7925 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7926 Local<v8::Array> alens =
7927 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7930 for (int i = 0; i < len; i++) {
7931 Local<v8::String> string =
7932 Local<v8::String>::Cast(b->Get(i));
7933 Local<v8::Number> expected_len =
7934 Local<v8::Number>::Cast(alens->Get(i));
7935 int utf8_length = static_cast<int>(expected_len->Value());
7936 for (int j = utf8_length + 1; j >= 0; j--) {
7937 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7938 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7941 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7943 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7944 CHECK_GE(utf8_length + 1, utf8_written);
7945 CHECK_GE(utf8_length, utf8_written2);
7946 for (int k = 0; k < utf8_written2; k++) {
7947 CHECK_EQ(buffer[k], buffer2[k]);
7949 CHECK(nchars * 3 >= utf8_written - 1);
7950 CHECK(nchars <= utf8_written);
7951 if (j == utf8_length + 1) {
7952 CHECK_EQ(utf8_written2, utf8_length);
7953 CHECK_EQ(utf8_written2 + 1, utf8_written);
7955 CHECK_EQ(buffer[utf8_written], 42);
7956 if (j > utf8_length) {
7957 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7958 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7959 Handle<String> roundtrip = v8_str(buffer);
7960 CHECK(roundtrip->Equals(string));
7962 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7964 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7966 uint16_t trail = StringGet(string, nchars - 1);
7967 uint16_t lead = StringGet(string, nchars - 2);
7968 if (((lead & 0xfc00) == 0xd800) &&
7969 ((trail & 0xfc00) == 0xdc00)) {
7970 unsigned char u1 = buffer2[utf8_written2 - 4];
7971 unsigned char u2 = buffer2[utf8_written2 - 3];
7972 unsigned char u3 = buffer2[utf8_written2 - 2];
7973 unsigned char u4 = buffer2[utf8_written2 - 1];
7974 CHECK_EQ((u1 & 0xf8), 0xf0);
7975 CHECK_EQ((u2 & 0xc0), 0x80);
7976 CHECK_EQ((u3 & 0xc0), 0x80);
7977 CHECK_EQ((u4 & 0xc0), 0x80);
7978 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7979 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7980 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7981 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7982 CHECK_EQ((u1 & 0x3), c >> 18);
7990 THREADED_TEST(Utf16) {
7991 LocalContext context;
7992 v8::HandleScope scope(context->GetIsolate());
7994 "var pad = '01234567890123456789';"
7996 "var plens = [20, 3, 3];"
7997 "p.push('01234567890123456789');"
7998 "var lead = 0xd800;"
7999 "var trail = 0xdc00;"
8000 "p.push(String.fromCharCode(0xd800));"
8001 "p.push(String.fromCharCode(0xdc00));"
8006 "for (var i = 0; i < 3; i++) {"
8007 " p[1] = String.fromCharCode(lead++);"
8008 " for (var j = 0; j < 3; j++) {"
8009 " p[2] = String.fromCharCode(trail++);"
8010 " a.push(p[i] + p[j]);"
8011 " b.push(p[i] + p[j]);"
8012 " c.push(p[i] + p[j]);"
8013 " alens.push(plens[i] + plens[j]);"
8016 "alens[5] -= 2;" // Here the surrogate pairs match up.
8021 "for (var m = 0; m < 9; m++) {"
8022 " for (var n = 0; n < 9; n++) {"
8023 " a2.push(a[m] + a[n]);"
8024 " b2.push(b[m] + b[n]);"
8025 " var newc = 'x' + c[m] + c[n] + 'y';"
8026 " c2.push(newc.substring(1, newc.length - 1));"
8027 " var utf = alens[m] + alens[n];" // And here.
8028 // The 'n's that start with 0xdc.. are 6-8
8029 // The 'm's that end with 0xd8.. are 1, 4 and 7
8030 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8031 " a2lens.push(utf);"
8034 Utf16Helper(context, "a", "alens", 9);
8035 Utf16Helper(context, "a2", "a2lens", 81);
8036 WriteUtf8Helper(context, "b", "alens", 9);
8037 WriteUtf8Helper(context, "b2", "a2lens", 81);
8038 WriteUtf8Helper(context, "c2", "a2lens", 81);
8042 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8043 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8044 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8045 return *is1 == *is2;
8048 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8050 Handle<String> symbol1 =
8051 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8052 Handle<String> symbol2 =
8053 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8054 CHECK(SameSymbol(symbol1, symbol2));
8058 THREADED_TEST(Utf16Symbol) {
8059 LocalContext context;
8060 v8::HandleScope scope(context->GetIsolate());
8062 Handle<String> symbol1 = v8::String::NewFromUtf8(
8063 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8064 Handle<String> symbol2 = v8::String::NewFromUtf8(
8065 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8066 CHECK(SameSymbol(symbol1, symbol2));
8068 SameSymbolHelper(context->GetIsolate(),
8069 "\360\220\220\205", // 4 byte encoding.
8070 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8071 SameSymbolHelper(context->GetIsolate(),
8072 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8073 "\360\220\220\206"); // 4 byte encoding.
8074 SameSymbolHelper(context->GetIsolate(),
8075 "x\360\220\220\205", // 4 byte encoding.
8076 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8077 SameSymbolHelper(context->GetIsolate(),
8078 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8079 "x\360\220\220\206"); // 4 byte encoding.
8081 "var sym0 = 'benedictus';"
8082 "var sym0b = 'S\303\270ren';"
8083 "var sym1 = '\355\240\201\355\260\207';"
8084 "var sym2 = '\360\220\220\210';"
8085 "var sym3 = 'x\355\240\201\355\260\207';"
8086 "var sym4 = 'x\360\220\220\210';"
8087 "if (sym1.length != 2) throw sym1;"
8088 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8089 "if (sym2.length != 2) throw sym2;"
8090 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8091 "if (sym3.length != 3) throw sym3;"
8092 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8093 "if (sym4.length != 3) throw sym4;"
8094 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8095 Handle<String> sym0 = v8::String::NewFromUtf8(
8096 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8097 Handle<String> sym0b = v8::String::NewFromUtf8(
8098 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8099 Handle<String> sym1 =
8100 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8101 v8::String::kInternalizedString);
8102 Handle<String> sym2 =
8103 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8104 v8::String::kInternalizedString);
8105 Handle<String> sym3 = v8::String::NewFromUtf8(
8106 context->GetIsolate(), "x\355\240\201\355\260\207",
8107 v8::String::kInternalizedString);
8108 Handle<String> sym4 =
8109 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8110 v8::String::kInternalizedString);
8111 v8::Local<v8::Object> global = context->Global();
8112 Local<Value> s0 = global->Get(v8_str("sym0"));
8113 Local<Value> s0b = global->Get(v8_str("sym0b"));
8114 Local<Value> s1 = global->Get(v8_str("sym1"));
8115 Local<Value> s2 = global->Get(v8_str("sym2"));
8116 Local<Value> s3 = global->Get(v8_str("sym3"));
8117 Local<Value> s4 = global->Get(v8_str("sym4"));
8118 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8119 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8120 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8121 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8122 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8123 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8127 THREADED_TEST(ToArrayIndex) {
8128 LocalContext context;
8129 v8::Isolate* isolate = context->GetIsolate();
8130 v8::HandleScope scope(isolate);
8132 v8::Handle<String> str = v8_str("42");
8133 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8134 CHECK(!index.IsEmpty());
8135 CHECK_EQ(42.0, index->Uint32Value());
8136 str = v8_str("42asdf");
8137 index = str->ToArrayIndex();
8138 CHECK(index.IsEmpty());
8139 str = v8_str("-42");
8140 index = str->ToArrayIndex();
8141 CHECK(index.IsEmpty());
8142 str = v8_str("4294967295");
8143 index = str->ToArrayIndex();
8144 CHECK(!index.IsEmpty());
8145 CHECK_EQ(4294967295.0, index->Uint32Value());
8146 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8147 index = num->ToArrayIndex();
8148 CHECK(!index.IsEmpty());
8149 CHECK_EQ(1.0, index->Uint32Value());
8150 num = v8::Number::New(isolate, -1);
8151 index = num->ToArrayIndex();
8152 CHECK(index.IsEmpty());
8153 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8154 index = obj->ToArrayIndex();
8155 CHECK(index.IsEmpty());
8159 THREADED_TEST(ErrorConstruction) {
8160 LocalContext context;
8161 v8::HandleScope scope(context->GetIsolate());
8163 v8::Handle<String> foo = v8_str("foo");
8164 v8::Handle<String> message = v8_str("message");
8165 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8166 CHECK(range_error->IsObject());
8167 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8168 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8169 CHECK(reference_error->IsObject());
8170 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8171 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8172 CHECK(syntax_error->IsObject());
8173 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8174 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8175 CHECK(type_error->IsObject());
8176 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8177 v8::Handle<Value> error = v8::Exception::Error(foo);
8178 CHECK(error->IsObject());
8179 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8183 static void YGetter(Local<String> name,
8184 const v8::PropertyCallbackInfo<v8::Value>& info) {
8185 ApiTestFuzzer::Fuzz();
8186 info.GetReturnValue().Set(v8_num(10));
8190 static void YSetter(Local<String> name,
8192 const v8::PropertyCallbackInfo<void>& info) {
8193 Local<Object> this_obj = Local<Object>::Cast(info.This());
8194 if (this_obj->Has(name)) this_obj->Delete(name);
8195 this_obj->Set(name, value);
8199 THREADED_TEST(DeleteAccessor) {
8200 v8::Isolate* isolate = CcTest::isolate();
8201 v8::HandleScope scope(isolate);
8202 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8203 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8204 LocalContext context;
8205 v8::Handle<v8::Object> holder = obj->NewInstance();
8206 context->Global()->Set(v8_str("holder"), holder);
8207 v8::Handle<Value> result = CompileRun(
8208 "holder.y = 11; holder.y = 12; holder.y");
8209 CHECK_EQ(12, result->Uint32Value());
8213 THREADED_TEST(TypeSwitch) {
8214 v8::Isolate* isolate = CcTest::isolate();
8215 v8::HandleScope scope(isolate);
8216 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8217 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8218 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8219 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8220 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8221 LocalContext context;
8222 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8223 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8224 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8225 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8226 for (int i = 0; i < 10; i++) {
8227 CHECK_EQ(0, type_switch->match(obj0));
8228 CHECK_EQ(1, type_switch->match(obj1));
8229 CHECK_EQ(2, type_switch->match(obj2));
8230 CHECK_EQ(3, type_switch->match(obj3));
8231 CHECK_EQ(3, type_switch->match(obj3));
8232 CHECK_EQ(2, type_switch->match(obj2));
8233 CHECK_EQ(1, type_switch->match(obj1));
8234 CHECK_EQ(0, type_switch->match(obj0));
8239 static int trouble_nesting = 0;
8240 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8241 ApiTestFuzzer::Fuzz();
8244 // Call a JS function that throws an uncaught exception.
8245 Local<v8::Object> arg_this =
8246 args.GetIsolate()->GetCurrentContext()->Global();
8247 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8248 arg_this->Get(v8_str("trouble_callee")) :
8249 arg_this->Get(v8_str("trouble_caller"));
8250 CHECK(trouble_callee->IsFunction());
8251 args.GetReturnValue().Set(
8252 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8256 static int report_count = 0;
8257 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8258 v8::Handle<Value>) {
8263 // Counts uncaught exceptions, but other tests running in parallel
8264 // also have uncaught exceptions.
8265 TEST(ApiUncaughtException) {
8268 v8::Isolate* isolate = env->GetIsolate();
8269 v8::HandleScope scope(isolate);
8270 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8272 Local<v8::FunctionTemplate> fun =
8273 v8::FunctionTemplate::New(isolate, TroubleCallback);
8274 v8::Local<v8::Object> global = env->Global();
8275 global->Set(v8_str("trouble"), fun->GetFunction());
8278 "function trouble_callee() {"
8282 "function trouble_caller() {"
8285 Local<Value> trouble = global->Get(v8_str("trouble"));
8286 CHECK(trouble->IsFunction());
8287 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8288 CHECK(trouble_callee->IsFunction());
8289 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8290 CHECK(trouble_caller->IsFunction());
8291 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8292 CHECK_EQ(1, report_count);
8293 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8296 static const char* script_resource_name = "ExceptionInNativeScript.js";
8297 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8298 v8::Handle<Value>) {
8299 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8300 CHECK(!name_val.IsEmpty() && name_val->IsString());
8301 v8::String::Utf8Value name(message->GetScriptResourceName());
8302 CHECK_EQ(script_resource_name, *name);
8303 CHECK_EQ(3, message->GetLineNumber());
8304 v8::String::Utf8Value source_line(message->GetSourceLine());
8305 CHECK_EQ(" new o.foo();", *source_line);
8309 TEST(ExceptionInNativeScript) {
8311 v8::Isolate* isolate = env->GetIsolate();
8312 v8::HandleScope scope(isolate);
8313 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8315 Local<v8::FunctionTemplate> fun =
8316 v8::FunctionTemplate::New(isolate, TroubleCallback);
8317 v8::Local<v8::Object> global = env->Global();
8318 global->Set(v8_str("trouble"), fun->GetFunction());
8320 CompileRunWithOrigin(
8321 "function trouble() {\n"
8325 script_resource_name);
8326 Local<Value> trouble = global->Get(v8_str("trouble"));
8327 CHECK(trouble->IsFunction());
8328 Function::Cast(*trouble)->Call(global, 0, NULL);
8329 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8333 TEST(CompilationErrorUsingTryCatchHandler) {
8335 v8::HandleScope scope(env->GetIsolate());
8336 v8::TryCatch try_catch;
8337 v8_compile("This doesn't &*&@#$&*^ compile.");
8338 CHECK_NE(NULL, *try_catch.Exception());
8339 CHECK(try_catch.HasCaught());
8343 TEST(TryCatchFinallyUsingTryCatchHandler) {
8345 v8::HandleScope scope(env->GetIsolate());
8346 v8::TryCatch try_catch;
8347 CompileRun("try { throw ''; } catch (e) {}");
8348 CHECK(!try_catch.HasCaught());
8349 CompileRun("try { throw ''; } finally {}");
8350 CHECK(try_catch.HasCaught());
8354 "try { throw ''; } finally { return; }"
8356 CHECK(!try_catch.HasCaught());
8359 " { try { throw ''; } finally { throw 0; }"
8361 CHECK(try_catch.HasCaught());
8365 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8366 v8::HandleScope scope(args.GetIsolate());
8367 CompileRun(args[0]->ToString());
8371 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8372 v8::Isolate* isolate = CcTest::isolate();
8373 v8::HandleScope scope(isolate);
8374 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8375 templ->Set(v8_str("CEvaluate"),
8376 v8::FunctionTemplate::New(isolate, CEvaluate));
8377 LocalContext context(0, templ);
8378 v8::TryCatch try_catch;
8380 " CEvaluate('throw 1;');"
8383 CHECK(try_catch.HasCaught());
8384 CHECK(!try_catch.Message().IsEmpty());
8385 String::Utf8Value exception_value(try_catch.Exception());
8386 CHECK_EQ(*exception_value, "1");
8389 " CEvaluate('throw 1;');"
8393 CHECK(try_catch.HasCaught());
8394 CHECK(!try_catch.Message().IsEmpty());
8395 String::Utf8Value finally_exception_value(try_catch.Exception());
8396 CHECK_EQ(*finally_exception_value, "2");
8400 // For use within the TestSecurityHandler() test.
8401 static bool g_security_callback_result = false;
8402 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8404 v8::AccessType type,
8405 Local<Value> data) {
8407 // Always allow read access.
8408 if (type == v8::ACCESS_GET)
8411 // Sometimes allow other access.
8412 return g_security_callback_result;
8416 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8418 v8::AccessType type,
8419 Local<Value> data) {
8421 // Always allow read access.
8422 if (type == v8::ACCESS_GET)
8425 // Sometimes allow other access.
8426 return g_security_callback_result;
8430 // SecurityHandler can't be run twice
8431 TEST(SecurityHandler) {
8432 v8::Isolate* isolate = CcTest::isolate();
8433 v8::HandleScope scope0(isolate);
8434 v8::Handle<v8::ObjectTemplate> global_template =
8435 v8::ObjectTemplate::New(isolate);
8436 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8437 IndexedSecurityTestCallback);
8438 // Create an environment
8439 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8442 v8::Handle<v8::Object> global0 = context0->Global();
8443 v8::Handle<Script> script0 = v8_compile("foo = 111");
8445 global0->Set(v8_str("0"), v8_num(999));
8446 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8447 CHECK_EQ(111, foo0->Int32Value());
8448 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8449 CHECK_EQ(999, z0->Int32Value());
8451 // Create another environment, should fail security checks.
8452 v8::HandleScope scope1(isolate);
8454 v8::Handle<Context> context1 =
8455 Context::New(isolate, NULL, global_template);
8458 v8::Handle<v8::Object> global1 = context1->Global();
8459 global1->Set(v8_str("othercontext"), global0);
8460 // This set will fail the security check.
8461 v8::Handle<Script> script1 =
8462 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8464 // This read will pass the security check.
8465 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8466 CHECK_EQ(111, foo1->Int32Value());
8467 // This read will pass the security check.
8468 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8469 CHECK_EQ(999, z1->Int32Value());
8471 // Create another environment, should pass security checks.
8472 { g_security_callback_result = true; // allow security handler to pass.
8473 v8::HandleScope scope2(isolate);
8474 LocalContext context2;
8475 v8::Handle<v8::Object> global2 = context2->Global();
8476 global2->Set(v8_str("othercontext"), global0);
8477 v8::Handle<Script> script2 =
8478 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8480 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8481 CHECK_EQ(333, foo2->Int32Value());
8482 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8483 CHECK_EQ(888, z2->Int32Value());
8491 THREADED_TEST(SecurityChecks) {
8493 v8::HandleScope handle_scope(env1->GetIsolate());
8494 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8496 Local<Value> foo = v8_str("foo");
8497 Local<Value> bar = v8_str("bar");
8499 // Set to the same domain.
8500 env1->SetSecurityToken(foo);
8502 // Create a function in env1.
8503 CompileRun("spy=function(){return spy;}");
8504 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8505 CHECK(spy->IsFunction());
8507 // Create another function accessing global objects.
8508 CompileRun("spy2=function(){return new this.Array();}");
8509 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8510 CHECK(spy2->IsFunction());
8512 // Switch to env2 in the same domain and invoke spy on env2.
8514 env2->SetSecurityToken(foo);
8516 Context::Scope scope_env2(env2);
8517 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8518 CHECK(result->IsFunction());
8522 env2->SetSecurityToken(bar);
8523 Context::Scope scope_env2(env2);
8525 // Call cross_domain_call, it should throw an exception
8526 v8::TryCatch try_catch;
8527 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8528 CHECK(try_catch.HasCaught());
8533 // Regression test case for issue 1183439.
8534 THREADED_TEST(SecurityChecksForPrototypeChain) {
8535 LocalContext current;
8536 v8::HandleScope scope(current->GetIsolate());
8537 v8::Handle<Context> other = Context::New(current->GetIsolate());
8539 // Change context to be able to get to the Object function in the
8540 // other context without hitting the security checks.
8541 v8::Local<Value> other_object;
8542 { Context::Scope scope(other);
8543 other_object = other->Global()->Get(v8_str("Object"));
8544 other->Global()->Set(v8_num(42), v8_num(87));
8547 current->Global()->Set(v8_str("other"), other->Global());
8548 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8550 // Make sure the security check fails here and we get an undefined
8551 // result instead of getting the Object function. Repeat in a loop
8552 // to make sure to exercise the IC code.
8553 v8::Local<Script> access_other0 = v8_compile("other.Object");
8554 v8::Local<Script> access_other1 = v8_compile("other[42]");
8555 for (int i = 0; i < 5; i++) {
8556 CHECK(!access_other0->Run()->Equals(other_object));
8557 CHECK(access_other0->Run()->IsUndefined());
8558 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8559 CHECK(access_other1->Run()->IsUndefined());
8562 // Create an object that has 'other' in its prototype chain and make
8563 // sure we cannot access the Object function indirectly through
8564 // that. Repeat in a loop to make sure to exercise the IC code.
8565 v8_compile("function F() { };"
8566 "F.prototype = other;"
8567 "var f = new F();")->Run();
8568 v8::Local<Script> access_f0 = v8_compile("f.Object");
8569 v8::Local<Script> access_f1 = v8_compile("f[42]");
8570 for (int j = 0; j < 5; j++) {
8571 CHECK(!access_f0->Run()->Equals(other_object));
8572 CHECK(access_f0->Run()->IsUndefined());
8573 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8574 CHECK(access_f1->Run()->IsUndefined());
8577 // Now it gets hairy: Set the prototype for the other global object
8578 // to be the current global object. The prototype chain for 'f' now
8579 // goes through 'other' but ends up in the current global object.
8580 { Context::Scope scope(other);
8581 other->Global()->Set(v8_str("__proto__"), current->Global());
8583 // Set a named and an index property on the current global
8584 // object. To force the lookup to go through the other global object,
8585 // the properties must not exist in the other global object.
8586 current->Global()->Set(v8_str("foo"), v8_num(100));
8587 current->Global()->Set(v8_num(99), v8_num(101));
8588 // Try to read the properties from f and make sure that the access
8589 // gets stopped by the security checks on the other global object.
8590 Local<Script> access_f2 = v8_compile("f.foo");
8591 Local<Script> access_f3 = v8_compile("f[99]");
8592 for (int k = 0; k < 5; k++) {
8593 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8594 CHECK(access_f2->Run()->IsUndefined());
8595 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8596 CHECK(access_f3->Run()->IsUndefined());
8601 static bool named_security_check_with_gc_called;
8603 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8605 v8::AccessType type,
8606 Local<Value> data) {
8607 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8608 named_security_check_with_gc_called = true;
8613 static bool indexed_security_check_with_gc_called;
8615 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8617 v8::AccessType type,
8618 Local<Value> data) {
8619 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8620 indexed_security_check_with_gc_called = true;
8625 TEST(SecurityTestGCAllowed) {
8626 v8::Isolate* isolate = CcTest::isolate();
8627 v8::HandleScope handle_scope(isolate);
8628 v8::Handle<v8::ObjectTemplate> object_template =
8629 v8::ObjectTemplate::New(isolate);
8630 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8631 IndexedSecurityTestCallbackWithGC);
8633 v8::Handle<Context> context = Context::New(isolate);
8634 v8::Context::Scope context_scope(context);
8636 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8638 named_security_check_with_gc_called = false;
8639 CompileRun("obj.foo = new String(1001);");
8640 CHECK(named_security_check_with_gc_called);
8642 indexed_security_check_with_gc_called = false;
8643 CompileRun("obj[0] = new String(1002);");
8644 CHECK(indexed_security_check_with_gc_called);
8646 named_security_check_with_gc_called = false;
8647 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8648 CHECK(named_security_check_with_gc_called);
8650 indexed_security_check_with_gc_called = false;
8651 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8652 CHECK(indexed_security_check_with_gc_called);
8656 THREADED_TEST(CrossDomainDelete) {
8658 v8::HandleScope handle_scope(env1->GetIsolate());
8659 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8661 Local<Value> foo = v8_str("foo");
8662 Local<Value> bar = v8_str("bar");
8664 // Set to the same domain.
8665 env1->SetSecurityToken(foo);
8666 env2->SetSecurityToken(foo);
8668 env1->Global()->Set(v8_str("prop"), v8_num(3));
8669 env2->Global()->Set(v8_str("env1"), env1->Global());
8671 // Change env2 to a different domain and delete env1.prop.
8672 env2->SetSecurityToken(bar);
8674 Context::Scope scope_env2(env2);
8675 Local<Value> result =
8676 CompileRun("delete env1.prop");
8677 CHECK(result->IsFalse());
8680 // Check that env1.prop still exists.
8681 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8682 CHECK(v->IsNumber());
8683 CHECK_EQ(3, v->Int32Value());
8687 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8689 v8::HandleScope handle_scope(env1->GetIsolate());
8690 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8692 Local<Value> foo = v8_str("foo");
8693 Local<Value> bar = v8_str("bar");
8695 // Set to the same domain.
8696 env1->SetSecurityToken(foo);
8697 env2->SetSecurityToken(foo);
8699 env1->Global()->Set(v8_str("prop"), v8_num(3));
8700 env2->Global()->Set(v8_str("env1"), env1->Global());
8702 // env1.prop is enumerable in env2.
8703 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8705 Context::Scope scope_env2(env2);
8706 Local<Value> result = CompileRun(test);
8707 CHECK(result->IsTrue());
8710 // Change env2 to a different domain and test again.
8711 env2->SetSecurityToken(bar);
8713 Context::Scope scope_env2(env2);
8714 Local<Value> result = CompileRun(test);
8715 CHECK(result->IsFalse());
8720 THREADED_TEST(CrossDomainForIn) {
8722 v8::HandleScope handle_scope(env1->GetIsolate());
8723 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8725 Local<Value> foo = v8_str("foo");
8726 Local<Value> bar = v8_str("bar");
8728 // Set to the same domain.
8729 env1->SetSecurityToken(foo);
8730 env2->SetSecurityToken(foo);
8732 env1->Global()->Set(v8_str("prop"), v8_num(3));
8733 env2->Global()->Set(v8_str("env1"), env1->Global());
8735 // Change env2 to a different domain and set env1's global object
8736 // as the __proto__ of an object in env2 and enumerate properties
8737 // in for-in. It shouldn't enumerate properties on env1's global
8739 env2->SetSecurityToken(bar);
8741 Context::Scope scope_env2(env2);
8742 Local<Value> result =
8743 CompileRun("(function(){var obj = {'__proto__':env1};"
8744 "for (var p in obj)"
8745 " if (p == 'prop') return false;"
8746 "return true;})()");
8747 CHECK(result->IsTrue());
8752 TEST(ContextDetachGlobal) {
8754 v8::HandleScope handle_scope(env1->GetIsolate());
8755 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8757 Local<v8::Object> global1 = env1->Global();
8759 Local<Value> foo = v8_str("foo");
8761 // Set to the same domain.
8762 env1->SetSecurityToken(foo);
8763 env2->SetSecurityToken(foo);
8768 // Create a function in env2 and add a reference to it in env1.
8769 Local<v8::Object> global2 = env2->Global();
8770 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8771 CompileRun("function getProp() {return prop;}");
8773 env1->Global()->Set(v8_str("getProp"),
8774 global2->Get(v8_str("getProp")));
8776 // Detach env2's global, and reuse the global object of env2
8778 env2->DetachGlobal();
8780 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8782 v8::Handle<v8::ObjectTemplate>(),
8784 env3->SetSecurityToken(v8_str("bar"));
8787 Local<v8::Object> global3 = env3->Global();
8788 CHECK_EQ(global2, global3);
8789 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8790 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8791 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8792 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8795 // Call getProp in env1, and it should return the value 1
8797 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8798 CHECK(get_prop->IsFunction());
8799 v8::TryCatch try_catch;
8800 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8801 CHECK(!try_catch.HasCaught());
8802 CHECK_EQ(1, r->Int32Value());
8805 // Check that env3 is not accessible from env1
8807 Local<Value> r = global3->Get(v8_str("prop2"));
8808 CHECK(r->IsUndefined());
8813 TEST(DetachGlobal) {
8815 v8::HandleScope scope(env1->GetIsolate());
8817 // Create second environment.
8818 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8820 Local<Value> foo = v8_str("foo");
8822 // Set same security token for env1 and env2.
8823 env1->SetSecurityToken(foo);
8824 env2->SetSecurityToken(foo);
8826 // Create a property on the global object in env2.
8828 v8::Context::Scope scope(env2);
8829 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8832 // Create a reference to env2 global from env1 global.
8833 env1->Global()->Set(v8_str("other"), env2->Global());
8835 // Check that we have access to other.p in env2 from env1.
8836 Local<Value> result = CompileRun("other.p");
8837 CHECK(result->IsInt32());
8838 CHECK_EQ(42, result->Int32Value());
8840 // Hold on to global from env2 and detach global from env2.
8841 Local<v8::Object> global2 = env2->Global();
8842 env2->DetachGlobal();
8844 // Check that the global has been detached. No other.p property can
8846 result = CompileRun("other.p");
8847 CHECK(result->IsUndefined());
8849 // Reuse global2 for env3.
8850 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8852 v8::Handle<v8::ObjectTemplate>(),
8854 CHECK_EQ(global2, env3->Global());
8856 // Start by using the same security token for env3 as for env1 and env2.
8857 env3->SetSecurityToken(foo);
8859 // Create a property on the global object in env3.
8861 v8::Context::Scope scope(env3);
8862 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8865 // Check that other.p is now the property in env3 and that we have access.
8866 result = CompileRun("other.p");
8867 CHECK(result->IsInt32());
8868 CHECK_EQ(24, result->Int32Value());
8870 // Change security token for env3 to something different from env1 and env2.
8871 env3->SetSecurityToken(v8_str("bar"));
8873 // Check that we do not have access to other.p in env1. |other| is now
8874 // the global object for env3 which has a different security token,
8875 // so access should be blocked.
8876 result = CompileRun("other.p");
8877 CHECK(result->IsUndefined());
8881 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8882 info.GetReturnValue().Set(
8883 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8887 TEST(DetachedAccesses) {
8889 v8::HandleScope scope(env1->GetIsolate());
8891 // Create second environment.
8892 Local<ObjectTemplate> inner_global_template =
8893 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8894 inner_global_template ->SetAccessorProperty(
8895 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8896 v8::Local<Context> env2 =
8897 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8899 Local<Value> foo = v8_str("foo");
8901 // Set same security token for env1 and env2.
8902 env1->SetSecurityToken(foo);
8903 env2->SetSecurityToken(foo);
8905 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8908 v8::Context::Scope scope(env2);
8909 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8911 "function bound_x() { return x; }"
8912 "function get_x() { return this.x; }"
8913 "function get_x_w() { return (function() {return this.x;})(); }");
8914 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8915 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8916 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8917 env1->Global()->Set(
8919 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8922 Local<Object> env2_global = env2->Global();
8923 env2_global->TurnOnAccessCheck();
8924 env2->DetachGlobal();
8926 Local<Value> result;
8927 result = CompileRun("bound_x()");
8928 CHECK_EQ(v8_str("env2_x"), result);
8929 result = CompileRun("get_x()");
8930 CHECK(result->IsUndefined());
8931 result = CompileRun("get_x_w()");
8932 CHECK(result->IsUndefined());
8933 result = CompileRun("this_x()");
8934 CHECK_EQ(v8_str("env2_x"), result);
8936 // Reattach env2's proxy
8937 env2 = Context::New(env1->GetIsolate(),
8939 v8::Handle<v8::ObjectTemplate>(),
8941 env2->SetSecurityToken(foo);
8943 v8::Context::Scope scope(env2);
8944 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8945 env2->Global()->Set(v8_str("env1"), env1->Global());
8946 result = CompileRun(
8948 "for (var i = 0; i < 4; i++ ) {"
8949 " results.push(env1.bound_x());"
8950 " results.push(env1.get_x());"
8951 " results.push(env1.get_x_w());"
8952 " results.push(env1.this_x());"
8955 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8956 CHECK_EQ(16, results->Length());
8957 for (int i = 0; i < 16; i += 4) {
8958 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8959 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8960 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8961 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8965 result = CompileRun(
8967 "for (var i = 0; i < 4; i++ ) {"
8968 " results.push(bound_x());"
8969 " results.push(get_x());"
8970 " results.push(get_x_w());"
8971 " results.push(this_x());"
8974 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8975 CHECK_EQ(16, results->Length());
8976 for (int i = 0; i < 16; i += 4) {
8977 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8978 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8979 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8980 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8983 result = CompileRun(
8985 "for (var i = 0; i < 4; i++ ) {"
8986 " results.push(this.bound_x());"
8987 " results.push(this.get_x());"
8988 " results.push(this.get_x_w());"
8989 " results.push(this.this_x());"
8992 results = Local<v8::Array>::Cast(result);
8993 CHECK_EQ(16, results->Length());
8994 for (int i = 0; i < 16; i += 4) {
8995 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8996 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8997 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8998 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9003 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9004 static bool NamedAccessBlocker(Local<v8::Object> global,
9006 v8::AccessType type,
9007 Local<Value> data) {
9008 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9009 allowed_access_type[type];
9013 static bool IndexedAccessBlocker(Local<v8::Object> global,
9015 v8::AccessType type,
9016 Local<Value> data) {
9017 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9018 allowed_access_type[type];
9022 static int g_echo_value_1 = -1;
9023 static int g_echo_value_2 = -1;
9026 static void EchoGetter(
9028 const v8::PropertyCallbackInfo<v8::Value>& info) {
9029 info.GetReturnValue().Set(v8_num(g_echo_value_1));
9033 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9034 info.GetReturnValue().Set(v8_num(g_echo_value_2));
9038 static void EchoSetter(Local<String> name,
9040 const v8::PropertyCallbackInfo<void>&) {
9041 if (value->IsNumber())
9042 g_echo_value_1 = value->Int32Value();
9046 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9047 v8::Handle<v8::Value> value = info[0];
9048 if (value->IsNumber())
9049 g_echo_value_2 = value->Int32Value();
9053 static void UnreachableGetter(
9055 const v8::PropertyCallbackInfo<v8::Value>& info) {
9056 CHECK(false); // This function should not be called..
9060 static void UnreachableSetter(Local<String>,
9062 const v8::PropertyCallbackInfo<void>&) {
9063 CHECK(false); // This function should nto be called.
9067 static void UnreachableFunction(
9068 const v8::FunctionCallbackInfo<v8::Value>& info) {
9069 CHECK(false); // This function should not be called..
9073 TEST(AccessControl) {
9074 v8::Isolate* isolate = CcTest::isolate();
9075 v8::HandleScope handle_scope(isolate);
9076 v8::Handle<v8::ObjectTemplate> global_template =
9077 v8::ObjectTemplate::New(isolate);
9079 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9080 IndexedAccessBlocker);
9082 // Add an accessor accessible by cross-domain JS code.
9083 global_template->SetAccessor(
9084 v8_str("accessible_prop"),
9085 EchoGetter, EchoSetter,
9086 v8::Handle<Value>(),
9087 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9090 global_template->SetAccessorProperty(
9091 v8_str("accessible_js_prop"),
9092 v8::FunctionTemplate::New(isolate, EchoGetter),
9093 v8::FunctionTemplate::New(isolate, EchoSetter),
9095 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9097 // Add an accessor that is not accessible by cross-domain JS code.
9098 global_template->SetAccessor(v8_str("blocked_prop"),
9099 UnreachableGetter, UnreachableSetter,
9100 v8::Handle<Value>(),
9103 global_template->SetAccessorProperty(
9104 v8_str("blocked_js_prop"),
9105 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9106 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9110 // Create an environment
9111 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9114 v8::Handle<v8::Object> global0 = context0->Global();
9116 // Define a property with JS getter and setter.
9118 "function getter() { return 'getter'; };\n"
9119 "function setter() { return 'setter'; }\n"
9120 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9122 Local<Value> getter = global0->Get(v8_str("getter"));
9123 Local<Value> setter = global0->Get(v8_str("setter"));
9125 // And define normal element.
9126 global0->Set(239, v8_str("239"));
9128 // Define an element with JS getter and setter.
9130 "function el_getter() { return 'el_getter'; };\n"
9131 "function el_setter() { return 'el_setter'; };\n"
9132 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9134 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9135 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9137 v8::HandleScope scope1(isolate);
9139 v8::Local<Context> context1 = Context::New(isolate);
9142 v8::Handle<v8::Object> global1 = context1->Global();
9143 global1->Set(v8_str("other"), global0);
9145 // Access blocked property.
9146 CompileRun("other.blocked_prop = 1");
9148 ExpectUndefined("other.blocked_prop");
9150 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9151 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9153 // Enable ACCESS_HAS
9154 allowed_access_type[v8::ACCESS_HAS] = true;
9155 ExpectUndefined("other.blocked_prop");
9156 // ... and now we can get the descriptor...
9158 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9159 // ... and enumerate the property.
9160 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9161 allowed_access_type[v8::ACCESS_HAS] = false;
9163 // Access blocked element.
9164 CompileRun("other[239] = 1");
9166 ExpectUndefined("other[239]");
9167 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9168 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9170 // Enable ACCESS_HAS
9171 allowed_access_type[v8::ACCESS_HAS] = true;
9172 ExpectUndefined("other[239]");
9173 // ... and now we can get the descriptor...
9174 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9175 // ... and enumerate the property.
9176 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9177 allowed_access_type[v8::ACCESS_HAS] = false;
9179 // Access a property with JS accessor.
9180 CompileRun("other.js_accessor_p = 2");
9182 ExpectUndefined("other.js_accessor_p");
9184 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9186 // Enable ACCESS_HAS.
9187 allowed_access_type[v8::ACCESS_HAS] = true;
9188 ExpectUndefined("other.js_accessor_p");
9190 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9192 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9194 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9195 allowed_access_type[v8::ACCESS_HAS] = false;
9197 // Enable both ACCESS_HAS and ACCESS_GET.
9198 allowed_access_type[v8::ACCESS_HAS] = true;
9199 allowed_access_type[v8::ACCESS_GET] = true;
9201 ExpectString("other.js_accessor_p", "getter");
9203 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9205 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9207 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9209 allowed_access_type[v8::ACCESS_GET] = false;
9210 allowed_access_type[v8::ACCESS_HAS] = false;
9212 // Enable both ACCESS_HAS and ACCESS_SET.
9213 allowed_access_type[v8::ACCESS_HAS] = true;
9214 allowed_access_type[v8::ACCESS_SET] = true;
9216 ExpectUndefined("other.js_accessor_p");
9218 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9220 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9222 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9224 allowed_access_type[v8::ACCESS_SET] = false;
9225 allowed_access_type[v8::ACCESS_HAS] = false;
9227 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9228 allowed_access_type[v8::ACCESS_HAS] = true;
9229 allowed_access_type[v8::ACCESS_GET] = true;
9230 allowed_access_type[v8::ACCESS_SET] = true;
9232 ExpectString("other.js_accessor_p", "getter");
9234 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9236 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9238 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9240 allowed_access_type[v8::ACCESS_SET] = false;
9241 allowed_access_type[v8::ACCESS_GET] = false;
9242 allowed_access_type[v8::ACCESS_HAS] = false;
9244 // Access an element with JS accessor.
9245 CompileRun("other[42] = 2");
9247 ExpectUndefined("other[42]");
9248 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9250 // Enable ACCESS_HAS.
9251 allowed_access_type[v8::ACCESS_HAS] = true;
9252 ExpectUndefined("other[42]");
9253 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9254 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9255 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9256 allowed_access_type[v8::ACCESS_HAS] = false;
9258 // Enable both ACCESS_HAS and ACCESS_GET.
9259 allowed_access_type[v8::ACCESS_HAS] = true;
9260 allowed_access_type[v8::ACCESS_GET] = true;
9262 ExpectString("other[42]", "el_getter");
9263 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9264 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9265 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9267 allowed_access_type[v8::ACCESS_GET] = false;
9268 allowed_access_type[v8::ACCESS_HAS] = false;
9270 // Enable both ACCESS_HAS and ACCESS_SET.
9271 allowed_access_type[v8::ACCESS_HAS] = true;
9272 allowed_access_type[v8::ACCESS_SET] = true;
9274 ExpectUndefined("other[42]");
9275 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9276 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9277 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9279 allowed_access_type[v8::ACCESS_SET] = false;
9280 allowed_access_type[v8::ACCESS_HAS] = false;
9282 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9283 allowed_access_type[v8::ACCESS_HAS] = true;
9284 allowed_access_type[v8::ACCESS_GET] = true;
9285 allowed_access_type[v8::ACCESS_SET] = true;
9287 ExpectString("other[42]", "el_getter");
9288 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9289 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9290 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9292 allowed_access_type[v8::ACCESS_SET] = false;
9293 allowed_access_type[v8::ACCESS_GET] = false;
9294 allowed_access_type[v8::ACCESS_HAS] = false;
9296 v8::Handle<Value> value;
9298 // Access accessible property
9299 value = CompileRun("other.accessible_prop = 3");
9300 CHECK(value->IsNumber());
9301 CHECK_EQ(3, value->Int32Value());
9302 CHECK_EQ(3, g_echo_value_1);
9304 // Access accessible js property
9305 value = CompileRun("other.accessible_js_prop = 3");
9306 CHECK(value->IsNumber());
9307 CHECK_EQ(3, value->Int32Value());
9308 CHECK_EQ(3, g_echo_value_2);
9310 value = CompileRun("other.accessible_prop");
9311 CHECK(value->IsNumber());
9312 CHECK_EQ(3, value->Int32Value());
9314 value = CompileRun("other.accessible_js_prop");
9315 CHECK(value->IsNumber());
9316 CHECK_EQ(3, value->Int32Value());
9319 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9320 CHECK(value->IsNumber());
9321 CHECK_EQ(3, value->Int32Value());
9324 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9325 CHECK(value->IsNumber());
9326 CHECK_EQ(3, value->Int32Value());
9328 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9329 CHECK(value->IsTrue());
9331 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9332 CHECK(value->IsTrue());
9334 // Enumeration doesn't enumerate accessors from inaccessible objects in
9335 // the prototype chain even if the accessors are in themselves accessible.
9337 CompileRun("(function(){var obj = {'__proto__':other};"
9338 "for (var p in obj)"
9339 " if (p == 'accessible_prop' ||"
9340 " p == 'accessible_js_prop' ||"
9341 " p == 'blocked_js_prop' ||"
9342 " p == 'blocked_js_prop') {"
9345 "return true;})()");
9346 CHECK(value->IsTrue());
9353 TEST(AccessControlES5) {
9354 v8::Isolate* isolate = CcTest::isolate();
9355 v8::HandleScope handle_scope(isolate);
9356 v8::Handle<v8::ObjectTemplate> global_template =
9357 v8::ObjectTemplate::New(isolate);
9359 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9360 IndexedAccessBlocker);
9362 // Add accessible accessor.
9363 global_template->SetAccessor(
9364 v8_str("accessible_prop"),
9365 EchoGetter, EchoSetter,
9366 v8::Handle<Value>(),
9367 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9370 // Add an accessor that is not accessible by cross-domain JS code.
9371 global_template->SetAccessor(v8_str("blocked_prop"),
9372 UnreachableGetter, UnreachableSetter,
9373 v8::Handle<Value>(),
9376 // Create an environment
9377 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9380 v8::Handle<v8::Object> global0 = context0->Global();
9382 v8::Local<Context> context1 = Context::New(isolate);
9384 v8::Handle<v8::Object> global1 = context1->Global();
9385 global1->Set(v8_str("other"), global0);
9387 // Regression test for issue 1154.
9388 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9390 ExpectUndefined("other.blocked_prop");
9392 // Regression test for issue 1027.
9393 CompileRun("Object.defineProperty(\n"
9394 " other, 'blocked_prop', {configurable: false})");
9395 ExpectUndefined("other.blocked_prop");
9397 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9399 // Regression test for issue 1171.
9400 ExpectTrue("Object.isExtensible(other)");
9401 CompileRun("Object.preventExtensions(other)");
9402 ExpectTrue("Object.isExtensible(other)");
9404 // Object.seal and Object.freeze.
9405 CompileRun("Object.freeze(other)");
9406 ExpectTrue("Object.isExtensible(other)");
9408 CompileRun("Object.seal(other)");
9409 ExpectTrue("Object.isExtensible(other)");
9411 // Regression test for issue 1250.
9412 // Make sure that we can set the accessible accessors value using normal
9414 CompileRun("other.accessible_prop = 42");
9415 CHECK_EQ(42, g_echo_value_1);
9417 v8::Handle<Value> value;
9418 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9419 value = CompileRun("other.accessible_prop == 42");
9420 CHECK(value->IsTrue());
9424 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9426 v8::AccessType type,
9427 Local<Value> data) {
9432 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9434 v8::AccessType type,
9435 Local<Value> data) {
9440 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9441 v8::Isolate* isolate = CcTest::isolate();
9442 v8::HandleScope handle_scope(isolate);
9443 v8::Handle<v8::ObjectTemplate> obj_template =
9444 v8::ObjectTemplate::New(isolate);
9446 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9447 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9448 GetOwnPropertyNamesIndexedBlocker);
9450 // Create an environment
9451 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9454 v8::Handle<v8::Object> global0 = context0->Global();
9456 v8::HandleScope scope1(CcTest::isolate());
9458 v8::Local<Context> context1 = Context::New(isolate);
9461 v8::Handle<v8::Object> global1 = context1->Global();
9462 global1->Set(v8_str("other"), global0);
9463 global1->Set(v8_str("object"), obj_template->NewInstance());
9465 v8::Handle<Value> value;
9467 // Attempt to get the property names of the other global object and
9468 // of an object that requires access checks. Accessing the other
9469 // global object should be blocked by access checks on the global
9470 // proxy object. Accessing the object that requires access checks
9471 // is blocked by the access checks on the object itself.
9472 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9473 CHECK(value->IsTrue());
9475 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9476 CHECK(value->IsTrue());
9483 static void IndexedPropertyEnumerator(
9484 const v8::PropertyCallbackInfo<v8::Array>& info) {
9485 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9486 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9487 result->Set(1, v8::Object::New(info.GetIsolate()));
9488 info.GetReturnValue().Set(result);
9492 static void NamedPropertyEnumerator(
9493 const v8::PropertyCallbackInfo<v8::Array>& info) {
9494 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9495 result->Set(0, v8_str("x"));
9496 result->Set(1, v8::Object::New(info.GetIsolate()));
9497 info.GetReturnValue().Set(result);
9501 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9502 v8::Isolate* isolate = CcTest::isolate();
9503 v8::HandleScope handle_scope(isolate);
9504 v8::Handle<v8::ObjectTemplate> obj_template =
9505 v8::ObjectTemplate::New(isolate);
9507 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9508 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9509 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9510 IndexedPropertyEnumerator);
9511 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9512 NamedPropertyEnumerator);
9514 LocalContext context;
9515 v8::Handle<v8::Object> global = context->Global();
9516 global->Set(v8_str("object"), obj_template->NewInstance());
9518 v8::Handle<v8::Value> result =
9519 CompileRun("Object.getOwnPropertyNames(object)");
9520 CHECK(result->IsArray());
9521 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9522 CHECK_EQ(3, result_array->Length());
9523 CHECK(result_array->Get(0)->IsString());
9524 CHECK(result_array->Get(1)->IsString());
9525 CHECK(result_array->Get(2)->IsString());
9526 CHECK_EQ(v8_str("7"), result_array->Get(0));
9527 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9528 CHECK_EQ(v8_str("x"), result_array->Get(2));
9532 static void ConstTenGetter(Local<String> name,
9533 const v8::PropertyCallbackInfo<v8::Value>& info) {
9534 info.GetReturnValue().Set(v8_num(10));
9538 THREADED_TEST(CrossDomainAccessors) {
9539 v8::Isolate* isolate = CcTest::isolate();
9540 v8::HandleScope handle_scope(isolate);
9542 v8::Handle<v8::FunctionTemplate> func_template =
9543 v8::FunctionTemplate::New(isolate);
9545 v8::Handle<v8::ObjectTemplate> global_template =
9546 func_template->InstanceTemplate();
9548 v8::Handle<v8::ObjectTemplate> proto_template =
9549 func_template->PrototypeTemplate();
9551 // Add an accessor to proto that's accessible by cross-domain JS code.
9552 proto_template->SetAccessor(v8_str("accessible"),
9554 v8::Handle<Value>(),
9557 // Add an accessor that is not accessible by cross-domain JS code.
9558 global_template->SetAccessor(v8_str("unreachable"),
9559 UnreachableGetter, 0,
9560 v8::Handle<Value>(),
9563 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9566 Local<v8::Object> global = context0->Global();
9567 // Add a normal property that shadows 'accessible'
9568 global->Set(v8_str("accessible"), v8_num(11));
9570 // Enter a new context.
9571 v8::HandleScope scope1(CcTest::isolate());
9572 v8::Local<Context> context1 = Context::New(isolate);
9575 v8::Handle<v8::Object> global1 = context1->Global();
9576 global1->Set(v8_str("other"), global);
9578 // Should return 10, instead of 11
9579 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9580 CHECK(value->IsNumber());
9581 CHECK_EQ(10, value->Int32Value());
9583 value = v8_compile("other.unreachable")->Run();
9584 CHECK(value->IsUndefined());
9591 static int named_access_count = 0;
9592 static int indexed_access_count = 0;
9594 static bool NamedAccessCounter(Local<v8::Object> global,
9596 v8::AccessType type,
9597 Local<Value> data) {
9598 named_access_count++;
9603 static bool IndexedAccessCounter(Local<v8::Object> global,
9605 v8::AccessType type,
9606 Local<Value> data) {
9607 indexed_access_count++;
9612 // This one is too easily disturbed by other tests.
9613 TEST(AccessControlIC) {
9614 named_access_count = 0;
9615 indexed_access_count = 0;
9617 v8::Isolate* isolate = CcTest::isolate();
9618 v8::HandleScope handle_scope(isolate);
9620 // Create an environment.
9621 v8::Local<Context> context0 = Context::New(isolate);
9624 // Create an object that requires access-check functions to be
9625 // called for cross-domain access.
9626 v8::Handle<v8::ObjectTemplate> object_template =
9627 v8::ObjectTemplate::New(isolate);
9628 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9629 IndexedAccessCounter);
9630 Local<v8::Object> object = object_template->NewInstance();
9632 v8::HandleScope scope1(isolate);
9634 // Create another environment.
9635 v8::Local<Context> context1 = Context::New(isolate);
9638 // Make easy access to the object from the other environment.
9639 v8::Handle<v8::Object> global1 = context1->Global();
9640 global1->Set(v8_str("obj"), object);
9642 v8::Handle<Value> value;
9644 // Check that the named access-control function is called every time.
9645 CompileRun("function testProp(obj) {"
9646 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9647 " for (var j = 0; j < 10; j++) obj.prop;"
9650 value = CompileRun("testProp(obj)");
9651 CHECK(value->IsNumber());
9652 CHECK_EQ(1, value->Int32Value());
9653 CHECK_EQ(21, named_access_count);
9655 // Check that the named access-control function is called every time.
9656 CompileRun("var p = 'prop';"
9657 "function testKeyed(obj) {"
9658 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9659 " for (var j = 0; j < 10; j++) obj[p];"
9662 // Use obj which requires access checks. No inline caching is used
9664 value = CompileRun("testKeyed(obj)");
9665 CHECK(value->IsNumber());
9666 CHECK_EQ(1, value->Int32Value());
9667 CHECK_EQ(42, named_access_count);
9668 // Force the inline caches into generic state and try again.
9669 CompileRun("testKeyed({ a: 0 })");
9670 CompileRun("testKeyed({ b: 0 })");
9671 value = CompileRun("testKeyed(obj)");
9672 CHECK(value->IsNumber());
9673 CHECK_EQ(1, value->Int32Value());
9674 CHECK_EQ(63, named_access_count);
9676 // Check that the indexed access-control function is called every time.
9677 CompileRun("function testIndexed(obj) {"
9678 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9679 " for (var j = 0; j < 10; j++) obj[0];"
9682 value = CompileRun("testIndexed(obj)");
9683 CHECK(value->IsNumber());
9684 CHECK_EQ(1, value->Int32Value());
9685 CHECK_EQ(21, indexed_access_count);
9686 // Force the inline caches into generic state.
9687 CompileRun("testIndexed(new Array(1))");
9688 // Test that the indexed access check is called.
9689 value = CompileRun("testIndexed(obj)");
9690 CHECK(value->IsNumber());
9691 CHECK_EQ(1, value->Int32Value());
9692 CHECK_EQ(42, indexed_access_count);
9694 // Check that the named access check is called when invoking
9695 // functions on an object that requires access checks.
9696 CompileRun("obj.f = function() {}");
9697 CompileRun("function testCallNormal(obj) {"
9698 " for (var i = 0; i < 10; i++) obj.f();"
9700 CompileRun("testCallNormal(obj)");
9701 CHECK_EQ(74, named_access_count);
9703 // Force obj into slow case.
9704 value = CompileRun("delete obj.prop");
9705 CHECK(value->BooleanValue());
9706 // Force inline caches into dictionary probing mode.
9707 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9708 // Test that the named access check is called.
9709 value = CompileRun("testProp(obj);");
9710 CHECK(value->IsNumber());
9711 CHECK_EQ(1, value->Int32Value());
9712 CHECK_EQ(96, named_access_count);
9714 // Force the call inline cache into dictionary probing mode.
9715 CompileRun("o.f = function() {}; testCallNormal(o)");
9716 // Test that the named access check is still called for each
9717 // invocation of the function.
9718 value = CompileRun("testCallNormal(obj)");
9719 CHECK_EQ(106, named_access_count);
9726 static bool NamedAccessFlatten(Local<v8::Object> global,
9728 v8::AccessType type,
9729 Local<Value> data) {
9733 CHECK(name->IsString());
9735 memset(buf, 0x1, sizeof(buf));
9736 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9741 memset(buf, 0x1, sizeof(buf));
9742 len = name.As<String>()->Write(buf2);
9749 static bool IndexedAccessFlatten(Local<v8::Object> global,
9751 v8::AccessType type,
9752 Local<Value> data) {
9757 // Regression test. In access checks, operations that may cause
9758 // garbage collection are not allowed. It used to be the case that
9759 // using the Write operation on a string could cause a garbage
9760 // collection due to flattening of the string. This is no longer the
9762 THREADED_TEST(AccessControlFlatten) {
9763 named_access_count = 0;
9764 indexed_access_count = 0;
9766 v8::Isolate* isolate = CcTest::isolate();
9767 v8::HandleScope handle_scope(isolate);
9769 // Create an environment.
9770 v8::Local<Context> context0 = Context::New(isolate);
9773 // Create an object that requires access-check functions to be
9774 // called for cross-domain access.
9775 v8::Handle<v8::ObjectTemplate> object_template =
9776 v8::ObjectTemplate::New(isolate);
9777 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9778 IndexedAccessFlatten);
9779 Local<v8::Object> object = object_template->NewInstance();
9781 v8::HandleScope scope1(isolate);
9783 // Create another environment.
9784 v8::Local<Context> context1 = Context::New(isolate);
9787 // Make easy access to the object from the other environment.
9788 v8::Handle<v8::Object> global1 = context1->Global();
9789 global1->Set(v8_str("obj"), object);
9791 v8::Handle<Value> value;
9793 value = v8_compile("var p = 'as' + 'df';")->Run();
9794 value = v8_compile("obj[p];")->Run();
9801 static void AccessControlNamedGetter(
9803 const v8::PropertyCallbackInfo<v8::Value>& info) {
9804 info.GetReturnValue().Set(42);
9808 static void AccessControlNamedSetter(
9811 const v8::PropertyCallbackInfo<v8::Value>& info) {
9812 info.GetReturnValue().Set(value);
9816 static void AccessControlIndexedGetter(
9818 const v8::PropertyCallbackInfo<v8::Value>& info) {
9819 info.GetReturnValue().Set(v8_num(42));
9823 static void AccessControlIndexedSetter(
9826 const v8::PropertyCallbackInfo<v8::Value>& info) {
9827 info.GetReturnValue().Set(value);
9831 THREADED_TEST(AccessControlInterceptorIC) {
9832 named_access_count = 0;
9833 indexed_access_count = 0;
9835 v8::Isolate* isolate = CcTest::isolate();
9836 v8::HandleScope handle_scope(isolate);
9838 // Create an environment.
9839 v8::Local<Context> context0 = Context::New(isolate);
9842 // Create an object that requires access-check functions to be
9843 // called for cross-domain access. The object also has interceptors
9845 v8::Handle<v8::ObjectTemplate> object_template =
9846 v8::ObjectTemplate::New(isolate);
9847 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9848 IndexedAccessCounter);
9849 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9850 AccessControlNamedSetter);
9851 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9852 AccessControlIndexedSetter);
9853 Local<v8::Object> object = object_template->NewInstance();
9855 v8::HandleScope scope1(isolate);
9857 // Create another environment.
9858 v8::Local<Context> context1 = Context::New(isolate);
9861 // Make easy access to the object from the other environment.
9862 v8::Handle<v8::Object> global1 = context1->Global();
9863 global1->Set(v8_str("obj"), object);
9865 v8::Handle<Value> value;
9867 // Check that the named access-control function is called every time
9868 // eventhough there is an interceptor on the object.
9869 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9870 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9872 CHECK(value->IsNumber());
9873 CHECK_EQ(42, value->Int32Value());
9874 CHECK_EQ(21, named_access_count);
9876 value = v8_compile("var p = 'x';")->Run();
9877 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9878 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9880 CHECK(value->IsNumber());
9881 CHECK_EQ(42, value->Int32Value());
9882 CHECK_EQ(42, named_access_count);
9884 // Check that the indexed access-control function is called every
9885 // time eventhough there is an interceptor on the object.
9886 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9887 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9889 CHECK(value->IsNumber());
9890 CHECK_EQ(42, value->Int32Value());
9891 CHECK_EQ(21, indexed_access_count);
9898 THREADED_TEST(Version) {
9899 v8::V8::GetVersion();
9903 static void InstanceFunctionCallback(
9904 const v8::FunctionCallbackInfo<v8::Value>& args) {
9905 ApiTestFuzzer::Fuzz();
9906 args.GetReturnValue().Set(v8_num(12));
9910 THREADED_TEST(InstanceProperties) {
9911 LocalContext context;
9912 v8::Isolate* isolate = context->GetIsolate();
9913 v8::HandleScope handle_scope(isolate);
9915 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9916 Local<ObjectTemplate> instance = t->InstanceTemplate();
9918 instance->Set(v8_str("x"), v8_num(42));
9919 instance->Set(v8_str("f"),
9920 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9922 Local<Value> o = t->GetFunction()->NewInstance();
9924 context->Global()->Set(v8_str("i"), o);
9925 Local<Value> value = CompileRun("i.x");
9926 CHECK_EQ(42, value->Int32Value());
9928 value = CompileRun("i.f()");
9929 CHECK_EQ(12, value->Int32Value());
9933 static void GlobalObjectInstancePropertiesGet(
9935 const v8::PropertyCallbackInfo<v8::Value>&) {
9936 ApiTestFuzzer::Fuzz();
9940 THREADED_TEST(GlobalObjectInstanceProperties) {
9941 v8::Isolate* isolate = CcTest::isolate();
9942 v8::HandleScope handle_scope(isolate);
9944 Local<Value> global_object;
9946 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9947 t->InstanceTemplate()->SetNamedPropertyHandler(
9948 GlobalObjectInstancePropertiesGet);
9949 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9950 instance_template->Set(v8_str("x"), v8_num(42));
9951 instance_template->Set(v8_str("f"),
9952 v8::FunctionTemplate::New(isolate,
9953 InstanceFunctionCallback));
9955 // The script to check how Crankshaft compiles missing global function
9956 // invocations. function g is not defined and should throw on call.
9957 const char* script =
9958 "function wrapper(call) {"
9959 " var x = 0, y = 1;"
9960 " for (var i = 0; i < 1000; i++) {"
9966 "for (var i = 0; i < 17; i++) wrapper(false);"
9968 "try { wrapper(true); } catch (e) { thrown = 1; };"
9972 LocalContext env(NULL, instance_template);
9973 // Hold on to the global object so it can be used again in another
9974 // environment initialization.
9975 global_object = env->Global();
9977 Local<Value> value = CompileRun("x");
9978 CHECK_EQ(42, value->Int32Value());
9979 value = CompileRun("f()");
9980 CHECK_EQ(12, value->Int32Value());
9981 value = CompileRun(script);
9982 CHECK_EQ(1, value->Int32Value());
9986 // Create new environment reusing the global object.
9987 LocalContext env(NULL, instance_template, global_object);
9988 Local<Value> value = CompileRun("x");
9989 CHECK_EQ(42, value->Int32Value());
9990 value = CompileRun("f()");
9991 CHECK_EQ(12, value->Int32Value());
9992 value = CompileRun(script);
9993 CHECK_EQ(1, value->Int32Value());
9998 THREADED_TEST(CallKnownGlobalReceiver) {
9999 v8::Isolate* isolate = CcTest::isolate();
10000 v8::HandleScope handle_scope(isolate);
10002 Local<Value> global_object;
10004 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10005 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10007 // The script to check that we leave global object not
10008 // global object proxy on stack when we deoptimize from inside
10009 // arguments evaluation.
10010 // To provoke error we need to both force deoptimization
10011 // from arguments evaluation and to force CallIC to take
10012 // CallIC_Miss code path that can't cope with global proxy.
10013 const char* script =
10014 "function bar(x, y) { try { } finally { } }"
10015 "function baz(x) { try { } finally { } }"
10016 "function bom(x) { try { } finally { } }"
10017 "function foo(x) { bar([x], bom(2)); }"
10018 "for (var i = 0; i < 10000; i++) foo(1);"
10023 LocalContext env(NULL, instance_template);
10024 // Hold on to the global object so it can be used again in another
10025 // environment initialization.
10026 global_object = env->Global();
10027 foo = CompileRun(script);
10031 // Create new environment reusing the global object.
10032 LocalContext env(NULL, instance_template, global_object);
10033 env->Global()->Set(v8_str("foo"), foo);
10034 CompileRun("foo()");
10039 static void ShadowFunctionCallback(
10040 const v8::FunctionCallbackInfo<v8::Value>& args) {
10041 ApiTestFuzzer::Fuzz();
10042 args.GetReturnValue().Set(v8_num(42));
10046 static int shadow_y;
10047 static int shadow_y_setter_call_count;
10048 static int shadow_y_getter_call_count;
10051 static void ShadowYSetter(Local<String>,
10053 const v8::PropertyCallbackInfo<void>&) {
10054 shadow_y_setter_call_count++;
10059 static void ShadowYGetter(Local<String> name,
10060 const v8::PropertyCallbackInfo<v8::Value>& info) {
10061 ApiTestFuzzer::Fuzz();
10062 shadow_y_getter_call_count++;
10063 info.GetReturnValue().Set(v8_num(shadow_y));
10067 static void ShadowIndexedGet(uint32_t index,
10068 const v8::PropertyCallbackInfo<v8::Value>&) {
10072 static void ShadowNamedGet(Local<String> key,
10073 const v8::PropertyCallbackInfo<v8::Value>&) {
10077 THREADED_TEST(ShadowObject) {
10078 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10079 v8::Isolate* isolate = CcTest::isolate();
10080 v8::HandleScope handle_scope(isolate);
10082 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10083 LocalContext context(NULL, global_template);
10085 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10086 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10087 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10088 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10089 Local<ObjectTemplate> instance = t->InstanceTemplate();
10091 proto->Set(v8_str("f"),
10092 v8::FunctionTemplate::New(isolate,
10093 ShadowFunctionCallback,
10095 proto->Set(v8_str("x"), v8_num(12));
10097 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10099 Local<Value> o = t->GetFunction()->NewInstance();
10100 context->Global()->Set(v8_str("__proto__"), o);
10102 Local<Value> value =
10103 CompileRun("this.propertyIsEnumerable(0)");
10104 CHECK(value->IsBoolean());
10105 CHECK(!value->BooleanValue());
10107 value = CompileRun("x");
10108 CHECK_EQ(12, value->Int32Value());
10110 value = CompileRun("f()");
10111 CHECK_EQ(42, value->Int32Value());
10113 CompileRun("y = 43");
10114 CHECK_EQ(1, shadow_y_setter_call_count);
10115 value = CompileRun("y");
10116 CHECK_EQ(1, shadow_y_getter_call_count);
10117 CHECK_EQ(42, value->Int32Value());
10121 THREADED_TEST(HiddenPrototype) {
10122 LocalContext context;
10123 v8::Isolate* isolate = context->GetIsolate();
10124 v8::HandleScope handle_scope(isolate);
10126 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10127 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10128 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10129 t1->SetHiddenPrototype(true);
10130 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10131 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10132 t2->SetHiddenPrototype(true);
10133 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10134 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10135 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10137 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10138 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10139 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10140 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10142 // Setting the prototype on an object skips hidden prototypes.
10143 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10144 o0->Set(v8_str("__proto__"), o1);
10145 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10146 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10147 o0->Set(v8_str("__proto__"), o2);
10148 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10149 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10150 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10151 o0->Set(v8_str("__proto__"), o3);
10152 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10153 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10154 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10155 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10157 // Getting the prototype of o0 should get the first visible one
10158 // which is o3. Therefore, z should not be defined on the prototype
10160 Local<Value> proto = o0->Get(v8_str("__proto__"));
10161 CHECK(proto->IsObject());
10162 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10166 THREADED_TEST(HiddenPrototypeSet) {
10167 LocalContext context;
10168 v8::Isolate* isolate = context->GetIsolate();
10169 v8::HandleScope handle_scope(isolate);
10171 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10172 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10173 ht->SetHiddenPrototype(true);
10174 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10175 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10177 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10178 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10179 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10180 o->Set(v8_str("__proto__"), h);
10181 h->Set(v8_str("__proto__"), p);
10183 // Setting a property that exists on the hidden prototype goes there.
10184 o->Set(v8_str("x"), v8_num(7));
10185 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10186 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10187 CHECK(p->Get(v8_str("x"))->IsUndefined());
10189 // Setting a new property should not be forwarded to the hidden prototype.
10190 o->Set(v8_str("y"), v8_num(6));
10191 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10192 CHECK(h->Get(v8_str("y"))->IsUndefined());
10193 CHECK(p->Get(v8_str("y"))->IsUndefined());
10195 // Setting a property that only exists on a prototype of the hidden prototype
10196 // is treated normally again.
10197 p->Set(v8_str("z"), v8_num(8));
10198 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10199 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10200 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10201 o->Set(v8_str("z"), v8_num(9));
10202 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10203 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10204 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10208 // Regression test for issue 2457.
10209 THREADED_TEST(HiddenPrototypeIdentityHash) {
10210 LocalContext context;
10211 v8::HandleScope handle_scope(context->GetIsolate());
10213 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10214 t->SetHiddenPrototype(true);
10215 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10216 Handle<Object> p = t->GetFunction()->NewInstance();
10217 Handle<Object> o = Object::New(context->GetIsolate());
10218 o->SetPrototype(p);
10220 int hash = o->GetIdentityHash();
10222 o->Set(v8_str("foo"), v8_num(42));
10223 ASSERT_EQ(hash, o->GetIdentityHash());
10227 THREADED_TEST(SetPrototype) {
10228 LocalContext context;
10229 v8::Isolate* isolate = context->GetIsolate();
10230 v8::HandleScope handle_scope(isolate);
10232 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10233 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10234 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10235 t1->SetHiddenPrototype(true);
10236 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10237 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10238 t2->SetHiddenPrototype(true);
10239 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10240 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10241 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10243 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10244 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10245 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10246 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10248 // Setting the prototype on an object does not skip hidden prototypes.
10249 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10250 CHECK(o0->SetPrototype(o1));
10251 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10252 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10253 CHECK(o1->SetPrototype(o2));
10254 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10255 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10256 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10257 CHECK(o2->SetPrototype(o3));
10258 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10259 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10260 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10261 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10263 // Getting the prototype of o0 should get the first visible one
10264 // which is o3. Therefore, z should not be defined on the prototype
10266 Local<Value> proto = o0->Get(v8_str("__proto__"));
10267 CHECK(proto->IsObject());
10268 CHECK_EQ(proto.As<v8::Object>(), o3);
10270 // However, Object::GetPrototype ignores hidden prototype.
10271 Local<Value> proto0 = o0->GetPrototype();
10272 CHECK(proto0->IsObject());
10273 CHECK_EQ(proto0.As<v8::Object>(), o1);
10275 Local<Value> proto1 = o1->GetPrototype();
10276 CHECK(proto1->IsObject());
10277 CHECK_EQ(proto1.As<v8::Object>(), o2);
10279 Local<Value> proto2 = o2->GetPrototype();
10280 CHECK(proto2->IsObject());
10281 CHECK_EQ(proto2.As<v8::Object>(), o3);
10285 // Getting property names of an object with a prototype chain that
10286 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10287 // crash the runtime.
10288 THREADED_TEST(Regress91517) {
10289 i::FLAG_allow_natives_syntax = true;
10290 LocalContext context;
10291 v8::Isolate* isolate = context->GetIsolate();
10292 v8::HandleScope handle_scope(isolate);
10294 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10295 t1->SetHiddenPrototype(true);
10296 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10297 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10298 t2->SetHiddenPrototype(true);
10299 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10300 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10301 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10302 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10303 t3->SetHiddenPrototype(true);
10304 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10305 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10306 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10308 // Force dictionary-based properties.
10309 i::ScopedVector<char> name_buf(1024);
10310 for (int i = 1; i <= 1000; i++) {
10311 i::SNPrintF(name_buf, "sdf%d", i);
10312 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10315 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10316 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10317 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10318 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10320 // Create prototype chain of hidden prototypes.
10321 CHECK(o4->SetPrototype(o3));
10322 CHECK(o3->SetPrototype(o2));
10323 CHECK(o2->SetPrototype(o1));
10325 // Call the runtime version of GetOwnPropertyNames() on the natively
10326 // created object through JavaScript.
10327 context->Global()->Set(v8_str("obj"), o4);
10328 // PROPERTY_ATTRIBUTES_NONE = 0
10329 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10331 ExpectInt32("names.length", 1006);
10332 ExpectTrue("names.indexOf(\"baz\") >= 0");
10333 ExpectTrue("names.indexOf(\"boo\") >= 0");
10334 ExpectTrue("names.indexOf(\"foo\") >= 0");
10335 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10336 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10337 ExpectFalse("names[1005] == undefined");
10341 // Getting property names of an object with a hidden and inherited
10342 // prototype should not duplicate the accessor properties inherited.
10343 THREADED_TEST(Regress269562) {
10344 i::FLAG_allow_natives_syntax = true;
10345 LocalContext context;
10346 v8::HandleScope handle_scope(context->GetIsolate());
10348 Local<v8::FunctionTemplate> t1 =
10349 v8::FunctionTemplate::New(context->GetIsolate());
10350 t1->SetHiddenPrototype(true);
10352 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10353 i1->SetAccessor(v8_str("foo"),
10354 SimpleAccessorGetter, SimpleAccessorSetter);
10355 i1->SetAccessor(v8_str("bar"),
10356 SimpleAccessorGetter, SimpleAccessorSetter);
10357 i1->SetAccessor(v8_str("baz"),
10358 SimpleAccessorGetter, SimpleAccessorSetter);
10359 i1->Set(v8_str("n1"), v8_num(1));
10360 i1->Set(v8_str("n2"), v8_num(2));
10362 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10363 Local<v8::FunctionTemplate> t2 =
10364 v8::FunctionTemplate::New(context->GetIsolate());
10365 t2->SetHiddenPrototype(true);
10367 // Inherit from t1 and mark prototype as hidden.
10369 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10371 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10372 CHECK(o2->SetPrototype(o1));
10374 v8::Local<v8::Symbol> sym =
10375 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10376 o1->Set(sym, v8_num(3));
10377 o1->SetHiddenValue(
10378 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10380 // Call the runtime version of GetOwnPropertyNames() on
10381 // the natively created object through JavaScript.
10382 context->Global()->Set(v8_str("obj"), o2);
10383 context->Global()->Set(v8_str("sym"), sym);
10384 // PROPERTY_ATTRIBUTES_NONE = 0
10385 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10387 ExpectInt32("names.length", 7);
10388 ExpectTrue("names.indexOf(\"foo\") >= 0");
10389 ExpectTrue("names.indexOf(\"bar\") >= 0");
10390 ExpectTrue("names.indexOf(\"baz\") >= 0");
10391 ExpectTrue("names.indexOf(\"n1\") >= 0");
10392 ExpectTrue("names.indexOf(\"n2\") >= 0");
10393 ExpectTrue("names.indexOf(sym) >= 0");
10394 ExpectTrue("names.indexOf(\"mine\") >= 0");
10398 THREADED_TEST(FunctionReadOnlyPrototype) {
10399 LocalContext context;
10400 v8::Isolate* isolate = context->GetIsolate();
10401 v8::HandleScope handle_scope(isolate);
10403 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10404 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10405 t1->ReadOnlyPrototype();
10406 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10407 // Configured value of ReadOnly flag.
10410 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10411 " return (descriptor['writable'] == false);"
10412 "})()")->BooleanValue());
10413 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10415 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10417 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10418 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10419 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10420 // Default value of ReadOnly flag.
10423 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10424 " return (descriptor['writable'] == true);"
10425 "})()")->BooleanValue());
10426 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10430 THREADED_TEST(SetPrototypeThrows) {
10431 LocalContext context;
10432 v8::Isolate* isolate = context->GetIsolate();
10433 v8::HandleScope handle_scope(isolate);
10435 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10437 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10438 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10440 CHECK(o0->SetPrototype(o1));
10441 // If setting the prototype leads to the cycle, SetPrototype should
10442 // return false and keep VM in sane state.
10443 v8::TryCatch try_catch;
10444 CHECK(!o1->SetPrototype(o0));
10445 CHECK(!try_catch.HasCaught());
10446 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10448 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10452 THREADED_TEST(FunctionRemovePrototype) {
10453 LocalContext context;
10454 v8::Isolate* isolate = context->GetIsolate();
10455 v8::HandleScope handle_scope(isolate);
10457 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10458 t1->RemovePrototype();
10459 Local<v8::Function> fun = t1->GetFunction();
10460 context->Global()->Set(v8_str("fun"), fun);
10461 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10463 v8::TryCatch try_catch;
10464 CompileRun("new fun()");
10465 CHECK(try_catch.HasCaught());
10468 fun->NewInstance();
10469 CHECK(try_catch.HasCaught());
10473 THREADED_TEST(GetterSetterExceptions) {
10474 LocalContext context;
10475 v8::Isolate* isolate = context->GetIsolate();
10476 v8::HandleScope handle_scope(isolate);
10478 "function Foo() { };"
10479 "function Throw() { throw 5; };"
10481 "x.__defineSetter__('set', Throw);"
10482 "x.__defineGetter__('get', Throw);");
10483 Local<v8::Object> x =
10484 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10485 v8::TryCatch try_catch;
10486 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10487 x->Get(v8_str("get"));
10488 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10489 x->Get(v8_str("get"));
10490 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10491 x->Get(v8_str("get"));
10492 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10493 x->Get(v8_str("get"));
10497 THREADED_TEST(Constructor) {
10498 LocalContext context;
10499 v8::Isolate* isolate = context->GetIsolate();
10500 v8::HandleScope handle_scope(isolate);
10501 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10502 templ->SetClassName(v8_str("Fun"));
10503 Local<Function> cons = templ->GetFunction();
10504 context->Global()->Set(v8_str("Fun"), cons);
10505 Local<v8::Object> inst = cons->NewInstance();
10506 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10507 CHECK(obj->IsJSObject());
10508 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10509 CHECK(value->BooleanValue());
10513 static void ConstructorCallback(
10514 const v8::FunctionCallbackInfo<v8::Value>& args) {
10515 ApiTestFuzzer::Fuzz();
10516 Local<Object> This;
10518 if (args.IsConstructCall()) {
10519 Local<Object> Holder = args.Holder();
10520 This = Object::New(args.GetIsolate());
10521 Local<Value> proto = Holder->GetPrototype();
10522 if (proto->IsObject()) {
10523 This->SetPrototype(proto);
10526 This = args.This();
10529 This->Set(v8_str("a"), args[0]);
10530 args.GetReturnValue().Set(This);
10534 static void FakeConstructorCallback(
10535 const v8::FunctionCallbackInfo<v8::Value>& args) {
10536 ApiTestFuzzer::Fuzz();
10537 args.GetReturnValue().Set(args[0]);
10541 THREADED_TEST(ConstructorForObject) {
10542 LocalContext context;
10543 v8::Isolate* isolate = context->GetIsolate();
10544 v8::HandleScope handle_scope(isolate);
10546 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10547 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10548 Local<Object> instance = instance_template->NewInstance();
10549 context->Global()->Set(v8_str("obj"), instance);
10550 v8::TryCatch try_catch;
10551 Local<Value> value;
10552 CHECK(!try_catch.HasCaught());
10554 // Call the Object's constructor with a 32-bit signed integer.
10555 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10556 CHECK(!try_catch.HasCaught());
10557 CHECK(value->IsInt32());
10558 CHECK_EQ(28, value->Int32Value());
10560 Local<Value> args1[] = { v8_num(28) };
10561 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10562 CHECK(value_obj1->IsObject());
10563 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10564 value = object1->Get(v8_str("a"));
10565 CHECK(value->IsInt32());
10566 CHECK(!try_catch.HasCaught());
10567 CHECK_EQ(28, value->Int32Value());
10569 // Call the Object's constructor with a String.
10570 value = CompileRun(
10571 "(function() { var o = new obj('tipli'); return o.a; })()");
10572 CHECK(!try_catch.HasCaught());
10573 CHECK(value->IsString());
10574 String::Utf8Value string_value1(value->ToString());
10575 CHECK_EQ("tipli", *string_value1);
10577 Local<Value> args2[] = { v8_str("tipli") };
10578 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10579 CHECK(value_obj2->IsObject());
10580 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10581 value = object2->Get(v8_str("a"));
10582 CHECK(!try_catch.HasCaught());
10583 CHECK(value->IsString());
10584 String::Utf8Value string_value2(value->ToString());
10585 CHECK_EQ("tipli", *string_value2);
10587 // Call the Object's constructor with a Boolean.
10588 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10589 CHECK(!try_catch.HasCaught());
10590 CHECK(value->IsBoolean());
10591 CHECK_EQ(true, value->BooleanValue());
10593 Handle<Value> args3[] = { v8::True(isolate) };
10594 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10595 CHECK(value_obj3->IsObject());
10596 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10597 value = object3->Get(v8_str("a"));
10598 CHECK(!try_catch.HasCaught());
10599 CHECK(value->IsBoolean());
10600 CHECK_EQ(true, value->BooleanValue());
10602 // Call the Object's constructor with undefined.
10603 Handle<Value> args4[] = { v8::Undefined(isolate) };
10604 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10605 CHECK(value_obj4->IsObject());
10606 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10607 value = object4->Get(v8_str("a"));
10608 CHECK(!try_catch.HasCaught());
10609 CHECK(value->IsUndefined());
10611 // Call the Object's constructor with null.
10612 Handle<Value> args5[] = { v8::Null(isolate) };
10613 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10614 CHECK(value_obj5->IsObject());
10615 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10616 value = object5->Get(v8_str("a"));
10617 CHECK(!try_catch.HasCaught());
10618 CHECK(value->IsNull());
10621 // Check exception handling when there is no constructor set for the Object.
10622 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10623 Local<Object> instance = instance_template->NewInstance();
10624 context->Global()->Set(v8_str("obj2"), instance);
10625 v8::TryCatch try_catch;
10626 Local<Value> value;
10627 CHECK(!try_catch.HasCaught());
10629 value = CompileRun("new obj2(28)");
10630 CHECK(try_catch.HasCaught());
10631 String::Utf8Value exception_value1(try_catch.Exception());
10632 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10635 Local<Value> args[] = { v8_num(29) };
10636 value = instance->CallAsConstructor(1, args);
10637 CHECK(try_catch.HasCaught());
10638 String::Utf8Value exception_value2(try_catch.Exception());
10639 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10643 // Check the case when constructor throws exception.
10644 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10645 instance_template->SetCallAsFunctionHandler(ThrowValue);
10646 Local<Object> instance = instance_template->NewInstance();
10647 context->Global()->Set(v8_str("obj3"), instance);
10648 v8::TryCatch try_catch;
10649 Local<Value> value;
10650 CHECK(!try_catch.HasCaught());
10652 value = CompileRun("new obj3(22)");
10653 CHECK(try_catch.HasCaught());
10654 String::Utf8Value exception_value1(try_catch.Exception());
10655 CHECK_EQ("22", *exception_value1);
10658 Local<Value> args[] = { v8_num(23) };
10659 value = instance->CallAsConstructor(1, args);
10660 CHECK(try_catch.HasCaught());
10661 String::Utf8Value exception_value2(try_catch.Exception());
10662 CHECK_EQ("23", *exception_value2);
10666 // Check whether constructor returns with an object or non-object.
10667 { Local<FunctionTemplate> function_template =
10668 FunctionTemplate::New(isolate, FakeConstructorCallback);
10669 Local<Function> function = function_template->GetFunction();
10670 Local<Object> instance1 = function;
10671 context->Global()->Set(v8_str("obj4"), instance1);
10672 v8::TryCatch try_catch;
10673 Local<Value> value;
10674 CHECK(!try_catch.HasCaught());
10676 CHECK(instance1->IsObject());
10677 CHECK(instance1->IsFunction());
10679 value = CompileRun("new obj4(28)");
10680 CHECK(!try_catch.HasCaught());
10681 CHECK(value->IsObject());
10683 Local<Value> args1[] = { v8_num(28) };
10684 value = instance1->CallAsConstructor(1, args1);
10685 CHECK(!try_catch.HasCaught());
10686 CHECK(value->IsObject());
10688 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10689 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10690 Local<Object> instance2 = instance_template->NewInstance();
10691 context->Global()->Set(v8_str("obj5"), instance2);
10692 CHECK(!try_catch.HasCaught());
10694 CHECK(instance2->IsObject());
10695 CHECK(!instance2->IsFunction());
10697 value = CompileRun("new obj5(28)");
10698 CHECK(!try_catch.HasCaught());
10699 CHECK(!value->IsObject());
10701 Local<Value> args2[] = { v8_num(28) };
10702 value = instance2->CallAsConstructor(1, args2);
10703 CHECK(!try_catch.HasCaught());
10704 CHECK(!value->IsObject());
10709 THREADED_TEST(FunctionDescriptorException) {
10710 LocalContext context;
10711 v8::Isolate* isolate = context->GetIsolate();
10712 v8::HandleScope handle_scope(isolate);
10713 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10714 templ->SetClassName(v8_str("Fun"));
10715 Local<Function> cons = templ->GetFunction();
10716 context->Global()->Set(v8_str("Fun"), cons);
10717 Local<Value> value = CompileRun(
10718 "function test() {"
10720 " (new Fun()).blah()"
10722 " var str = String(e);"
10723 // " if (str.indexOf('TypeError') == -1) return 1;"
10724 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10725 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10731 CHECK_EQ(0, value->Int32Value());
10735 THREADED_TEST(EvalAliasedDynamic) {
10736 LocalContext current;
10737 v8::HandleScope scope(current->GetIsolate());
10739 // Tests where aliased eval can only be resolved dynamically.
10740 Local<Script> script = v8_compile(
10743 " with (x) { return eval('foo'); }"
10746 "result1 = f(new Object());"
10747 "result2 = f(this);"
10748 "var x = new Object();"
10749 "x.eval = function(x) { return 1; };"
10750 "result3 = f(x);");
10752 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10753 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10754 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10756 v8::TryCatch try_catch;
10757 script = v8_compile(
10760 " with (x) { return eval('bar'); }"
10762 "result4 = f(this)");
10764 CHECK(!try_catch.HasCaught());
10765 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10771 THREADED_TEST(CrossEval) {
10772 v8::HandleScope scope(CcTest::isolate());
10773 LocalContext other;
10774 LocalContext current;
10776 Local<String> token = v8_str("<security token>");
10777 other->SetSecurityToken(token);
10778 current->SetSecurityToken(token);
10780 // Set up reference from current to other.
10781 current->Global()->Set(v8_str("other"), other->Global());
10783 // Check that new variables are introduced in other context.
10784 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10786 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10787 CHECK_EQ(1234, foo->Int32Value());
10788 CHECK(!current->Global()->Has(v8_str("foo")));
10790 // Check that writing to non-existing properties introduces them in
10791 // the other context.
10792 script = v8_compile("other.eval('na = 1234')");
10794 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10795 CHECK(!current->Global()->Has(v8_str("na")));
10797 // Check that global variables in current context are not visible in other
10799 v8::TryCatch try_catch;
10800 script = v8_compile("var bar = 42; other.eval('bar');");
10801 Local<Value> result = script->Run();
10802 CHECK(try_catch.HasCaught());
10805 // Check that local variables in current context are not visible in other
10807 script = v8_compile(
10810 " return other.eval('baz');"
10812 result = script->Run();
10813 CHECK(try_catch.HasCaught());
10816 // Check that global variables in the other environment are visible
10817 // when evaluting code.
10818 other->Global()->Set(v8_str("bis"), v8_num(1234));
10819 script = v8_compile("other.eval('bis')");
10820 CHECK_EQ(1234, script->Run()->Int32Value());
10821 CHECK(!try_catch.HasCaught());
10823 // Check that the 'this' pointer points to the global object evaluating
10825 other->Global()->Set(v8_str("t"), other->Global());
10826 script = v8_compile("other.eval('this == t')");
10827 result = script->Run();
10828 CHECK(result->IsTrue());
10829 CHECK(!try_catch.HasCaught());
10831 // Check that variables introduced in with-statement are not visible in
10833 script = v8_compile("with({x:2}){other.eval('x')}");
10834 result = script->Run();
10835 CHECK(try_catch.HasCaught());
10838 // Check that you cannot use 'eval.call' with another object than the
10839 // current global object.
10840 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10841 result = script->Run();
10842 CHECK(try_catch.HasCaught());
10846 // Test that calling eval in a context which has been detached from
10847 // its global throws an exception. This behavior is consistent with
10848 // other JavaScript implementations.
10849 THREADED_TEST(EvalInDetachedGlobal) {
10850 v8::Isolate* isolate = CcTest::isolate();
10851 v8::HandleScope scope(isolate);
10853 v8::Local<Context> context0 = Context::New(isolate);
10854 v8::Local<Context> context1 = Context::New(isolate);
10856 // Set up function in context0 that uses eval from context0.
10858 v8::Handle<v8::Value> fun =
10859 CompileRun("var x = 42;"
10862 " return function(s) { return e(s); }"
10866 // Put the function into context1 and call it before and after
10867 // detaching the global. Before detaching, the call succeeds and
10868 // after detaching and exception is thrown.
10870 context1->Global()->Set(v8_str("fun"), fun);
10871 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10872 CHECK_EQ(42, x_value->Int32Value());
10873 context0->DetachGlobal();
10874 v8::TryCatch catcher;
10875 x_value = CompileRun("fun('x')");
10876 CHECK(x_value.IsEmpty());
10877 CHECK(catcher.HasCaught());
10882 THREADED_TEST(CrossLazyLoad) {
10883 v8::HandleScope scope(CcTest::isolate());
10884 LocalContext other;
10885 LocalContext current;
10887 Local<String> token = v8_str("<security token>");
10888 other->SetSecurityToken(token);
10889 current->SetSecurityToken(token);
10891 // Set up reference from current to other.
10892 current->Global()->Set(v8_str("other"), other->Global());
10894 // Trigger lazy loading in other context.
10895 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10896 Local<Value> value = script->Run();
10897 CHECK_EQ(42.0, value->NumberValue());
10901 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10902 ApiTestFuzzer::Fuzz();
10903 if (args.IsConstructCall()) {
10904 if (args[0]->IsInt32()) {
10905 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10910 args.GetReturnValue().Set(args[0]);
10914 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10915 args.GetReturnValue().Set(args.This());
10919 // Test that a call handler can be set for objects which will allow
10920 // non-function objects created through the API to be called as
10922 THREADED_TEST(CallAsFunction) {
10923 LocalContext context;
10924 v8::Isolate* isolate = context->GetIsolate();
10925 v8::HandleScope scope(isolate);
10927 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10928 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10929 instance_template->SetCallAsFunctionHandler(call_as_function);
10930 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10931 context->Global()->Set(v8_str("obj"), instance);
10932 v8::TryCatch try_catch;
10933 Local<Value> value;
10934 CHECK(!try_catch.HasCaught());
10936 value = CompileRun("obj(42)");
10937 CHECK(!try_catch.HasCaught());
10938 CHECK_EQ(42, value->Int32Value());
10940 value = CompileRun("(function(o){return o(49)})(obj)");
10941 CHECK(!try_catch.HasCaught());
10942 CHECK_EQ(49, value->Int32Value());
10944 // test special case of call as function
10945 value = CompileRun("[obj]['0'](45)");
10946 CHECK(!try_catch.HasCaught());
10947 CHECK_EQ(45, value->Int32Value());
10949 value = CompileRun("obj.call = Function.prototype.call;"
10950 "obj.call(null, 87)");
10951 CHECK(!try_catch.HasCaught());
10952 CHECK_EQ(87, value->Int32Value());
10954 // Regression tests for bug #1116356: Calling call through call/apply
10955 // must work for non-function receivers.
10956 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10957 value = CompileRun(apply_99);
10958 CHECK(!try_catch.HasCaught());
10959 CHECK_EQ(99, value->Int32Value());
10961 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10962 value = CompileRun(call_17);
10963 CHECK(!try_catch.HasCaught());
10964 CHECK_EQ(17, value->Int32Value());
10966 // Check that the call-as-function handler can be called through
10968 value = CompileRun("new obj(43)");
10969 CHECK(!try_catch.HasCaught());
10970 CHECK_EQ(-43, value->Int32Value());
10972 // Check that the call-as-function handler can be called through
10974 v8::Handle<Value> args[] = { v8_num(28) };
10975 value = instance->CallAsFunction(instance, 1, args);
10976 CHECK(!try_catch.HasCaught());
10977 CHECK_EQ(28, value->Int32Value());
10980 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10981 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10982 USE(instance_template);
10983 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10984 context->Global()->Set(v8_str("obj2"), instance);
10985 v8::TryCatch try_catch;
10986 Local<Value> value;
10987 CHECK(!try_catch.HasCaught());
10989 // Call an object without call-as-function handler through the JS
10990 value = CompileRun("obj2(28)");
10991 CHECK(value.IsEmpty());
10992 CHECK(try_catch.HasCaught());
10993 String::Utf8Value exception_value1(try_catch.Exception());
10994 // TODO(verwaest): Better message
10995 CHECK_EQ("TypeError: object is not a function",
10996 *exception_value1);
10999 // Call an object without call-as-function handler through the API
11000 value = CompileRun("obj2(28)");
11001 v8::Handle<Value> args[] = { v8_num(28) };
11002 value = instance->CallAsFunction(instance, 1, args);
11003 CHECK(value.IsEmpty());
11004 CHECK(try_catch.HasCaught());
11005 String::Utf8Value exception_value2(try_catch.Exception());
11006 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11010 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11011 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11012 instance_template->SetCallAsFunctionHandler(ThrowValue);
11013 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11014 context->Global()->Set(v8_str("obj3"), instance);
11015 v8::TryCatch try_catch;
11016 Local<Value> value;
11017 CHECK(!try_catch.HasCaught());
11019 // Catch the exception which is thrown by call-as-function handler
11020 value = CompileRun("obj3(22)");
11021 CHECK(try_catch.HasCaught());
11022 String::Utf8Value exception_value1(try_catch.Exception());
11023 CHECK_EQ("22", *exception_value1);
11026 v8::Handle<Value> args[] = { v8_num(23) };
11027 value = instance->CallAsFunction(instance, 1, args);
11028 CHECK(try_catch.HasCaught());
11029 String::Utf8Value exception_value2(try_catch.Exception());
11030 CHECK_EQ("23", *exception_value2);
11034 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11035 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11036 instance_template->SetCallAsFunctionHandler(ReturnThis);
11037 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11039 Local<v8::Value> a1 =
11040 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11041 CHECK(a1->StrictEquals(instance));
11042 Local<v8::Value> a2 =
11043 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11044 CHECK(a2->StrictEquals(instance));
11045 Local<v8::Value> a3 =
11046 instance->CallAsFunction(v8_num(42), 0, NULL);
11047 CHECK(a3->StrictEquals(instance));
11048 Local<v8::Value> a4 =
11049 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11050 CHECK(a4->StrictEquals(instance));
11051 Local<v8::Value> a5 =
11052 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11053 CHECK(a5->StrictEquals(instance));
11057 "function ReturnThisSloppy() {"
11060 "function ReturnThisStrict() {"
11064 Local<Function> ReturnThisSloppy =
11065 Local<Function>::Cast(
11066 context->Global()->Get(v8_str("ReturnThisSloppy")));
11067 Local<Function> ReturnThisStrict =
11068 Local<Function>::Cast(
11069 context->Global()->Get(v8_str("ReturnThisStrict")));
11071 Local<v8::Value> a1 =
11072 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11073 CHECK(a1->StrictEquals(context->Global()));
11074 Local<v8::Value> a2 =
11075 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11076 CHECK(a2->StrictEquals(context->Global()));
11077 Local<v8::Value> a3 =
11078 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11079 CHECK(a3->IsNumberObject());
11080 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11081 Local<v8::Value> a4 =
11082 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11083 CHECK(a4->IsStringObject());
11084 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11085 Local<v8::Value> a5 =
11086 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11087 CHECK(a5->IsBooleanObject());
11088 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11090 Local<v8::Value> a6 =
11091 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11092 CHECK(a6->IsUndefined());
11093 Local<v8::Value> a7 =
11094 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11095 CHECK(a7->IsNull());
11096 Local<v8::Value> a8 =
11097 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11098 CHECK(a8->StrictEquals(v8_num(42)));
11099 Local<v8::Value> a9 =
11100 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11101 CHECK(a9->StrictEquals(v8_str("hello")));
11102 Local<v8::Value> a10 =
11103 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11104 CHECK(a10->StrictEquals(v8::True(isolate)));
11109 // Check whether a non-function object is callable.
11110 THREADED_TEST(CallableObject) {
11111 LocalContext context;
11112 v8::Isolate* isolate = context->GetIsolate();
11113 v8::HandleScope scope(isolate);
11115 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11116 instance_template->SetCallAsFunctionHandler(call_as_function);
11117 Local<Object> instance = instance_template->NewInstance();
11118 v8::TryCatch try_catch;
11120 CHECK(instance->IsCallable());
11121 CHECK(!try_catch.HasCaught());
11124 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11125 Local<Object> instance = instance_template->NewInstance();
11126 v8::TryCatch try_catch;
11128 CHECK(!instance->IsCallable());
11129 CHECK(!try_catch.HasCaught());
11132 { Local<FunctionTemplate> function_template =
11133 FunctionTemplate::New(isolate, call_as_function);
11134 Local<Function> function = function_template->GetFunction();
11135 Local<Object> instance = function;
11136 v8::TryCatch try_catch;
11138 CHECK(instance->IsCallable());
11139 CHECK(!try_catch.HasCaught());
11142 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11143 Local<Function> function = function_template->GetFunction();
11144 Local<Object> instance = function;
11145 v8::TryCatch try_catch;
11147 CHECK(instance->IsCallable());
11148 CHECK(!try_catch.HasCaught());
11153 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11154 v8::HandleScope scope(isolate);
11155 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11156 for (int i = 0; i < iterations; i++) {
11157 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11159 return Recurse(isolate, depth - 1, iterations);
11163 THREADED_TEST(HandleIteration) {
11164 static const int kIterations = 500;
11165 static const int kNesting = 200;
11166 LocalContext context;
11167 v8::Isolate* isolate = context->GetIsolate();
11168 v8::HandleScope scope0(isolate);
11169 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11171 v8::HandleScope scope1(isolate);
11172 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11173 for (int i = 0; i < kIterations; i++) {
11174 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11175 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11178 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11180 v8::HandleScope scope2(CcTest::isolate());
11181 for (int j = 0; j < kIterations; j++) {
11182 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11183 CHECK_EQ(j + 1 + kIterations,
11184 v8::HandleScope::NumberOfHandles(isolate));
11187 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11189 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11190 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11194 static void InterceptorHasOwnPropertyGetter(
11195 Local<String> name,
11196 const v8::PropertyCallbackInfo<v8::Value>& info) {
11197 ApiTestFuzzer::Fuzz();
11201 THREADED_TEST(InterceptorHasOwnProperty) {
11202 LocalContext context;
11203 v8::Isolate* isolate = context->GetIsolate();
11204 v8::HandleScope scope(isolate);
11205 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11206 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11207 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11208 Local<Function> function = fun_templ->GetFunction();
11209 context->Global()->Set(v8_str("constructor"), function);
11210 v8::Handle<Value> value = CompileRun(
11211 "var o = new constructor();"
11212 "o.hasOwnProperty('ostehaps');");
11213 CHECK_EQ(false, value->BooleanValue());
11214 value = CompileRun(
11216 "o.hasOwnProperty('ostehaps');");
11217 CHECK_EQ(true, value->BooleanValue());
11218 value = CompileRun(
11219 "var p = new constructor();"
11220 "p.hasOwnProperty('ostehaps');");
11221 CHECK_EQ(false, value->BooleanValue());
11225 static void InterceptorHasOwnPropertyGetterGC(
11226 Local<String> name,
11227 const v8::PropertyCallbackInfo<v8::Value>& info) {
11228 ApiTestFuzzer::Fuzz();
11229 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11233 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11234 LocalContext context;
11235 v8::Isolate* isolate = context->GetIsolate();
11236 v8::HandleScope scope(isolate);
11237 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11238 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11239 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11240 Local<Function> function = fun_templ->GetFunction();
11241 context->Global()->Set(v8_str("constructor"), function);
11242 // Let's first make some stuff so we can be sure to get a good GC.
11244 "function makestr(size) {"
11246 " case 1: return 'f';"
11247 " case 2: return 'fo';"
11248 " case 3: return 'foo';"
11250 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11252 "var x = makestr(12345);"
11253 "x = makestr(31415);"
11254 "x = makestr(23456);");
11255 v8::Handle<Value> value = CompileRun(
11256 "var o = new constructor();"
11257 "o.__proto__ = new String(x);"
11258 "o.hasOwnProperty('ostehaps');");
11259 CHECK_EQ(false, value->BooleanValue());
11263 typedef void (*NamedPropertyGetter)(
11264 Local<String> property,
11265 const v8::PropertyCallbackInfo<v8::Value>& info);
11268 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11269 const char* source,
11271 v8::Isolate* isolate = CcTest::isolate();
11272 v8::HandleScope scope(isolate);
11273 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11274 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11275 LocalContext context;
11276 context->Global()->Set(v8_str("o"), templ->NewInstance());
11277 v8::Handle<Value> value = CompileRun(source);
11278 CHECK_EQ(expected, value->Int32Value());
11282 static void InterceptorLoadICGetter(
11283 Local<String> name,
11284 const v8::PropertyCallbackInfo<v8::Value>& info) {
11285 ApiTestFuzzer::Fuzz();
11286 v8::Isolate* isolate = CcTest::isolate();
11287 CHECK_EQ(isolate, info.GetIsolate());
11288 CHECK_EQ(v8_str("data"), info.Data());
11289 CHECK_EQ(v8_str("x"), name);
11290 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11294 // This test should hit the load IC for the interceptor case.
11295 THREADED_TEST(InterceptorLoadIC) {
11296 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11298 "for (var i = 0; i < 1000; i++) {"
11305 // Below go several tests which verify that JITing for various
11306 // configurations of interceptor and explicit fields works fine
11307 // (those cases are special cased to get better performance).
11309 static void InterceptorLoadXICGetter(
11310 Local<String> name,
11311 const v8::PropertyCallbackInfo<v8::Value>& info) {
11312 ApiTestFuzzer::Fuzz();
11313 info.GetReturnValue().Set(
11314 v8_str("x")->Equals(name) ?
11315 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11316 v8::Handle<v8::Value>());
11320 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11321 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11324 "for (var i = 0; i < 1000; i++) {"
11331 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11332 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11334 "o.__proto__ = { 'y': 239 };"
11335 "for (var i = 0; i < 1000; i++) {"
11336 " result = o.y + o.x;"
11342 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11343 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11345 "o.__proto__.y = 239;"
11346 "for (var i = 0; i < 1000; i++) {"
11347 " result = o.y + o.x;"
11353 THREADED_TEST(InterceptorLoadICUndefined) {
11354 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11356 "for (var i = 0; i < 1000; i++) {"
11357 " result = (o.y == undefined) ? 239 : 42;"
11363 THREADED_TEST(InterceptorLoadICWithOverride) {
11364 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11365 "fst = new Object(); fst.__proto__ = o;"
11366 "snd = new Object(); snd.__proto__ = fst;"
11368 "for (var i = 0; i < 1000; i++) {"
11369 " result1 = snd.x;"
11373 "for (var i = 0; i < 1000; i++) {"
11376 "result + result1",
11381 // Test the case when we stored field into
11382 // a stub, but interceptor produced value on its own.
11383 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11384 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11385 "proto = new Object();"
11386 "o.__proto__ = proto;"
11388 "for (var i = 0; i < 1000; i++) {"
11390 // Now it should be ICed and keep a reference to x defined on proto
11393 "for (var i = 0; i < 1000; i++) {"
11401 // Test the case when we stored field into
11402 // a stub, but it got invalidated later on.
11403 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11404 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11405 "proto1 = new Object();"
11406 "proto2 = new Object();"
11407 "o.__proto__ = proto1;"
11408 "proto1.__proto__ = proto2;"
11410 "for (var i = 0; i < 1000; i++) {"
11412 // Now it should be ICed and keep a reference to y defined on proto2
11416 "for (var i = 0; i < 1000; i++) {"
11424 static int interceptor_load_not_handled_calls = 0;
11425 static void InterceptorLoadNotHandled(
11426 Local<String> name,
11427 const v8::PropertyCallbackInfo<v8::Value>& info) {
11428 ++interceptor_load_not_handled_calls;
11432 // Test how post-interceptor lookups are done in the non-cacheable
11433 // case: the interceptor should not be invoked during this lookup.
11434 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11435 interceptor_load_not_handled_calls = 0;
11436 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11437 "receiver = new Object();"
11438 "receiver.__proto__ = o;"
11439 "proto = new Object();"
11440 "/* Make proto a slow-case object. */"
11441 "for (var i = 0; i < 1000; i++) {"
11442 " proto[\"xxxxxxxx\" + i] = [];"
11445 "o.__proto__ = proto;"
11447 "for (var i = 0; i < 1000; i++) {"
11448 " result += receiver.x;"
11452 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11456 // Test the case when we stored field into
11457 // a stub, but it got invalidated later on due to override on
11458 // global object which is between interceptor and fields' holders.
11459 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11460 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11461 "o.__proto__ = this;" // set a global to be a proto of o.
11462 "this.__proto__.y = 239;"
11463 "for (var i = 0; i < 10; i++) {"
11464 " if (o.y != 239) throw 'oops: ' + o.y;"
11465 // Now it should be ICed and keep a reference to y defined on field_holder.
11467 "this.y = 42;" // Assign on a global.
11469 "for (var i = 0; i < 10; i++) {"
11477 static void SetOnThis(Local<String> name,
11478 Local<Value> value,
11479 const v8::PropertyCallbackInfo<void>& info) {
11480 Local<Object>::Cast(info.This())->ForceSet(name, value);
11484 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11485 v8::Isolate* isolate = CcTest::isolate();
11486 v8::HandleScope scope(isolate);
11487 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11488 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11489 templ->SetAccessor(v8_str("y"), Return239Callback);
11490 LocalContext context;
11491 context->Global()->Set(v8_str("o"), templ->NewInstance());
11493 // Check the case when receiver and interceptor's holder
11494 // are the same objects.
11495 v8::Handle<Value> value = CompileRun(
11497 "for (var i = 0; i < 7; i++) {"
11500 CHECK_EQ(239, value->Int32Value());
11502 // Check the case when interceptor's holder is in proto chain
11504 value = CompileRun(
11505 "r = { __proto__: o };"
11507 "for (var i = 0; i < 7; i++) {"
11510 CHECK_EQ(239, value->Int32Value());
11514 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11515 v8::Isolate* isolate = CcTest::isolate();
11516 v8::HandleScope scope(isolate);
11517 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11518 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11519 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11520 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11522 LocalContext context;
11523 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11524 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11526 // Check the case when receiver and interceptor's holder
11527 // are the same objects.
11528 v8::Handle<Value> value = CompileRun(
11531 "for (var i = 0; i < 7; i++) {"
11532 " result = o.x + o.y;"
11534 CHECK_EQ(239 + 42, value->Int32Value());
11536 // Check the case when interceptor's holder is in proto chain
11538 value = CompileRun(
11539 "r = { __proto__: o };"
11541 "for (var i = 0; i < 7; i++) {"
11542 " result = r.x + r.y;"
11544 CHECK_EQ(239 + 42, value->Int32Value());
11548 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11549 v8::Isolate* isolate = CcTest::isolate();
11550 v8::HandleScope scope(isolate);
11551 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11552 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11553 templ->SetAccessor(v8_str("y"), Return239Callback);
11555 LocalContext context;
11556 context->Global()->Set(v8_str("o"), templ->NewInstance());
11558 v8::Handle<Value> value = CompileRun(
11559 "fst = new Object(); fst.__proto__ = o;"
11560 "snd = new Object(); snd.__proto__ = fst;"
11562 "for (var i = 0; i < 7; i++) {"
11563 " result1 = snd.x;"
11567 "for (var i = 0; i < 7; i++) {"
11570 "result + result1");
11571 CHECK_EQ(239 + 42, value->Int32Value());
11575 // Test the case when we stored callback into
11576 // a stub, but interceptor produced value on its own.
11577 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11578 v8::Isolate* isolate = CcTest::isolate();
11579 v8::HandleScope scope(isolate);
11580 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11581 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11582 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11583 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11585 LocalContext context;
11586 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11587 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11589 v8::Handle<Value> value = CompileRun(
11591 "for (var i = 0; i < 7; i++) {"
11593 // Now it should be ICed and keep a reference to x defined on p
11596 "for (var i = 0; i < 7; i++) {"
11600 CHECK_EQ(42 * 7, value->Int32Value());
11604 // Test the case when we stored callback into
11605 // a stub, but it got invalidated later on.
11606 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11607 v8::Isolate* isolate = CcTest::isolate();
11608 v8::HandleScope scope(isolate);
11609 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11610 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11611 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11612 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11614 LocalContext context;
11615 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11616 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11618 v8::Handle<Value> value = CompileRun(
11619 "inbetween = new Object();"
11620 "o.__proto__ = inbetween;"
11621 "inbetween.__proto__ = p;"
11622 "for (var i = 0; i < 10; i++) {"
11624 // Now it should be ICed and keep a reference to y defined on p
11626 "inbetween.y = 42;"
11628 "for (var i = 0; i < 10; i++) {"
11632 CHECK_EQ(42 * 10, value->Int32Value());
11636 // Test the case when we stored callback into
11637 // a stub, but it got invalidated later on due to override on
11638 // global object which is between interceptor and callbacks' holders.
11639 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11640 v8::Isolate* isolate = CcTest::isolate();
11641 v8::HandleScope scope(isolate);
11642 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11643 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11644 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11645 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11647 LocalContext context;
11648 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11649 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11651 v8::Handle<Value> value = CompileRun(
11652 "o.__proto__ = this;"
11653 "this.__proto__ = p;"
11654 "for (var i = 0; i < 10; i++) {"
11655 " if (o.y != 239) throw 'oops: ' + o.y;"
11656 // Now it should be ICed and keep a reference to y defined on p
11660 "for (var i = 0; i < 10; i++) {"
11664 CHECK_EQ(42 * 10, value->Int32Value());
11668 static void InterceptorLoadICGetter0(
11669 Local<String> name,
11670 const v8::PropertyCallbackInfo<v8::Value>& info) {
11671 ApiTestFuzzer::Fuzz();
11672 CHECK(v8_str("x")->Equals(name));
11673 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11677 THREADED_TEST(InterceptorReturningZero) {
11678 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11679 "o.x == undefined ? 1 : 0",
11684 static void InterceptorStoreICSetter(
11686 Local<Value> value,
11687 const v8::PropertyCallbackInfo<v8::Value>& info) {
11688 CHECK(v8_str("x")->Equals(key));
11689 CHECK_EQ(42, value->Int32Value());
11690 info.GetReturnValue().Set(value);
11694 // This test should hit the store IC for the interceptor case.
11695 THREADED_TEST(InterceptorStoreIC) {
11696 v8::Isolate* isolate = CcTest::isolate();
11697 v8::HandleScope scope(isolate);
11698 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11699 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11700 InterceptorStoreICSetter,
11701 0, 0, 0, v8_str("data"));
11702 LocalContext context;
11703 context->Global()->Set(v8_str("o"), templ->NewInstance());
11705 "for (var i = 0; i < 1000; i++) {"
11711 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11712 v8::Isolate* isolate = CcTest::isolate();
11713 v8::HandleScope scope(isolate);
11714 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11715 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11716 LocalContext context;
11717 context->Global()->Set(v8_str("o"), templ->NewInstance());
11718 v8::Handle<Value> value = CompileRun(
11719 "for (var i = 0; i < 1000; i++) {"
11723 CHECK_EQ(239 + 42, value->Int32Value());
11729 v8::Handle<Value> call_ic_function;
11730 v8::Handle<Value> call_ic_function2;
11731 v8::Handle<Value> call_ic_function3;
11733 static void InterceptorCallICGetter(
11734 Local<String> name,
11735 const v8::PropertyCallbackInfo<v8::Value>& info) {
11736 ApiTestFuzzer::Fuzz();
11737 CHECK(v8_str("x")->Equals(name));
11738 info.GetReturnValue().Set(call_ic_function);
11742 // This test should hit the call IC for the interceptor case.
11743 THREADED_TEST(InterceptorCallIC) {
11744 v8::Isolate* isolate = CcTest::isolate();
11745 v8::HandleScope scope(isolate);
11746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11747 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11748 LocalContext context;
11749 context->Global()->Set(v8_str("o"), templ->NewInstance());
11751 v8_compile("function f(x) { return x + 1; }; f")->Run();
11752 v8::Handle<Value> value = CompileRun(
11754 "for (var i = 0; i < 1000; i++) {"
11755 " result = o.x(41);"
11757 CHECK_EQ(42, value->Int32Value());
11761 // This test checks that if interceptor doesn't provide
11762 // a value, we can fetch regular value.
11763 THREADED_TEST(InterceptorCallICSeesOthers) {
11764 v8::Isolate* isolate = CcTest::isolate();
11765 v8::HandleScope scope(isolate);
11766 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11767 templ->SetNamedPropertyHandler(NoBlockGetterX);
11768 LocalContext context;
11769 context->Global()->Set(v8_str("o"), templ->NewInstance());
11770 v8::Handle<Value> value = CompileRun(
11771 "o.x = function f(x) { return x + 1; };"
11773 "for (var i = 0; i < 7; i++) {"
11774 " result = o.x(41);"
11776 CHECK_EQ(42, value->Int32Value());
11780 static v8::Handle<Value> call_ic_function4;
11781 static void InterceptorCallICGetter4(
11782 Local<String> name,
11783 const v8::PropertyCallbackInfo<v8::Value>& info) {
11784 ApiTestFuzzer::Fuzz();
11785 CHECK(v8_str("x")->Equals(name));
11786 info.GetReturnValue().Set(call_ic_function4);
11790 // This test checks that if interceptor provides a function,
11791 // even if we cached shadowed variant, interceptor's function
11793 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11794 v8::Isolate* isolate = CcTest::isolate();
11795 v8::HandleScope scope(isolate);
11796 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11797 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11798 LocalContext context;
11799 context->Global()->Set(v8_str("o"), templ->NewInstance());
11800 call_ic_function4 =
11801 v8_compile("function f(x) { return x - 1; }; f")->Run();
11802 v8::Handle<Value> value = CompileRun(
11803 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11805 "for (var i = 0; i < 1000; i++) {"
11806 " result = o.x(42);"
11808 CHECK_EQ(41, value->Int32Value());
11812 // Test the case when we stored cacheable lookup into
11813 // a stub, but it got invalidated later on
11814 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11815 v8::Isolate* isolate = CcTest::isolate();
11816 v8::HandleScope scope(isolate);
11817 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11818 templ->SetNamedPropertyHandler(NoBlockGetterX);
11819 LocalContext context;
11820 context->Global()->Set(v8_str("o"), templ->NewInstance());
11821 v8::Handle<Value> value = CompileRun(
11822 "proto1 = new Object();"
11823 "proto2 = new Object();"
11824 "o.__proto__ = proto1;"
11825 "proto1.__proto__ = proto2;"
11826 "proto2.y = function(x) { return x + 1; };"
11827 // Invoke it many times to compile a stub
11828 "for (var i = 0; i < 7; i++) {"
11831 "proto1.y = function(x) { return x - 1; };"
11833 "for (var i = 0; i < 7; i++) {"
11834 " result += o.y(42);"
11836 CHECK_EQ(41 * 7, value->Int32Value());
11840 // This test checks that if interceptor doesn't provide a function,
11841 // cached constant function is used
11842 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11843 v8::Isolate* isolate = CcTest::isolate();
11844 v8::HandleScope scope(isolate);
11845 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11846 templ->SetNamedPropertyHandler(NoBlockGetterX);
11847 LocalContext context;
11848 context->Global()->Set(v8_str("o"), templ->NewInstance());
11849 v8::Handle<Value> value = CompileRun(
11850 "function inc(x) { return x + 1; };"
11854 "for (var i = 0; i < 1000; i++) {"
11855 " result = o.x(42);"
11857 CHECK_EQ(43, value->Int32Value());
11861 static v8::Handle<Value> call_ic_function5;
11862 static void InterceptorCallICGetter5(
11863 Local<String> name,
11864 const v8::PropertyCallbackInfo<v8::Value>& info) {
11865 ApiTestFuzzer::Fuzz();
11866 if (v8_str("x")->Equals(name))
11867 info.GetReturnValue().Set(call_ic_function5);
11871 // This test checks that if interceptor provides a function,
11872 // even if we cached constant function, interceptor's function
11874 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11875 v8::Isolate* isolate = CcTest::isolate();
11876 v8::HandleScope scope(isolate);
11877 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11878 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11879 LocalContext context;
11880 context->Global()->Set(v8_str("o"), templ->NewInstance());
11881 call_ic_function5 =
11882 v8_compile("function f(x) { return x - 1; }; f")->Run();
11883 v8::Handle<Value> value = CompileRun(
11884 "function inc(x) { return x + 1; };"
11888 "for (var i = 0; i < 1000; i++) {"
11889 " result = o.x(42);"
11891 CHECK_EQ(41, value->Int32Value());
11895 static v8::Handle<Value> call_ic_function6;
11896 static void InterceptorCallICGetter6(
11897 Local<String> name,
11898 const v8::PropertyCallbackInfo<v8::Value>& info) {
11899 ApiTestFuzzer::Fuzz();
11900 if (v8_str("x")->Equals(name))
11901 info.GetReturnValue().Set(call_ic_function6);
11905 // Same test as above, except the code is wrapped in a function
11906 // to test the optimized compiler.
11907 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11908 i::FLAG_allow_natives_syntax = true;
11909 v8::Isolate* isolate = CcTest::isolate();
11910 v8::HandleScope scope(isolate);
11911 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11912 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11913 LocalContext context;
11914 context->Global()->Set(v8_str("o"), templ->NewInstance());
11915 call_ic_function6 =
11916 v8_compile("function f(x) { return x - 1; }; f")->Run();
11917 v8::Handle<Value> value = CompileRun(
11918 "function inc(x) { return x + 1; };"
11921 "function test() {"
11923 " for (var i = 0; i < 1000; i++) {"
11924 " result = o.x(42);"
11931 "%OptimizeFunctionOnNextCall(test);"
11933 CHECK_EQ(41, value->Int32Value());
11937 // Test the case when we stored constant function into
11938 // a stub, but it got invalidated later on
11939 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11940 v8::Isolate* isolate = CcTest::isolate();
11941 v8::HandleScope scope(isolate);
11942 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11943 templ->SetNamedPropertyHandler(NoBlockGetterX);
11944 LocalContext context;
11945 context->Global()->Set(v8_str("o"), templ->NewInstance());
11946 v8::Handle<Value> value = CompileRun(
11947 "function inc(x) { return x + 1; };"
11949 "proto1 = new Object();"
11950 "proto2 = new Object();"
11951 "o.__proto__ = proto1;"
11952 "proto1.__proto__ = proto2;"
11954 // Invoke it many times to compile a stub
11955 "for (var i = 0; i < 7; i++) {"
11958 "proto1.y = function(x) { return x - 1; };"
11960 "for (var i = 0; i < 7; i++) {"
11961 " result += o.y(42);"
11963 CHECK_EQ(41 * 7, value->Int32Value());
11967 // Test the case when we stored constant function into
11968 // a stub, but it got invalidated later on due to override on
11969 // global object which is between interceptor and constant function' holders.
11970 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11971 v8::Isolate* isolate = CcTest::isolate();
11972 v8::HandleScope scope(isolate);
11973 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11974 templ->SetNamedPropertyHandler(NoBlockGetterX);
11975 LocalContext context;
11976 context->Global()->Set(v8_str("o"), templ->NewInstance());
11977 v8::Handle<Value> value = CompileRun(
11978 "function inc(x) { return x + 1; };"
11980 "o.__proto__ = this;"
11981 "this.__proto__.y = inc;"
11982 // Invoke it many times to compile a stub
11983 "for (var i = 0; i < 7; i++) {"
11984 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11986 "this.y = function(x) { return x - 1; };"
11988 "for (var i = 0; i < 7; i++) {"
11989 " result += o.y(42);"
11991 CHECK_EQ(41 * 7, value->Int32Value());
11995 // Test the case when actual function to call sits on global object.
11996 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11997 v8::Isolate* isolate = CcTest::isolate();
11998 v8::HandleScope scope(isolate);
11999 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12000 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12002 LocalContext context;
12003 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12005 v8::Handle<Value> value = CompileRun(
12007 " o.__proto__ = this;"
12008 " for (var i = 0; i < 10; i++) {"
12009 " var v = o.parseFloat('239');"
12010 " if (v != 239) throw v;"
12011 // Now it should be ICed and keep a reference to parseFloat.
12014 " for (var i = 0; i < 10; i++) {"
12015 " result += o.parseFloat('239');"
12021 CHECK_EQ(239 * 10, value->Int32Value());
12024 static void InterceptorCallICFastApi(
12025 Local<String> name,
12026 const v8::PropertyCallbackInfo<v8::Value>& info) {
12027 ApiTestFuzzer::Fuzz();
12028 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12030 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12032 if ((*call_count) % 20 == 0) {
12033 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12037 static void FastApiCallback_TrivialSignature(
12038 const v8::FunctionCallbackInfo<v8::Value>& args) {
12039 ApiTestFuzzer::Fuzz();
12040 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12041 v8::Isolate* isolate = CcTest::isolate();
12042 CHECK_EQ(isolate, args.GetIsolate());
12043 CHECK_EQ(args.This(), args.Holder());
12044 CHECK(args.Data()->Equals(v8_str("method_data")));
12045 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12048 static void FastApiCallback_SimpleSignature(
12049 const v8::FunctionCallbackInfo<v8::Value>& args) {
12050 ApiTestFuzzer::Fuzz();
12051 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12052 v8::Isolate* isolate = CcTest::isolate();
12053 CHECK_EQ(isolate, args.GetIsolate());
12054 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12055 CHECK(args.Data()->Equals(v8_str("method_data")));
12056 // Note, we're using HasRealNamedProperty instead of Has to avoid
12057 // invoking the interceptor again.
12058 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12059 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12063 // Helper to maximize the odds of object moving.
12064 static void GenerateSomeGarbage() {
12067 "for (var i = 0; i < 1000; i++) {"
12068 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12070 "garbage = undefined;");
12074 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12075 static int count = 0;
12076 if (count++ % 3 == 0) {
12077 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12078 // This should move the stub
12079 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12084 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12085 LocalContext context;
12086 v8::Isolate* isolate = context->GetIsolate();
12087 v8::HandleScope scope(isolate);
12088 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12089 v8::ObjectTemplate::New(isolate);
12090 nativeobject_templ->Set(isolate, "callback",
12091 v8::FunctionTemplate::New(isolate,
12092 DirectApiCallback));
12093 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12094 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12095 // call the api function multiple times to ensure direct call stub creation.
12098 " for (var i = 1; i <= 30; i++) {"
12099 " nativeobject.callback();"
12106 void ThrowingDirectApiCallback(
12107 const v8::FunctionCallbackInfo<v8::Value>& args) {
12108 args.GetIsolate()->ThrowException(v8_str("g"));
12112 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12113 LocalContext context;
12114 v8::Isolate* isolate = context->GetIsolate();
12115 v8::HandleScope scope(isolate);
12116 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12117 v8::ObjectTemplate::New(isolate);
12118 nativeobject_templ->Set(isolate, "callback",
12119 v8::FunctionTemplate::New(isolate,
12120 ThrowingDirectApiCallback));
12121 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12122 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12123 // call the api function multiple times to ensure direct call stub creation.
12124 v8::Handle<Value> result = CompileRun(
12127 " for (var i = 1; i <= 5; i++) {"
12128 " try { nativeobject.callback(); } catch (e) { result += e; }"
12132 CHECK_EQ(v8_str("ggggg"), result);
12136 static Handle<Value> DoDirectGetter() {
12137 if (++p_getter_count % 3 == 0) {
12138 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12139 GenerateSomeGarbage();
12141 return v8_str("Direct Getter Result");
12144 static void DirectGetterCallback(
12145 Local<String> name,
12146 const v8::PropertyCallbackInfo<v8::Value>& info) {
12147 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12148 info.GetReturnValue().Set(DoDirectGetter());
12152 template<typename Accessor>
12153 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12154 LocalContext context;
12155 v8::Isolate* isolate = context->GetIsolate();
12156 v8::HandleScope scope(isolate);
12157 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12158 obj->SetAccessor(v8_str("p1"), accessor);
12159 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12160 p_getter_count = 0;
12161 v8::Handle<v8::Value> result = CompileRun(
12163 " for (var i = 0; i < 30; i++) o1.p1;"
12167 CHECK_EQ(v8_str("Direct Getter Result"), result);
12168 CHECK_EQ(31, p_getter_count);
12172 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12173 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12177 void ThrowingDirectGetterCallback(
12178 Local<String> name,
12179 const v8::PropertyCallbackInfo<v8::Value>& info) {
12180 info.GetIsolate()->ThrowException(v8_str("g"));
12184 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12185 LocalContext context;
12186 v8::Isolate* isolate = context->GetIsolate();
12187 v8::HandleScope scope(isolate);
12188 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12189 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12190 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12191 v8::Handle<Value> result = CompileRun(
12193 "for (var i = 0; i < 5; i++) {"
12194 " try { o1.p1; } catch (e) { result += e; }"
12197 CHECK_EQ(v8_str("ggggg"), result);
12201 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12202 int interceptor_call_count = 0;
12203 v8::Isolate* isolate = CcTest::isolate();
12204 v8::HandleScope scope(isolate);
12205 v8::Handle<v8::FunctionTemplate> fun_templ =
12206 v8::FunctionTemplate::New(isolate);
12207 v8::Handle<v8::FunctionTemplate> method_templ =
12208 v8::FunctionTemplate::New(isolate,
12209 FastApiCallback_TrivialSignature,
12210 v8_str("method_data"),
12211 v8::Handle<v8::Signature>());
12212 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12213 proto_templ->Set(v8_str("method"), method_templ);
12214 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12215 templ->SetNamedPropertyHandler(
12216 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12217 v8::External::New(isolate, &interceptor_call_count));
12218 LocalContext context;
12219 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12220 GenerateSomeGarbage();
12221 context->Global()->Set(v8_str("o"), fun->NewInstance());
12224 "for (var i = 0; i < 100; i++) {"
12225 " result = o.method(41);"
12227 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12228 CHECK_EQ(100, interceptor_call_count);
12232 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12233 int interceptor_call_count = 0;
12234 v8::Isolate* isolate = CcTest::isolate();
12235 v8::HandleScope scope(isolate);
12236 v8::Handle<v8::FunctionTemplate> fun_templ =
12237 v8::FunctionTemplate::New(isolate);
12238 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12239 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12240 v8::Signature::New(isolate, fun_templ));
12241 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12242 proto_templ->Set(v8_str("method"), method_templ);
12243 fun_templ->SetHiddenPrototype(true);
12244 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12245 templ->SetNamedPropertyHandler(
12246 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12247 v8::External::New(isolate, &interceptor_call_count));
12248 LocalContext context;
12249 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12250 GenerateSomeGarbage();
12251 context->Global()->Set(v8_str("o"), fun->NewInstance());
12254 "var receiver = {};"
12255 "receiver.__proto__ = o;"
12257 "for (var i = 0; i < 100; i++) {"
12258 " result = receiver.method(41);"
12260 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12261 CHECK_EQ(100, interceptor_call_count);
12265 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12266 int interceptor_call_count = 0;
12267 v8::Isolate* isolate = CcTest::isolate();
12268 v8::HandleScope scope(isolate);
12269 v8::Handle<v8::FunctionTemplate> fun_templ =
12270 v8::FunctionTemplate::New(isolate);
12271 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12272 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12273 v8::Signature::New(isolate, fun_templ));
12274 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12275 proto_templ->Set(v8_str("method"), method_templ);
12276 fun_templ->SetHiddenPrototype(true);
12277 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12278 templ->SetNamedPropertyHandler(
12279 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12280 v8::External::New(isolate, &interceptor_call_count));
12281 LocalContext context;
12282 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12283 GenerateSomeGarbage();
12284 context->Global()->Set(v8_str("o"), fun->NewInstance());
12287 "var receiver = {};"
12288 "receiver.__proto__ = o;"
12290 "var saved_result = 0;"
12291 "for (var i = 0; i < 100; i++) {"
12292 " result = receiver.method(41);"
12294 " saved_result = result;"
12295 " receiver = {method: function(x) { return x - 1 }};"
12298 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12299 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12300 CHECK_GE(interceptor_call_count, 50);
12304 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12305 int interceptor_call_count = 0;
12306 v8::Isolate* isolate = CcTest::isolate();
12307 v8::HandleScope scope(isolate);
12308 v8::Handle<v8::FunctionTemplate> fun_templ =
12309 v8::FunctionTemplate::New(isolate);
12310 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12311 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12312 v8::Signature::New(isolate, fun_templ));
12313 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12314 proto_templ->Set(v8_str("method"), method_templ);
12315 fun_templ->SetHiddenPrototype(true);
12316 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12317 templ->SetNamedPropertyHandler(
12318 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12319 v8::External::New(isolate, &interceptor_call_count));
12320 LocalContext context;
12321 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12322 GenerateSomeGarbage();
12323 context->Global()->Set(v8_str("o"), fun->NewInstance());
12326 "var receiver = {};"
12327 "receiver.__proto__ = o;"
12329 "var saved_result = 0;"
12330 "for (var i = 0; i < 100; i++) {"
12331 " result = receiver.method(41);"
12333 " saved_result = result;"
12334 " o.method = function(x) { return x - 1 };"
12337 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12338 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12339 CHECK_GE(interceptor_call_count, 50);
12343 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12344 int interceptor_call_count = 0;
12345 v8::Isolate* isolate = CcTest::isolate();
12346 v8::HandleScope scope(isolate);
12347 v8::Handle<v8::FunctionTemplate> fun_templ =
12348 v8::FunctionTemplate::New(isolate);
12349 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12350 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12351 v8::Signature::New(isolate, fun_templ));
12352 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12353 proto_templ->Set(v8_str("method"), method_templ);
12354 fun_templ->SetHiddenPrototype(true);
12355 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12356 templ->SetNamedPropertyHandler(
12357 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12358 v8::External::New(isolate, &interceptor_call_count));
12359 LocalContext context;
12360 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12361 GenerateSomeGarbage();
12362 context->Global()->Set(v8_str("o"), fun->NewInstance());
12363 v8::TryCatch try_catch;
12366 "var receiver = {};"
12367 "receiver.__proto__ = o;"
12369 "var saved_result = 0;"
12370 "for (var i = 0; i < 100; i++) {"
12371 " result = receiver.method(41);"
12373 " saved_result = result;"
12377 CHECK(try_catch.HasCaught());
12378 // TODO(verwaest): Adjust message.
12379 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12380 try_catch.Exception()->ToString());
12381 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12382 CHECK_GE(interceptor_call_count, 50);
12386 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12387 int interceptor_call_count = 0;
12388 v8::Isolate* isolate = CcTest::isolate();
12389 v8::HandleScope scope(isolate);
12390 v8::Handle<v8::FunctionTemplate> fun_templ =
12391 v8::FunctionTemplate::New(isolate);
12392 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12393 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12394 v8::Signature::New(isolate, fun_templ));
12395 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12396 proto_templ->Set(v8_str("method"), method_templ);
12397 fun_templ->SetHiddenPrototype(true);
12398 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12399 templ->SetNamedPropertyHandler(
12400 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12401 v8::External::New(isolate, &interceptor_call_count));
12402 LocalContext context;
12403 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12404 GenerateSomeGarbage();
12405 context->Global()->Set(v8_str("o"), fun->NewInstance());
12406 v8::TryCatch try_catch;
12409 "var receiver = {};"
12410 "receiver.__proto__ = o;"
12412 "var saved_result = 0;"
12413 "for (var i = 0; i < 100; i++) {"
12414 " result = receiver.method(41);"
12416 " saved_result = result;"
12417 " receiver = {method: receiver.method};"
12420 CHECK(try_catch.HasCaught());
12421 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12422 try_catch.Exception()->ToString());
12423 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12424 CHECK_GE(interceptor_call_count, 50);
12428 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12429 v8::Isolate* isolate = CcTest::isolate();
12430 v8::HandleScope scope(isolate);
12431 v8::Handle<v8::FunctionTemplate> fun_templ =
12432 v8::FunctionTemplate::New(isolate);
12433 v8::Handle<v8::FunctionTemplate> method_templ =
12434 v8::FunctionTemplate::New(isolate,
12435 FastApiCallback_TrivialSignature,
12436 v8_str("method_data"),
12437 v8::Handle<v8::Signature>());
12438 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12439 proto_templ->Set(v8_str("method"), method_templ);
12440 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12442 LocalContext context;
12443 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12444 GenerateSomeGarbage();
12445 context->Global()->Set(v8_str("o"), fun->NewInstance());
12448 "for (var i = 0; i < 100; i++) {"
12449 " result = o.method(41);"
12452 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12456 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12457 v8::Isolate* isolate = CcTest::isolate();
12458 v8::HandleScope scope(isolate);
12459 v8::Handle<v8::FunctionTemplate> fun_templ =
12460 v8::FunctionTemplate::New(isolate);
12461 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12462 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12463 v8::Signature::New(isolate, fun_templ));
12464 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12465 proto_templ->Set(v8_str("method"), method_templ);
12466 fun_templ->SetHiddenPrototype(true);
12467 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12468 CHECK(!templ.IsEmpty());
12469 LocalContext context;
12470 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12471 GenerateSomeGarbage();
12472 context->Global()->Set(v8_str("o"), fun->NewInstance());
12475 "var receiver = {};"
12476 "receiver.__proto__ = o;"
12478 "for (var i = 0; i < 100; i++) {"
12479 " result = receiver.method(41);"
12482 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12486 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12487 v8::Isolate* isolate = CcTest::isolate();
12488 v8::HandleScope scope(isolate);
12489 v8::Handle<v8::FunctionTemplate> fun_templ =
12490 v8::FunctionTemplate::New(isolate);
12491 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12492 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12493 v8::Signature::New(isolate, fun_templ));
12494 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12495 proto_templ->Set(v8_str("method"), method_templ);
12496 fun_templ->SetHiddenPrototype(true);
12497 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12498 CHECK(!templ.IsEmpty());
12499 LocalContext context;
12500 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12501 GenerateSomeGarbage();
12502 context->Global()->Set(v8_str("o"), fun->NewInstance());
12505 "var receiver = {};"
12506 "receiver.__proto__ = o;"
12508 "var saved_result = 0;"
12509 "for (var i = 0; i < 100; i++) {"
12510 " result = receiver.method(41);"
12512 " saved_result = result;"
12513 " receiver = {method: function(x) { return x - 1 }};"
12516 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12517 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12521 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12522 v8::Isolate* isolate = CcTest::isolate();
12523 v8::HandleScope scope(isolate);
12524 v8::Handle<v8::FunctionTemplate> fun_templ =
12525 v8::FunctionTemplate::New(isolate);
12526 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12527 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12528 v8::Signature::New(isolate, fun_templ));
12529 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12530 proto_templ->Set(v8_str("method"), method_templ);
12531 fun_templ->SetHiddenPrototype(true);
12532 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12533 CHECK(!templ.IsEmpty());
12534 LocalContext context;
12535 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12536 GenerateSomeGarbage();
12537 context->Global()->Set(v8_str("o"), fun->NewInstance());
12538 v8::TryCatch try_catch;
12541 "var receiver = {};"
12542 "receiver.__proto__ = o;"
12544 "var saved_result = 0;"
12545 "for (var i = 0; i < 100; i++) {"
12546 " result = receiver.method(41);"
12548 " saved_result = result;"
12552 CHECK(try_catch.HasCaught());
12553 // TODO(verwaest): Adjust message.
12554 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12555 try_catch.Exception()->ToString());
12556 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12560 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12561 v8::Isolate* isolate = CcTest::isolate();
12562 v8::HandleScope scope(isolate);
12563 v8::Handle<v8::FunctionTemplate> fun_templ =
12564 v8::FunctionTemplate::New(isolate);
12565 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12566 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12567 v8::Signature::New(isolate, fun_templ));
12568 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12569 proto_templ->Set(v8_str("method"), method_templ);
12570 fun_templ->SetHiddenPrototype(true);
12571 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12572 CHECK(!templ.IsEmpty());
12573 LocalContext context;
12574 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12575 GenerateSomeGarbage();
12576 context->Global()->Set(v8_str("o"), fun->NewInstance());
12577 v8::TryCatch try_catch;
12580 "var receiver = {};"
12581 "receiver.__proto__ = o;"
12583 "var saved_result = 0;"
12584 "for (var i = 0; i < 100; i++) {"
12585 " result = receiver.method(41);"
12587 " saved_result = result;"
12588 " receiver = Object.create(receiver);"
12591 CHECK(try_catch.HasCaught());
12592 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12593 try_catch.Exception()->ToString());
12594 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12598 v8::Handle<Value> keyed_call_ic_function;
12600 static void InterceptorKeyedCallICGetter(
12601 Local<String> name,
12602 const v8::PropertyCallbackInfo<v8::Value>& info) {
12603 ApiTestFuzzer::Fuzz();
12604 if (v8_str("x")->Equals(name)) {
12605 info.GetReturnValue().Set(keyed_call_ic_function);
12610 // Test the case when we stored cacheable lookup into
12611 // a stub, but the function name changed (to another cacheable function).
12612 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12613 v8::Isolate* isolate = CcTest::isolate();
12614 v8::HandleScope scope(isolate);
12615 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12616 templ->SetNamedPropertyHandler(NoBlockGetterX);
12617 LocalContext context;
12618 context->Global()->Set(v8_str("o"), templ->NewInstance());
12620 "proto = new Object();"
12621 "proto.y = function(x) { return x + 1; };"
12622 "proto.z = function(x) { return x - 1; };"
12623 "o.__proto__ = proto;"
12625 "var method = 'y';"
12626 "for (var i = 0; i < 10; i++) {"
12627 " if (i == 5) { method = 'z'; };"
12628 " result += o[method](41);"
12630 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12634 // Test the case when we stored cacheable lookup into
12635 // a stub, but the function name changed (and the new function is present
12636 // both before and after the interceptor in the prototype chain).
12637 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12638 v8::Isolate* isolate = CcTest::isolate();
12639 v8::HandleScope scope(isolate);
12640 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12641 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12642 LocalContext context;
12643 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12644 keyed_call_ic_function =
12645 v8_compile("function f(x) { return x - 1; }; f")->Run();
12647 "o = new Object();"
12648 "proto2 = new Object();"
12649 "o.y = function(x) { return x + 1; };"
12650 "proto2.y = function(x) { return x + 2; };"
12651 "o.__proto__ = proto1;"
12652 "proto1.__proto__ = proto2;"
12654 "var method = 'x';"
12655 "for (var i = 0; i < 10; i++) {"
12656 " if (i == 5) { method = 'y'; };"
12657 " result += o[method](41);"
12659 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12663 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12664 // on the global object.
12665 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12666 v8::Isolate* isolate = CcTest::isolate();
12667 v8::HandleScope scope(isolate);
12668 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12669 templ->SetNamedPropertyHandler(NoBlockGetterX);
12670 LocalContext context;
12671 context->Global()->Set(v8_str("o"), templ->NewInstance());
12673 "function inc(x) { return x + 1; };"
12675 "function dec(x) { return x - 1; };"
12677 "o.__proto__ = this;"
12678 "this.__proto__.x = inc;"
12679 "this.__proto__.y = dec;"
12681 "var method = 'x';"
12682 "for (var i = 0; i < 10; i++) {"
12683 " if (i == 5) { method = 'y'; };"
12684 " result += o[method](41);"
12686 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12690 // Test the case when actual function to call sits on global object.
12691 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12692 v8::Isolate* isolate = CcTest::isolate();
12693 v8::HandleScope scope(isolate);
12694 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12695 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12696 LocalContext context;
12697 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12700 "function len(x) { return x.length; };"
12701 "o.__proto__ = this;"
12702 "var m = 'parseFloat';"
12704 "for (var i = 0; i < 10; i++) {"
12707 " saved_result = result;"
12709 " result = o[m]('239');"
12711 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12712 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12716 // Test the map transition before the interceptor.
12717 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12718 v8::Isolate* isolate = CcTest::isolate();
12719 v8::HandleScope scope(isolate);
12720 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12721 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12722 LocalContext context;
12723 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12726 "var o = new Object();"
12727 "o.__proto__ = proto;"
12728 "o.method = function(x) { return x + 1; };"
12729 "var m = 'method';"
12731 "for (var i = 0; i < 10; i++) {"
12732 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12733 " result += o[m](41);"
12735 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12739 // Test the map transition after the interceptor.
12740 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12741 v8::Isolate* isolate = CcTest::isolate();
12742 v8::HandleScope scope(isolate);
12743 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12744 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12745 LocalContext context;
12746 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12749 "var proto = new Object();"
12750 "o.__proto__ = proto;"
12751 "proto.method = function(x) { return x + 1; };"
12752 "var m = 'method';"
12754 "for (var i = 0; i < 10; i++) {"
12755 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12756 " result += o[m](41);"
12758 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12762 static int interceptor_call_count = 0;
12764 static void InterceptorICRefErrorGetter(
12765 Local<String> name,
12766 const v8::PropertyCallbackInfo<v8::Value>& info) {
12767 ApiTestFuzzer::Fuzz();
12768 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12769 info.GetReturnValue().Set(call_ic_function2);
12774 // This test should hit load and call ICs for the interceptor case.
12775 // Once in a while, the interceptor will reply that a property was not
12776 // found in which case we should get a reference error.
12777 THREADED_TEST(InterceptorICReferenceErrors) {
12778 v8::Isolate* isolate = CcTest::isolate();
12779 v8::HandleScope scope(isolate);
12780 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12781 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12782 LocalContext context(0, templ, v8::Handle<Value>());
12783 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12784 v8::Handle<Value> value = CompileRun(
12786 " for (var i = 0; i < 1000; i++) {"
12787 " try { x; } catch(e) { return true; }"
12792 CHECK_EQ(true, value->BooleanValue());
12793 interceptor_call_count = 0;
12794 value = CompileRun(
12796 " for (var i = 0; i < 1000; i++) {"
12797 " try { x(42); } catch(e) { return true; }"
12802 CHECK_EQ(true, value->BooleanValue());
12806 static int interceptor_ic_exception_get_count = 0;
12808 static void InterceptorICExceptionGetter(
12809 Local<String> name,
12810 const v8::PropertyCallbackInfo<v8::Value>& info) {
12811 ApiTestFuzzer::Fuzz();
12812 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12813 info.GetReturnValue().Set(call_ic_function3);
12815 if (interceptor_ic_exception_get_count == 20) {
12816 info.GetIsolate()->ThrowException(v8_num(42));
12822 // Test interceptor load/call IC where the interceptor throws an
12823 // exception once in a while.
12824 THREADED_TEST(InterceptorICGetterExceptions) {
12825 interceptor_ic_exception_get_count = 0;
12826 v8::Isolate* isolate = CcTest::isolate();
12827 v8::HandleScope scope(isolate);
12828 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12829 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12830 LocalContext context(0, templ, v8::Handle<Value>());
12831 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12832 v8::Handle<Value> value = CompileRun(
12834 " for (var i = 0; i < 100; i++) {"
12835 " try { x; } catch(e) { return true; }"
12840 CHECK_EQ(true, value->BooleanValue());
12841 interceptor_ic_exception_get_count = 0;
12842 value = CompileRun(
12844 " for (var i = 0; i < 100; i++) {"
12845 " try { x(42); } catch(e) { return true; }"
12850 CHECK_EQ(true, value->BooleanValue());
12854 static int interceptor_ic_exception_set_count = 0;
12856 static void InterceptorICExceptionSetter(
12858 Local<Value> value,
12859 const v8::PropertyCallbackInfo<v8::Value>& info) {
12860 ApiTestFuzzer::Fuzz();
12861 if (++interceptor_ic_exception_set_count > 20) {
12862 info.GetIsolate()->ThrowException(v8_num(42));
12867 // Test interceptor store IC where the interceptor throws an exception
12868 // once in a while.
12869 THREADED_TEST(InterceptorICSetterExceptions) {
12870 interceptor_ic_exception_set_count = 0;
12871 v8::Isolate* isolate = CcTest::isolate();
12872 v8::HandleScope scope(isolate);
12873 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12874 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12875 LocalContext context(0, templ, v8::Handle<Value>());
12876 v8::Handle<Value> value = CompileRun(
12878 " for (var i = 0; i < 100; i++) {"
12879 " try { x = 42; } catch(e) { return true; }"
12884 CHECK_EQ(true, value->BooleanValue());
12888 // Test that we ignore null interceptors.
12889 THREADED_TEST(NullNamedInterceptor) {
12890 v8::Isolate* isolate = CcTest::isolate();
12891 v8::HandleScope scope(isolate);
12892 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12893 templ->SetNamedPropertyHandler(
12894 static_cast<v8::NamedPropertyGetterCallback>(0));
12895 LocalContext context;
12896 templ->Set(CcTest::isolate(), "x", v8_num(42));
12897 v8::Handle<v8::Object> obj = templ->NewInstance();
12898 context->Global()->Set(v8_str("obj"), obj);
12899 v8::Handle<Value> value = CompileRun("obj.x");
12900 CHECK(value->IsInt32());
12901 CHECK_EQ(42, value->Int32Value());
12905 // Test that we ignore null interceptors.
12906 THREADED_TEST(NullIndexedInterceptor) {
12907 v8::Isolate* isolate = CcTest::isolate();
12908 v8::HandleScope scope(isolate);
12909 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12910 templ->SetIndexedPropertyHandler(
12911 static_cast<v8::IndexedPropertyGetterCallback>(0));
12912 LocalContext context;
12913 templ->Set(CcTest::isolate(), "42", v8_num(42));
12914 v8::Handle<v8::Object> obj = templ->NewInstance();
12915 context->Global()->Set(v8_str("obj"), obj);
12916 v8::Handle<Value> value = CompileRun("obj[42]");
12917 CHECK(value->IsInt32());
12918 CHECK_EQ(42, value->Int32Value());
12922 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12923 v8::Isolate* isolate = CcTest::isolate();
12924 v8::HandleScope scope(isolate);
12925 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12926 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12928 env->Global()->Set(v8_str("obj"),
12929 templ->GetFunction()->NewInstance());
12930 ExpectTrue("obj.x === 42");
12931 ExpectTrue("!obj.propertyIsEnumerable('x')");
12935 static void ThrowingGetter(Local<String> name,
12936 const v8::PropertyCallbackInfo<v8::Value>& info) {
12937 ApiTestFuzzer::Fuzz();
12938 info.GetIsolate()->ThrowException(Handle<Value>());
12939 info.GetReturnValue().SetUndefined();
12943 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12944 LocalContext context;
12945 HandleScope scope(context->GetIsolate());
12947 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12948 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12949 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12951 Local<Object> instance = templ->GetFunction()->NewInstance();
12953 Local<Object> another = Object::New(context->GetIsolate());
12954 another->SetPrototype(instance);
12956 Local<Object> with_js_getter = CompileRun(
12958 "o.__defineGetter__('f', function() { throw undefined; });\n"
12959 "o\n").As<Object>();
12960 CHECK(!with_js_getter.IsEmpty());
12962 TryCatch try_catch;
12964 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12965 CHECK(try_catch.HasCaught());
12967 CHECK(result.IsEmpty());
12969 result = another->GetRealNamedProperty(v8_str("f"));
12970 CHECK(try_catch.HasCaught());
12972 CHECK(result.IsEmpty());
12974 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12975 CHECK(try_catch.HasCaught());
12977 CHECK(result.IsEmpty());
12979 result = another->Get(v8_str("f"));
12980 CHECK(try_catch.HasCaught());
12982 CHECK(result.IsEmpty());
12984 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12985 CHECK(try_catch.HasCaught());
12987 CHECK(result.IsEmpty());
12989 result = with_js_getter->Get(v8_str("f"));
12990 CHECK(try_catch.HasCaught());
12992 CHECK(result.IsEmpty());
12996 static void ThrowingCallbackWithTryCatch(
12997 const v8::FunctionCallbackInfo<v8::Value>& args) {
12998 TryCatch try_catch;
12999 // Verboseness is important: it triggers message delivery which can call into
13001 try_catch.SetVerbose(true);
13002 CompileRun("throw 'from JS';");
13003 CHECK(try_catch.HasCaught());
13004 CHECK(!CcTest::i_isolate()->has_pending_exception());
13005 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13009 static int call_depth;
13012 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13013 TryCatch try_catch;
13017 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13018 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13022 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13023 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13027 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13028 Handle<String> errorMessageString = message->Get();
13029 CHECK(!errorMessageString.IsEmpty());
13030 message->GetStackTrace();
13031 message->GetScriptResourceName();
13035 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13036 LocalContext context;
13037 v8::Isolate* isolate = context->GetIsolate();
13038 HandleScope scope(isolate);
13040 Local<Function> func =
13041 FunctionTemplate::New(isolate,
13042 ThrowingCallbackWithTryCatch)->GetFunction();
13043 context->Global()->Set(v8_str("func"), func);
13045 MessageCallback callbacks[] =
13046 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13047 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13048 MessageCallback callback = callbacks[i];
13049 if (callback != NULL) {
13050 V8::AddMessageListener(callback);
13052 // Some small number to control number of times message handler should
13053 // throw an exception.
13056 "var thrown = false;\n"
13057 "try { func(); } catch(e) { thrown = true; }\n"
13059 if (callback != NULL) {
13060 V8::RemoveMessageListeners(callback);
13066 static void ParentGetter(Local<String> name,
13067 const v8::PropertyCallbackInfo<v8::Value>& info) {
13068 ApiTestFuzzer::Fuzz();
13069 info.GetReturnValue().Set(v8_num(1));
13073 static void ChildGetter(Local<String> name,
13074 const v8::PropertyCallbackInfo<v8::Value>& info) {
13075 ApiTestFuzzer::Fuzz();
13076 info.GetReturnValue().Set(v8_num(42));
13080 THREADED_TEST(Overriding) {
13081 LocalContext context;
13082 v8::Isolate* isolate = context->GetIsolate();
13083 v8::HandleScope scope(isolate);
13085 // Parent template.
13086 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13087 Local<ObjectTemplate> parent_instance_templ =
13088 parent_templ->InstanceTemplate();
13089 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13091 // Template that inherits from the parent template.
13092 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13093 Local<ObjectTemplate> child_instance_templ =
13094 child_templ->InstanceTemplate();
13095 child_templ->Inherit(parent_templ);
13096 // Override 'f'. The child version of 'f' should get called for child
13098 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13099 // Add 'g' twice. The 'g' added last should get called for instances.
13100 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13101 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13103 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13104 // so 'h' can be shadowed on the instance object.
13105 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13106 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13107 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13109 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13110 // but the attribute does not have effect because it is duplicated with
13112 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13113 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13117 // Instantiate the child template.
13118 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13120 // Check that the child function overrides the parent one.
13121 context->Global()->Set(v8_str("o"), instance);
13122 Local<Value> value = v8_compile("o.f")->Run();
13123 // Check that the 'g' that was added last is hit.
13124 CHECK_EQ(42, value->Int32Value());
13125 value = v8_compile("o.g")->Run();
13126 CHECK_EQ(42, value->Int32Value());
13128 // Check that 'h' cannot be shadowed.
13129 value = v8_compile("o.h = 3; o.h")->Run();
13130 CHECK_EQ(1, value->Int32Value());
13132 // Check that 'i' cannot be shadowed or changed.
13133 value = v8_compile("o.i = 3; o.i")->Run();
13134 CHECK_EQ(42, value->Int32Value());
13138 static void IsConstructHandler(
13139 const v8::FunctionCallbackInfo<v8::Value>& args) {
13140 ApiTestFuzzer::Fuzz();
13141 args.GetReturnValue().Set(args.IsConstructCall());
13145 THREADED_TEST(IsConstructCall) {
13146 v8::Isolate* isolate = CcTest::isolate();
13147 v8::HandleScope scope(isolate);
13149 // Function template with call handler.
13150 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13151 templ->SetCallHandler(IsConstructHandler);
13153 LocalContext context;
13155 context->Global()->Set(v8_str("f"), templ->GetFunction());
13156 Local<Value> value = v8_compile("f()")->Run();
13157 CHECK(!value->BooleanValue());
13158 value = v8_compile("new f()")->Run();
13159 CHECK(value->BooleanValue());
13163 THREADED_TEST(ObjectProtoToString) {
13164 v8::Isolate* isolate = CcTest::isolate();
13165 v8::HandleScope scope(isolate);
13166 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13167 templ->SetClassName(v8_str("MyClass"));
13169 LocalContext context;
13171 Local<String> customized_tostring = v8_str("customized toString");
13173 // Replace Object.prototype.toString
13174 v8_compile("Object.prototype.toString = function() {"
13175 " return 'customized toString';"
13178 // Normal ToString call should call replaced Object.prototype.toString
13179 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13180 Local<String> value = instance->ToString();
13181 CHECK(value->IsString() && value->Equals(customized_tostring));
13183 // ObjectProtoToString should not call replace toString function.
13184 value = instance->ObjectProtoToString();
13185 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13188 value = context->Global()->ObjectProtoToString();
13189 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13191 // Check ordinary object
13192 Local<Value> object = v8_compile("new Object()")->Run();
13193 value = object.As<v8::Object>()->ObjectProtoToString();
13194 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13198 THREADED_TEST(ObjectGetConstructorName) {
13199 LocalContext context;
13200 v8::HandleScope scope(context->GetIsolate());
13201 v8_compile("function Parent() {};"
13202 "function Child() {};"
13203 "Child.prototype = new Parent();"
13204 "var outer = { inner: function() { } };"
13205 "var p = new Parent();"
13206 "var c = new Child();"
13207 "var x = new outer.inner();")->Run();
13209 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13210 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13211 v8_str("Parent")));
13213 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13214 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13217 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13218 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13219 v8_str("outer.inner")));
13223 bool ApiTestFuzzer::fuzzing_ = false;
13224 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13225 int ApiTestFuzzer::active_tests_;
13226 int ApiTestFuzzer::tests_being_run_;
13227 int ApiTestFuzzer::current_;
13230 // We are in a callback and want to switch to another thread (if we
13231 // are currently running the thread fuzzing test).
13232 void ApiTestFuzzer::Fuzz() {
13233 if (!fuzzing_) return;
13234 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13235 test->ContextSwitch();
13239 // Let the next thread go. Since it is also waiting on the V8 lock it may
13240 // not start immediately.
13241 bool ApiTestFuzzer::NextThread() {
13242 int test_position = GetNextTestNumber();
13243 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13244 if (test_position == current_) {
13246 printf("Stay with %s\n", test_name);
13249 if (kLogThreading) {
13250 printf("Switch from %s to %s\n",
13252 RegisterThreadedTest::nth(test_position)->name());
13254 current_ = test_position;
13255 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13260 void ApiTestFuzzer::Run() {
13261 // When it is our turn...
13264 // ... get the V8 lock and start running the test.
13265 v8::Locker locker(CcTest::isolate());
13268 // This test finished.
13271 // If it was the last then signal that fact.
13272 if (active_tests_ == 0) {
13273 all_tests_done_.Signal();
13275 // Otherwise select a new test and start that.
13281 static unsigned linear_congruential_generator;
13284 void ApiTestFuzzer::SetUp(PartOfTest part) {
13285 linear_congruential_generator = i::FLAG_testing_prng_seed;
13287 int count = RegisterThreadedTest::count();
13288 int start = count * part / (LAST_PART + 1);
13289 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13290 active_tests_ = tests_being_run_ = end - start + 1;
13291 for (int i = 0; i < tests_being_run_; i++) {
13292 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13294 for (int i = 0; i < active_tests_; i++) {
13295 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13300 static void CallTestNumber(int test_number) {
13301 (RegisterThreadedTest::nth(test_number)->callback())();
13305 void ApiTestFuzzer::RunAllTests() {
13306 // Set off the first test.
13309 // Wait till they are all done.
13310 all_tests_done_.Wait();
13314 int ApiTestFuzzer::GetNextTestNumber() {
13317 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13318 linear_congruential_generator *= 1664525u;
13319 linear_congruential_generator += 1013904223u;
13320 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13325 void ApiTestFuzzer::ContextSwitch() {
13326 // If the new thread is the same as the current thread there is nothing to do.
13327 if (NextThread()) {
13328 // Now it can start.
13329 v8::Unlocker unlocker(CcTest::isolate());
13330 // Wait till someone starts us again.
13337 void ApiTestFuzzer::TearDown() {
13339 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13340 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13341 if (fuzzer != NULL) fuzzer->Join();
13346 // Lets not be needlessly self-referential.
13348 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13349 ApiTestFuzzer::RunAllTests();
13350 ApiTestFuzzer::TearDown();
13355 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13356 ApiTestFuzzer::RunAllTests();
13357 ApiTestFuzzer::TearDown();
13362 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13363 ApiTestFuzzer::RunAllTests();
13364 ApiTestFuzzer::TearDown();
13369 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13370 ApiTestFuzzer::RunAllTests();
13371 ApiTestFuzzer::TearDown();
13375 void ApiTestFuzzer::CallTest() {
13376 v8::Isolate::Scope scope(CcTest::isolate());
13378 printf("Start test %d\n", test_number_);
13379 CallTestNumber(test_number_);
13381 printf("End test %d\n", test_number_);
13385 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13386 v8::Isolate* isolate = args.GetIsolate();
13387 CHECK(v8::Locker::IsLocked(isolate));
13388 ApiTestFuzzer::Fuzz();
13389 v8::Unlocker unlocker(isolate);
13390 const char* code = "throw 7;";
13392 v8::Locker nested_locker(isolate);
13393 v8::HandleScope scope(isolate);
13394 v8::Handle<Value> exception;
13395 { v8::TryCatch try_catch;
13396 v8::Handle<Value> value = CompileRun(code);
13397 CHECK(value.IsEmpty());
13398 CHECK(try_catch.HasCaught());
13399 // Make sure to wrap the exception in a new handle because
13400 // the handle returned from the TryCatch is destroyed
13401 // when the TryCatch is destroyed.
13402 exception = Local<Value>::New(isolate, try_catch.Exception());
13404 args.GetIsolate()->ThrowException(exception);
13409 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13410 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13411 ApiTestFuzzer::Fuzz();
13412 v8::Unlocker unlocker(CcTest::isolate());
13413 const char* code = "throw 7;";
13415 v8::Locker nested_locker(CcTest::isolate());
13416 v8::HandleScope scope(args.GetIsolate());
13417 v8::Handle<Value> value = CompileRun(code);
13418 CHECK(value.IsEmpty());
13419 args.GetReturnValue().Set(v8_str("foo"));
13424 // These are locking tests that don't need to be run again
13425 // as part of the locking aggregation tests.
13426 TEST(NestedLockers) {
13427 v8::Isolate* isolate = CcTest::isolate();
13428 v8::Locker locker(isolate);
13429 CHECK(v8::Locker::IsLocked(isolate));
13431 v8::HandleScope scope(env->GetIsolate());
13432 Local<v8::FunctionTemplate> fun_templ =
13433 v8::FunctionTemplate::New(isolate, ThrowInJS);
13434 Local<Function> fun = fun_templ->GetFunction();
13435 env->Global()->Set(v8_str("throw_in_js"), fun);
13436 Local<Script> script = v8_compile("(function () {"
13444 CHECK_EQ(91, script->Run()->Int32Value());
13448 // These are locking tests that don't need to be run again
13449 // as part of the locking aggregation tests.
13450 TEST(NestedLockersNoTryCatch) {
13451 v8::Locker locker(CcTest::isolate());
13453 v8::HandleScope scope(env->GetIsolate());
13454 Local<v8::FunctionTemplate> fun_templ =
13455 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13456 Local<Function> fun = fun_templ->GetFunction();
13457 env->Global()->Set(v8_str("throw_in_js"), fun);
13458 Local<Script> script = v8_compile("(function () {"
13466 CHECK_EQ(91, script->Run()->Int32Value());
13470 THREADED_TEST(RecursiveLocking) {
13471 v8::Locker locker(CcTest::isolate());
13473 v8::Locker locker2(CcTest::isolate());
13474 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13479 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13480 ApiTestFuzzer::Fuzz();
13481 v8::Unlocker unlocker(CcTest::isolate());
13485 THREADED_TEST(LockUnlockLock) {
13487 v8::Locker locker(CcTest::isolate());
13488 v8::HandleScope scope(CcTest::isolate());
13490 Local<v8::FunctionTemplate> fun_templ =
13491 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13492 Local<Function> fun = fun_templ->GetFunction();
13493 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13494 Local<Script> script = v8_compile("(function () {"
13495 " unlock_for_a_moment();"
13498 CHECK_EQ(42, script->Run()->Int32Value());
13501 v8::Locker locker(CcTest::isolate());
13502 v8::HandleScope scope(CcTest::isolate());
13504 Local<v8::FunctionTemplate> fun_templ =
13505 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13506 Local<Function> fun = fun_templ->GetFunction();
13507 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13508 Local<Script> script = v8_compile("(function () {"
13509 " unlock_for_a_moment();"
13512 CHECK_EQ(42, script->Run()->Int32Value());
13517 static int GetGlobalObjectsCount() {
13519 i::HeapIterator it(CcTest::heap());
13520 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13521 if (object->IsJSGlobalObject()) count++;
13526 static void CheckSurvivingGlobalObjectsCount(int expected) {
13527 // We need to collect all garbage twice to be sure that everything
13528 // has been collected. This is because inline caches are cleared in
13529 // the first garbage collection but some of the maps have already
13530 // been marked at that point. Therefore some of the maps are not
13531 // collected until the second garbage collection.
13532 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13533 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13534 int count = GetGlobalObjectsCount();
13536 if (count != expected) CcTest::heap()->TracePathToGlobal();
13538 CHECK_EQ(expected, count);
13542 TEST(DontLeakGlobalObjects) {
13543 // Regression test for issues 1139850 and 1174891.
13545 i::FLAG_expose_gc = true;
13546 v8::V8::Initialize();
13548 for (int i = 0; i < 5; i++) {
13549 { v8::HandleScope scope(CcTest::isolate());
13550 LocalContext context;
13552 v8::V8::ContextDisposedNotification();
13553 CheckSurvivingGlobalObjectsCount(0);
13555 { v8::HandleScope scope(CcTest::isolate());
13556 LocalContext context;
13557 v8_compile("Date")->Run();
13559 v8::V8::ContextDisposedNotification();
13560 CheckSurvivingGlobalObjectsCount(0);
13562 { v8::HandleScope scope(CcTest::isolate());
13563 LocalContext context;
13564 v8_compile("/aaa/")->Run();
13566 v8::V8::ContextDisposedNotification();
13567 CheckSurvivingGlobalObjectsCount(0);
13569 { v8::HandleScope scope(CcTest::isolate());
13570 const char* extension_list[] = { "v8/gc" };
13571 v8::ExtensionConfiguration extensions(1, extension_list);
13572 LocalContext context(&extensions);
13573 v8_compile("gc();")->Run();
13575 v8::V8::ContextDisposedNotification();
13576 CheckSurvivingGlobalObjectsCount(0);
13581 TEST(CopyablePersistent) {
13582 LocalContext context;
13583 v8::Isolate* isolate = context->GetIsolate();
13584 i::GlobalHandles* globals =
13585 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13586 int initial_handles = globals->global_handles_count();
13587 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13590 CopyableObject handle1;
13592 v8::HandleScope scope(isolate);
13593 handle1.Reset(isolate, v8::Object::New(isolate));
13595 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13596 CopyableObject handle2;
13598 CHECK(handle1 == handle2);
13599 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13600 CopyableObject handle3(handle2);
13601 CHECK(handle1 == handle3);
13602 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13604 // Verify autodispose
13605 CHECK_EQ(initial_handles, globals->global_handles_count());
13609 static void WeakApiCallback(
13610 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13611 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13612 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13613 data.GetParameter()->Reset();
13614 delete data.GetParameter();
13618 TEST(WeakCallbackApi) {
13619 LocalContext context;
13620 v8::Isolate* isolate = context->GetIsolate();
13621 i::GlobalHandles* globals =
13622 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13623 int initial_handles = globals->global_handles_count();
13625 v8::HandleScope scope(isolate);
13626 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13627 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13628 v8::Persistent<v8::Object>* handle =
13629 new v8::Persistent<v8::Object>(isolate, obj);
13630 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13633 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13634 CollectAllGarbage(i::Heap::kNoGCFlags);
13635 // Verify disposed.
13636 CHECK_EQ(initial_handles, globals->global_handles_count());
13640 v8::Persistent<v8::Object> some_object;
13641 v8::Persistent<v8::Object> bad_handle;
13643 void NewPersistentHandleCallback(
13644 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13645 v8::HandleScope scope(data.GetIsolate());
13646 bad_handle.Reset(data.GetIsolate(), some_object);
13647 data.GetParameter()->Reset();
13651 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13652 LocalContext context;
13653 v8::Isolate* isolate = context->GetIsolate();
13655 v8::Persistent<v8::Object> handle1, handle2;
13657 v8::HandleScope scope(isolate);
13658 some_object.Reset(isolate, v8::Object::New(isolate));
13659 handle1.Reset(isolate, v8::Object::New(isolate));
13660 handle2.Reset(isolate, v8::Object::New(isolate));
13662 // Note: order is implementation dependent alas: currently
13663 // global handle nodes are processed by PostGarbageCollectionProcessing
13664 // in reverse allocation order, so if second allocated handle is deleted,
13665 // weak callback of the first handle would be able to 'reallocate' it.
13666 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13668 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13672 v8::Persistent<v8::Object> to_be_disposed;
13674 void DisposeAndForceGcCallback(
13675 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13676 to_be_disposed.Reset();
13677 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13678 data.GetParameter()->Reset();
13682 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13683 LocalContext context;
13684 v8::Isolate* isolate = context->GetIsolate();
13686 v8::Persistent<v8::Object> handle1, handle2;
13688 v8::HandleScope scope(isolate);
13689 handle1.Reset(isolate, v8::Object::New(isolate));
13690 handle2.Reset(isolate, v8::Object::New(isolate));
13692 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13693 to_be_disposed.Reset(isolate, handle2);
13694 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13697 void DisposingCallback(
13698 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13699 data.GetParameter()->Reset();
13702 void HandleCreatingCallback(
13703 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13704 v8::HandleScope scope(data.GetIsolate());
13705 v8::Persistent<v8::Object>(data.GetIsolate(),
13706 v8::Object::New(data.GetIsolate()));
13707 data.GetParameter()->Reset();
13711 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13712 LocalContext context;
13713 v8::Isolate* isolate = context->GetIsolate();
13715 v8::Persistent<v8::Object> handle1, handle2, handle3;
13717 v8::HandleScope scope(isolate);
13718 handle3.Reset(isolate, v8::Object::New(isolate));
13719 handle2.Reset(isolate, v8::Object::New(isolate));
13720 handle1.Reset(isolate, v8::Object::New(isolate));
13722 handle2.SetWeak(&handle2, DisposingCallback);
13723 handle3.SetWeak(&handle3, HandleCreatingCallback);
13724 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13728 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13729 v8::V8::Initialize();
13732 const char* sources[nof] = {
13733 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13737 for (int i = 0; i < nof; i++) {
13738 const char* source = sources[i];
13739 { v8::HandleScope scope(CcTest::isolate());
13740 LocalContext context;
13741 CompileRun(source);
13743 { v8::HandleScope scope(CcTest::isolate());
13744 LocalContext context;
13745 CompileRun(source);
13751 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13752 v8::EscapableHandleScope inner(env->GetIsolate());
13754 v8::Local<Value> three = v8_num(3);
13755 v8::Local<Value> value = inner.Escape(three);
13761 THREADED_TEST(NestedHandleScopeAndContexts) {
13762 v8::Isolate* isolate = CcTest::isolate();
13763 v8::HandleScope outer(isolate);
13764 v8::Local<Context> env = Context::New(isolate);
13766 v8::Handle<Value> value = NestedScope(env);
13767 v8::Handle<String> str(value->ToString());
13768 CHECK(!str.IsEmpty());
13773 static bool MatchPointers(void* key1, void* key2) {
13774 return key1 == key2;
13778 struct SymbolInfo {
13785 class SetFunctionEntryHookTest {
13787 SetFunctionEntryHookTest() {
13788 CHECK(instance_ == NULL);
13791 ~SetFunctionEntryHookTest() {
13792 CHECK(instance_ == this);
13797 symbol_locations_.clear();
13798 invocations_.clear();
13801 void OnJitEvent(const v8::JitCodeEvent* event);
13802 static void JitEvent(const v8::JitCodeEvent* event) {
13803 CHECK(instance_ != NULL);
13804 instance_->OnJitEvent(event);
13807 void OnEntryHook(uintptr_t function,
13808 uintptr_t return_addr_location);
13809 static void EntryHook(uintptr_t function,
13810 uintptr_t return_addr_location) {
13811 CHECK(instance_ != NULL);
13812 instance_->OnEntryHook(function, return_addr_location);
13815 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13816 CHECK(instance_ != NULL);
13817 args.GetReturnValue().Set(v8_num(42));
13819 void RunLoopInNewEnv(v8::Isolate* isolate);
13821 // Records addr as location of symbol.
13822 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13824 // Finds the symbol containing addr
13825 SymbolInfo* FindSymbolForAddr(i::Address addr);
13826 // Returns the number of invocations where the caller name contains
13827 // \p caller_name and the function name contains \p function_name.
13828 int CountInvocations(const char* caller_name,
13829 const char* function_name);
13831 i::Handle<i::JSFunction> foo_func_;
13832 i::Handle<i::JSFunction> bar_func_;
13834 typedef std::map<size_t, SymbolInfo> SymbolMap;
13835 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13836 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13837 SymbolMap symbols_;
13838 SymbolLocationMap symbol_locations_;
13839 InvocationMap invocations_;
13841 static SetFunctionEntryHookTest* instance_;
13843 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13846 // Returns true if addr is in the range [start, start+len).
13847 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13848 if (start <= addr && start + len > addr)
13854 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13855 SymbolInfo* symbol) {
13856 // Insert the symbol at the new location.
13857 SymbolLocationMap::iterator it =
13858 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13859 // Now erase symbols to the left and right that overlap this one.
13860 while (it != symbol_locations_.begin()) {
13861 SymbolLocationMap::iterator left = it;
13863 if (!Overlaps(left->first, left->second->size, addr))
13865 symbol_locations_.erase(left);
13868 // Now erase symbols to the left and right that overlap this one.
13870 SymbolLocationMap::iterator right = it;
13872 if (right == symbol_locations_.end())
13874 if (!Overlaps(addr, symbol->size, right->first))
13876 symbol_locations_.erase(right);
13881 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13882 switch (event->type) {
13883 case v8::JitCodeEvent::CODE_ADDED: {
13884 CHECK(event->code_start != NULL);
13885 CHECK_NE(0, static_cast<int>(event->code_len));
13886 CHECK(event->name.str != NULL);
13887 size_t symbol_id = symbols_.size();
13889 // Record the new symbol.
13890 SymbolInfo& info = symbols_[symbol_id];
13891 info.id = symbol_id;
13892 info.size = event->code_len;
13893 info.name.assign(event->name.str, event->name.str + event->name.len);
13895 // And record it's location.
13896 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13900 case v8::JitCodeEvent::CODE_MOVED: {
13901 // We would like to never see code move that we haven't seen before,
13902 // but the code creation event does not happen until the line endings
13903 // have been calculated (this is so that we can report the line in the
13904 // script at which the function source is found, see
13905 // Compiler::RecordFunctionCompilation) and the line endings
13906 // calculations can cause a GC, which can move the newly created code
13907 // before its existence can be logged.
13908 SymbolLocationMap::iterator it(
13909 symbol_locations_.find(
13910 reinterpret_cast<i::Address>(event->code_start)));
13911 if (it != symbol_locations_.end()) {
13912 // Found a symbol at this location, move it.
13913 SymbolInfo* info = it->second;
13914 symbol_locations_.erase(it);
13915 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13924 void SetFunctionEntryHookTest::OnEntryHook(
13925 uintptr_t function, uintptr_t return_addr_location) {
13926 // Get the function's code object.
13927 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13928 reinterpret_cast<i::Address>(function));
13929 CHECK(function_code != NULL);
13931 // Then try and look up the caller's code object.
13932 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13934 // Count the invocation.
13935 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13936 SymbolInfo* function_symbol =
13937 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13938 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13940 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13941 // Check that we have a symbol for the "bar" function at the right location.
13942 SymbolLocationMap::iterator it(
13943 symbol_locations_.find(function_code->instruction_start()));
13944 CHECK(it != symbol_locations_.end());
13947 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13948 // Check that we have a symbol for "foo" at the right location.
13949 SymbolLocationMap::iterator it(
13950 symbol_locations_.find(function_code->instruction_start()));
13951 CHECK(it != symbol_locations_.end());
13956 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13957 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13958 // Do we have a direct hit on a symbol?
13959 if (it != symbol_locations_.end()) {
13960 if (it->first == addr)
13964 // If not a direct hit, it'll have to be the previous symbol.
13965 if (it == symbol_locations_.begin())
13969 size_t offs = addr - it->first;
13970 if (offs < it->second->size)
13977 int SetFunctionEntryHookTest::CountInvocations(
13978 const char* caller_name, const char* function_name) {
13979 InvocationMap::iterator it(invocations_.begin());
13980 int invocations = 0;
13981 for (; it != invocations_.end(); ++it) {
13982 SymbolInfo* caller = it->first.first;
13983 SymbolInfo* function = it->first.second;
13985 // Filter out non-matching functions.
13986 if (function_name != NULL) {
13987 if (function->name.find(function_name) == std::string::npos)
13991 // Filter out non-matching callers.
13992 if (caller_name != NULL) {
13993 if (caller == NULL)
13995 if (caller->name.find(caller_name) == std::string::npos)
13999 // It matches add the invocation count to the tally.
14000 invocations += it->second;
14003 return invocations;
14007 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14008 v8::HandleScope outer(isolate);
14009 v8::Local<Context> env = Context::New(isolate);
14012 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14013 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14014 env->Global()->Set(v8_str("obj"), t->NewInstance());
14016 const char* script =
14017 "function bar() {\n"
14019 " for (i = 0; i < 100; ++i)\n"
14023 "function foo(i) { return i * i; }\n"
14024 "// Invoke on the runtime function.\n"
14026 CompileRun(script);
14027 bar_func_ = i::Handle<i::JSFunction>::cast(
14028 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14029 ASSERT(!bar_func_.is_null());
14032 i::Handle<i::JSFunction>::cast(
14033 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14034 ASSERT(!foo_func_.is_null());
14036 v8::Handle<v8::Value> value = CompileRun("bar();");
14037 CHECK(value->IsNumber());
14038 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14040 // Test the optimized codegen path.
14041 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14043 CHECK(value->IsNumber());
14044 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14050 void SetFunctionEntryHookTest::RunTest() {
14051 // Work in a new isolate throughout.
14052 v8::Isolate* isolate = v8::Isolate::New();
14054 // Test setting the entry hook on the new isolate.
14055 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14057 // Replacing the hook, once set should fail.
14058 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14061 v8::Isolate::Scope scope(isolate);
14063 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14065 RunLoopInNewEnv(isolate);
14067 // Check the exepected invocation counts.
14068 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14069 CHECK_EQ(200, CountInvocations("bar", "foo"));
14070 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14072 // Verify that we have an entry hook on some specific stubs.
14073 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14074 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14075 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14077 isolate->Dispose();
14081 // Make sure a second isolate is unaffected by the previous entry hook.
14082 isolate = v8::Isolate::New();
14084 v8::Isolate::Scope scope(isolate);
14086 // Reset the entry count to zero and set the entry hook.
14087 RunLoopInNewEnv(isolate);
14089 // We should record no invocations in this isolate.
14090 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14092 // Since the isolate has been used, we shouldn't be able to set an entry
14094 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14096 isolate->Dispose();
14100 TEST(SetFunctionEntryHook) {
14101 // FunctionEntryHook does not work well with experimental natives.
14102 // Experimental natives are compiled during snapshot deserialization.
14103 // This test breaks because InstallGetter (function from snapshot that
14104 // only gets called from experimental natives) is compiled with entry hooks.
14105 i::FLAG_allow_natives_syntax = true;
14106 i::FLAG_use_inlining = false;
14108 SetFunctionEntryHookTest test;
14113 static i::HashMap* code_map = NULL;
14114 static i::HashMap* jitcode_line_info = NULL;
14115 static int saw_bar = 0;
14116 static int move_events = 0;
14119 static bool FunctionNameIs(const char* expected,
14120 const v8::JitCodeEvent* event) {
14121 // Log lines for functions are of the general form:
14122 // "LazyCompile:<type><function_name>", where the type is one of
14124 static const char kPreamble[] = "LazyCompile:";
14125 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14127 if (event->name.len < sizeof(kPreamble) - 1 ||
14128 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14132 const char* tail = event->name.str + kPreambleLen;
14133 size_t tail_len = event->name.len - kPreambleLen;
14134 size_t expected_len = strlen(expected);
14135 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14140 // Check for tails like 'bar :1'.
14141 if (tail_len > expected_len + 2 &&
14142 tail[expected_len] == ' ' &&
14143 tail[expected_len + 1] == ':' &&
14144 tail[expected_len + 2] &&
14145 !strncmp(tail, expected, expected_len)) {
14149 if (tail_len != expected_len)
14152 return strncmp(tail, expected, expected_len) == 0;
14156 static void event_handler(const v8::JitCodeEvent* event) {
14157 CHECK(event != NULL);
14158 CHECK(code_map != NULL);
14159 CHECK(jitcode_line_info != NULL);
14161 class DummyJitCodeLineInfo {
14164 switch (event->type) {
14165 case v8::JitCodeEvent::CODE_ADDED: {
14166 CHECK(event->code_start != NULL);
14167 CHECK_NE(0, static_cast<int>(event->code_len));
14168 CHECK(event->name.str != NULL);
14169 i::HashMap::Entry* entry =
14170 code_map->Lookup(event->code_start,
14171 i::ComputePointerHash(event->code_start),
14173 entry->value = reinterpret_cast<void*>(event->code_len);
14175 if (FunctionNameIs("bar", event)) {
14181 case v8::JitCodeEvent::CODE_MOVED: {
14182 uint32_t hash = i::ComputePointerHash(event->code_start);
14183 // We would like to never see code move that we haven't seen before,
14184 // but the code creation event does not happen until the line endings
14185 // have been calculated (this is so that we can report the line in the
14186 // script at which the function source is found, see
14187 // Compiler::RecordFunctionCompilation) and the line endings
14188 // calculations can cause a GC, which can move the newly created code
14189 // before its existence can be logged.
14190 i::HashMap::Entry* entry =
14191 code_map->Lookup(event->code_start, hash, false);
14192 if (entry != NULL) {
14195 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14196 code_map->Remove(event->code_start, hash);
14198 entry = code_map->Lookup(event->new_code_start,
14199 i::ComputePointerHash(event->new_code_start),
14201 CHECK(entry != NULL);
14202 entry->value = reinterpret_cast<void*>(event->code_len);
14207 case v8::JitCodeEvent::CODE_REMOVED:
14208 // Object/code removal events are currently not dispatched from the GC.
14212 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14213 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14214 // record it in jitcode_line_info.
14215 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14216 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14217 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14218 temp_event->user_data = line_info;
14219 i::HashMap::Entry* entry =
14220 jitcode_line_info->Lookup(line_info,
14221 i::ComputePointerHash(line_info),
14223 entry->value = reinterpret_cast<void*>(line_info);
14226 // For these two events, we will check whether the event->user_data
14227 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14228 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14229 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14230 CHECK(event->user_data != NULL);
14231 uint32_t hash = i::ComputePointerHash(event->user_data);
14232 i::HashMap::Entry* entry =
14233 jitcode_line_info->Lookup(event->user_data, hash, false);
14234 CHECK(entry != NULL);
14235 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14239 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14240 CHECK(event->user_data != NULL);
14241 uint32_t hash = i::ComputePointerHash(event->user_data);
14242 i::HashMap::Entry* entry =
14243 jitcode_line_info->Lookup(event->user_data, hash, false);
14244 CHECK(entry != NULL);
14249 // Impossible event.
14256 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14257 i::FLAG_stress_compaction = true;
14258 i::FLAG_incremental_marking = false;
14259 if (i::FLAG_never_compact) return;
14260 const char* script =
14263 " for (i = 0; i < 100; ++i)"
14267 "function foo(i) { return i * i; };"
14270 // Run this test in a new isolate to make sure we don't
14271 // have remnants of state from other code.
14272 v8::Isolate* isolate = v8::Isolate::New();
14274 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14275 i::Heap* heap = i_isolate->heap();
14278 v8::HandleScope scope(isolate);
14279 i::HashMap code(MatchPointers);
14282 i::HashMap lineinfo(MatchPointers);
14283 jitcode_line_info = &lineinfo;
14288 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14290 // Generate new code objects sparsely distributed across several
14291 // different fragmented code-space pages.
14292 const int kIterations = 10;
14293 for (int i = 0; i < kIterations; ++i) {
14294 LocalContext env(isolate);
14295 i::AlwaysAllocateScope always_allocate(i_isolate);
14296 SimulateFullSpace(heap->code_space());
14297 CompileRun(script);
14299 // Keep a strong reference to the code object in the handle scope.
14300 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14301 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14302 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14303 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14305 // Clear the compilation cache to get more wastage.
14306 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14309 // Force code movement.
14310 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14312 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14314 CHECK_LE(kIterations, saw_bar);
14315 CHECK_LT(0, move_events);
14318 jitcode_line_info = NULL;
14322 isolate->Dispose();
14324 // Do this in a new isolate.
14325 isolate = v8::Isolate::New();
14328 // Verify that we get callbacks for existing code objects when we
14329 // request enumeration of existing code.
14331 v8::HandleScope scope(isolate);
14332 LocalContext env(isolate);
14333 CompileRun(script);
14335 // Now get code through initial iteration.
14336 i::HashMap code(MatchPointers);
14339 i::HashMap lineinfo(MatchPointers);
14340 jitcode_line_info = &lineinfo;
14342 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14343 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14345 jitcode_line_info = NULL;
14346 // We expect that we got some events. Note that if we could get code removal
14347 // notifications, we could compare two collections, one created by listening
14348 // from the time of creation of an isolate, and the other by subscribing
14349 // with EnumExisting.
14350 CHECK_LT(0, code.occupancy());
14356 isolate->Dispose();
14360 THREADED_TEST(ExternalAllocatedMemory) {
14361 v8::Isolate* isolate = CcTest::isolate();
14362 v8::HandleScope outer(isolate);
14363 v8::Local<Context> env(Context::New(isolate));
14364 CHECK(!env.IsEmpty());
14365 const int64_t kSize = 1024*1024;
14366 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14367 CHECK_EQ(baseline + kSize,
14368 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14370 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14374 // Regression test for issue 54, object templates with internal fields
14375 // but no accessors or interceptors did not get their internal field
14376 // count set on instances.
14377 THREADED_TEST(Regress54) {
14378 LocalContext context;
14379 v8::Isolate* isolate = context->GetIsolate();
14380 v8::HandleScope outer(isolate);
14381 static v8::Persistent<v8::ObjectTemplate> templ;
14382 if (templ.IsEmpty()) {
14383 v8::EscapableHandleScope inner(isolate);
14384 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14385 local->SetInternalFieldCount(1);
14386 templ.Reset(isolate, inner.Escape(local));
14388 v8::Handle<v8::Object> result =
14389 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14390 CHECK_EQ(1, result->InternalFieldCount());
14394 // If part of the threaded tests, this test makes ThreadingTest fail
14396 TEST(CatchStackOverflow) {
14397 LocalContext context;
14398 v8::HandleScope scope(context->GetIsolate());
14399 v8::TryCatch try_catch;
14400 v8::Handle<v8::Value> result = CompileRun(
14406 CHECK(result.IsEmpty());
14410 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14411 const char* resource_name,
14413 v8::HandleScope scope(CcTest::isolate());
14414 v8::TryCatch try_catch;
14415 v8::Handle<v8::Value> result = script->Run();
14416 CHECK(result.IsEmpty());
14417 CHECK(try_catch.HasCaught());
14418 v8::Handle<v8::Message> message = try_catch.Message();
14419 CHECK(!message.IsEmpty());
14420 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14421 CHECK_EQ(91, message->GetStartPosition());
14422 CHECK_EQ(92, message->GetEndPosition());
14423 CHECK_EQ(2, message->GetStartColumn());
14424 CHECK_EQ(3, message->GetEndColumn());
14425 v8::String::Utf8Value line(message->GetSourceLine());
14426 CHECK_EQ(" throw 'nirk';", *line);
14427 v8::String::Utf8Value name(message->GetScriptResourceName());
14428 CHECK_EQ(resource_name, *name);
14432 THREADED_TEST(TryCatchSourceInfo) {
14433 LocalContext context;
14434 v8::HandleScope scope(context->GetIsolate());
14435 v8::Local<v8::String> source = v8_str(
14436 "function Foo() {\n"
14440 "function Bar() {\n"
14444 "function Baz() {\n"
14450 const char* resource_name;
14451 v8::Handle<v8::Script> script;
14452 resource_name = "test.js";
14453 script = CompileWithOrigin(source, resource_name);
14454 CheckTryCatchSourceInfo(script, resource_name, 0);
14456 resource_name = "test1.js";
14457 v8::ScriptOrigin origin1(
14458 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14459 script = v8::Script::Compile(source, &origin1);
14460 CheckTryCatchSourceInfo(script, resource_name, 0);
14462 resource_name = "test2.js";
14463 v8::ScriptOrigin origin2(
14464 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14465 v8::Integer::New(context->GetIsolate(), 7));
14466 script = v8::Script::Compile(source, &origin2);
14467 CheckTryCatchSourceInfo(script, resource_name, 7);
14471 THREADED_TEST(CompilationCache) {
14472 LocalContext context;
14473 v8::HandleScope scope(context->GetIsolate());
14474 v8::Handle<v8::String> source0 =
14475 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14476 v8::Handle<v8::String> source1 =
14477 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14478 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14479 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14480 v8::Handle<v8::Script> script2 =
14481 v8::Script::Compile(source0); // different origin
14482 CHECK_EQ(1234, script0->Run()->Int32Value());
14483 CHECK_EQ(1234, script1->Run()->Int32Value());
14484 CHECK_EQ(1234, script2->Run()->Int32Value());
14488 static void FunctionNameCallback(
14489 const v8::FunctionCallbackInfo<v8::Value>& args) {
14490 ApiTestFuzzer::Fuzz();
14491 args.GetReturnValue().Set(v8_num(42));
14495 THREADED_TEST(CallbackFunctionName) {
14496 LocalContext context;
14497 v8::Isolate* isolate = context->GetIsolate();
14498 v8::HandleScope scope(isolate);
14499 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14500 t->Set(v8_str("asdf"),
14501 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14502 context->Global()->Set(v8_str("obj"), t->NewInstance());
14503 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14504 CHECK(value->IsString());
14505 v8::String::Utf8Value name(value);
14506 CHECK_EQ("asdf", *name);
14510 THREADED_TEST(DateAccess) {
14511 LocalContext context;
14512 v8::HandleScope scope(context->GetIsolate());
14513 v8::Handle<v8::Value> date =
14514 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14515 CHECK(date->IsDate());
14516 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14520 void CheckProperties(v8::Isolate* isolate,
14521 v8::Handle<v8::Value> val,
14523 const char* elmv[]) {
14524 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14525 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14526 CHECK_EQ(elmc, props->Length());
14527 for (int i = 0; i < elmc; i++) {
14528 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14529 CHECK_EQ(elmv[i], *elm);
14534 void CheckOwnProperties(v8::Isolate* isolate,
14535 v8::Handle<v8::Value> val,
14537 const char* elmv[]) {
14538 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14539 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14540 CHECK_EQ(elmc, props->Length());
14541 for (int i = 0; i < elmc; i++) {
14542 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14543 CHECK_EQ(elmv[i], *elm);
14548 THREADED_TEST(PropertyEnumeration) {
14549 LocalContext context;
14550 v8::Isolate* isolate = context->GetIsolate();
14551 v8::HandleScope scope(isolate);
14552 v8::Handle<v8::Value> obj = CompileRun(
14555 "result[1] = {a: 1, b: 2};"
14556 "result[2] = [1, 2, 3];"
14557 "var proto = {x: 1, y: 2, z: 3};"
14558 "var x = { __proto__: proto, w: 0, z: 1 };"
14561 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14562 CHECK_EQ(4, elms->Length());
14564 const char** elmv0 = NULL;
14566 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14567 CheckOwnProperties(
14568 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14570 const char* elmv1[] = {"a", "b"};
14572 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14573 CheckOwnProperties(
14574 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14576 const char* elmv2[] = {"0", "1", "2"};
14578 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14579 CheckOwnProperties(
14580 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14582 const char* elmv3[] = {"w", "z", "x", "y"};
14584 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14586 const char* elmv4[] = {"w", "z"};
14587 CheckOwnProperties(
14588 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14592 THREADED_TEST(PropertyEnumeration2) {
14593 LocalContext context;
14594 v8::Isolate* isolate = context->GetIsolate();
14595 v8::HandleScope scope(isolate);
14596 v8::Handle<v8::Value> obj = CompileRun(
14599 "result[1] = {a: 1, b: 2};"
14600 "result[2] = [1, 2, 3];"
14601 "var proto = {x: 1, y: 2, z: 3};"
14602 "var x = { __proto__: proto, w: 0, z: 1 };"
14605 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14606 CHECK_EQ(4, elms->Length());
14608 const char** elmv0 = NULL;
14609 CheckProperties(isolate,
14610 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14612 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14613 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14614 CHECK_EQ(0, props->Length());
14615 for (uint32_t i = 0; i < props->Length(); i++) {
14616 printf("p[%d]\n", i);
14620 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14622 v8::AccessType type,
14623 Local<Value> data) {
14624 return type != v8::ACCESS_SET;
14628 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14630 v8::AccessType type,
14631 Local<Value> data) {
14632 return type != v8::ACCESS_SET;
14636 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14637 LocalContext context;
14638 v8::Isolate* isolate = context->GetIsolate();
14639 v8::HandleScope scope(isolate);
14640 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14641 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14642 IndexedSetAccessBlocker);
14643 templ->Set(v8_str("x"), v8::True(isolate));
14644 Local<v8::Object> instance = templ->NewInstance();
14645 context->Global()->Set(v8_str("obj"), instance);
14646 Local<Value> value = CompileRun("obj.x");
14647 CHECK(value->BooleanValue());
14651 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14653 v8::AccessType type,
14654 Local<Value> data) {
14659 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14661 v8::AccessType type,
14662 Local<Value> data) {
14668 THREADED_TEST(AccessChecksReenabledCorrectly) {
14669 LocalContext context;
14670 v8::Isolate* isolate = context->GetIsolate();
14671 v8::HandleScope scope(isolate);
14672 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14673 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14674 IndexedGetAccessBlocker);
14675 templ->Set(v8_str("a"), v8_str("a"));
14676 // Add more than 8 (see kMaxFastProperties) properties
14677 // so that the constructor will force copying map.
14678 // Cannot sprintf, gcc complains unsafety.
14680 for (char i = '0'; i <= '9' ; i++) {
14682 for (char j = '0'; j <= '9'; j++) {
14684 for (char k = '0'; k <= '9'; k++) {
14687 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14692 Local<v8::Object> instance_1 = templ->NewInstance();
14693 context->Global()->Set(v8_str("obj_1"), instance_1);
14695 Local<Value> value_1 = CompileRun("obj_1.a");
14696 CHECK(value_1->IsUndefined());
14698 Local<v8::Object> instance_2 = templ->NewInstance();
14699 context->Global()->Set(v8_str("obj_2"), instance_2);
14701 Local<Value> value_2 = CompileRun("obj_2.a");
14702 CHECK(value_2->IsUndefined());
14706 // This tests that access check information remains on the global
14707 // object template when creating contexts.
14708 THREADED_TEST(AccessControlRepeatedContextCreation) {
14709 v8::Isolate* isolate = CcTest::isolate();
14710 v8::HandleScope handle_scope(isolate);
14711 v8::Handle<v8::ObjectTemplate> global_template =
14712 v8::ObjectTemplate::New(isolate);
14713 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14714 IndexedSetAccessBlocker);
14715 i::Handle<i::ObjectTemplateInfo> internal_template =
14716 v8::Utils::OpenHandle(*global_template);
14717 CHECK(!internal_template->constructor()->IsUndefined());
14718 i::Handle<i::FunctionTemplateInfo> constructor(
14719 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14720 CHECK(!constructor->access_check_info()->IsUndefined());
14721 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14722 CHECK(!context0.IsEmpty());
14723 CHECK(!constructor->access_check_info()->IsUndefined());
14727 THREADED_TEST(TurnOnAccessCheck) {
14728 v8::Isolate* isolate = CcTest::isolate();
14729 v8::HandleScope handle_scope(isolate);
14731 // Create an environment with access check to the global object disabled by
14733 v8::Handle<v8::ObjectTemplate> global_template =
14734 v8::ObjectTemplate::New(isolate);
14735 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14736 IndexedGetAccessBlocker,
14737 v8::Handle<v8::Value>(),
14739 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14740 Context::Scope context_scope(context);
14742 // Set up a property and a number of functions.
14743 context->Global()->Set(v8_str("a"), v8_num(1));
14744 CompileRun("function f1() {return a;}"
14745 "function f2() {return a;}"
14746 "function g1() {return h();}"
14747 "function g2() {return h();}"
14748 "function h() {return 1;}");
14749 Local<Function> f1 =
14750 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14751 Local<Function> f2 =
14752 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14753 Local<Function> g1 =
14754 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14755 Local<Function> g2 =
14756 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14757 Local<Function> h =
14758 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14760 // Get the global object.
14761 v8::Handle<v8::Object> global = context->Global();
14763 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14764 // uses the runtime system to retreive property a whereas f2 uses global load
14766 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14767 for (int i = 0; i < 4; i++) {
14768 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14771 // Same for g1 and g2.
14772 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14773 for (int i = 0; i < 4; i++) {
14774 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14777 // Detach the global and turn on access check.
14778 Local<Object> hidden_global = Local<Object>::Cast(
14779 context->Global()->GetPrototype());
14780 context->DetachGlobal();
14781 hidden_global->TurnOnAccessCheck();
14783 // Failing access check to property get results in undefined.
14784 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14785 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14787 // Failing access check to function call results in exception.
14788 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14789 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14791 // No failing access check when just returning a constant.
14792 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14796 static const char* kPropertyA = "a";
14797 static const char* kPropertyH = "h";
14799 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14801 v8::AccessType type,
14802 Local<Value> data) {
14803 if (!name->IsString()) return false;
14804 i::Handle<i::String> name_handle =
14805 v8::Utils::OpenHandle(String::Cast(*name));
14806 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14807 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14811 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14812 v8::Isolate* isolate = CcTest::isolate();
14813 v8::HandleScope handle_scope(isolate);
14815 // Create an environment with access check to the global object disabled by
14816 // default. When the registered access checker will block access to properties
14818 v8::Handle<v8::ObjectTemplate> global_template =
14819 v8::ObjectTemplate::New(isolate);
14820 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14821 IndexedGetAccessBlocker,
14822 v8::Handle<v8::Value>(),
14824 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14825 Context::Scope context_scope(context);
14827 // Set up a property and a number of functions.
14828 context->Global()->Set(v8_str("a"), v8_num(1));
14829 static const char* source = "function f1() {return a;}"
14830 "function f2() {return a;}"
14831 "function g1() {return h();}"
14832 "function g2() {return h();}"
14833 "function h() {return 1;}";
14835 CompileRun(source);
14836 Local<Function> f1;
14837 Local<Function> f2;
14838 Local<Function> g1;
14839 Local<Function> g2;
14841 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14842 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14843 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14844 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14845 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14847 // Get the global object.
14848 v8::Handle<v8::Object> global = context->Global();
14850 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14851 // uses the runtime system to retreive property a whereas f2 uses global load
14853 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14854 for (int i = 0; i < 4; i++) {
14855 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14858 // Same for g1 and g2.
14859 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14860 for (int i = 0; i < 4; i++) {
14861 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14864 // Detach the global and turn on access check now blocking access to property
14865 // a and function h.
14866 Local<Object> hidden_global = Local<Object>::Cast(
14867 context->Global()->GetPrototype());
14868 context->DetachGlobal();
14869 hidden_global->TurnOnAccessCheck();
14871 // Failing access check to property get results in undefined.
14872 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14873 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14875 // Failing access check to function call results in exception.
14876 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14877 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14879 // No failing access check when just returning a constant.
14880 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14882 // Now compile the source again. And get the newly compiled functions, except
14883 // for h for which access is blocked.
14884 CompileRun(source);
14885 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14886 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14887 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14888 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14889 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14891 // Failing access check to property get results in undefined.
14892 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14893 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14895 // Failing access check to function call results in exception.
14896 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14897 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14901 // Tests that ScriptData can be serialized and deserialized.
14902 TEST(PreCompileSerialization) {
14903 v8::V8::Initialize();
14905 v8::Isolate* isolate = env->GetIsolate();
14906 HandleScope handle_scope(isolate);
14908 i::FLAG_min_preparse_length = 0;
14909 const char* script = "function foo(a) { return a+1; }";
14910 v8::ScriptCompiler::Source source(v8_str(script));
14911 v8::ScriptCompiler::Compile(isolate, &source,
14912 v8::ScriptCompiler::kProduceDataToCache);
14914 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14915 char* serialized_data = i::NewArray<char>(cd->length);
14916 i::MemCopy(serialized_data, cd->data, cd->length);
14919 i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
14921 // Verify that the original is the same as the deserialized.
14922 CHECK_EQ(cd->length, deserialized->Length());
14923 CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
14925 delete deserialized;
14926 i::DeleteArray(serialized_data);
14930 // Attempts to deserialize bad data.
14931 TEST(PreCompileDeserializationError) {
14932 v8::V8::Initialize();
14933 const char* data = "DONT CARE";
14934 int invalid_size = 3;
14935 i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
14936 CHECK_EQ(NULL, sd);
14940 TEST(CompileWithInvalidCachedData) {
14941 v8::V8::Initialize();
14942 v8::Isolate* isolate = CcTest::isolate();
14943 LocalContext context;
14944 v8::HandleScope scope(context->GetIsolate());
14945 i::FLAG_min_preparse_length = 0;
14947 const char* script = "function foo(){ return 5;}\n"
14948 "function bar(){ return 6 + 7;} foo();";
14949 v8::ScriptCompiler::Source source(v8_str(script));
14950 v8::ScriptCompiler::Compile(isolate, &source,
14951 v8::ScriptCompiler::kProduceDataToCache);
14952 // source owns its cached data. Create a ScriptData based on it. The user
14953 // never needs to create ScriptDatas any more; we only need it here because we
14954 // want to modify the data before passing it back.
14955 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14956 // ScriptData does not take ownership of the buffers passed to it.
14957 i::ScriptData* sd =
14958 i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14959 CHECK(!sd->HasError());
14960 // ScriptData private implementation details
14961 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14962 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14963 const int kFunctionEntryStartOffset = 0;
14964 const int kFunctionEntryEndOffset = 1;
14965 unsigned* sd_data =
14966 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14968 // Overwrite function bar's end position with 0.
14969 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14970 v8::TryCatch try_catch;
14972 // Make the script slightly different so that we don't hit the compilation
14973 // cache. Don't change the lenghts of tokens.
14974 const char* script2 = "function foo(){ return 6;}\n"
14975 "function bar(){ return 6 + 7;} foo();";
14976 v8::ScriptCompiler::Source source2(
14978 // CachedData doesn't take ownership of the buffers, Source takes
14979 // ownership of CachedData.
14980 new v8::ScriptCompiler::CachedData(
14981 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14982 Local<v8::UnboundScript> compiled_script =
14983 v8::ScriptCompiler::CompileUnbound(isolate, &source2);
14985 CHECK(try_catch.HasCaught());
14987 String::Utf8Value exception_value(try_catch.Message()->Get());
14988 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14995 // Overwrite function bar's start position with 200. The function entry will
14996 // not be found when searching for it by position, and the compilation fails.
14998 // ScriptData does not take ownership of the buffers passed to it.
14999 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15000 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
15001 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
15003 const char* script3 = "function foo(){ return 7;}\n"
15004 "function bar(){ return 6 + 7;} foo();";
15005 v8::ScriptCompiler::Source source3(
15007 new v8::ScriptCompiler::CachedData(
15008 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
15010 v8::ScriptCompiler::CompileUnbound(isolate, &source3);
15011 CHECK(try_catch.HasCaught());
15013 String::Utf8Value exception_value(try_catch.Message()->Get());
15014 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
15017 CHECK(compiled_script.IsEmpty());
15021 // Try passing in cached data which is obviously invalid (wrong length).
15022 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15023 const char* script4 =
15024 "function foo(){ return 8;}\n"
15025 "function bar(){ return 6 + 7;} foo();";
15026 v8::ScriptCompiler::Source source4(
15028 new v8::ScriptCompiler::CachedData(
15029 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
15031 v8::ScriptCompiler::CompileUnbound(isolate, &source4);
15032 CHECK(try_catch.HasCaught());
15034 String::Utf8Value exception_value(try_catch.Message()->Get());
15035 CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
15038 CHECK(compiled_script.IsEmpty());
15043 // This tests that we do not allow dictionary load/call inline caches
15044 // to use functions that have not yet been compiled. The potential
15045 // problem of loading a function that has not yet been compiled can
15046 // arise because we share code between contexts via the compilation
15048 THREADED_TEST(DictionaryICLoadedFunction) {
15049 v8::HandleScope scope(CcTest::isolate());
15051 for (int i = 0; i < 2; i++) {
15052 LocalContext context;
15053 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15054 context->Global()->Delete(v8_str("tmp"));
15055 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15058 for (int i = 0; i < 2; i++) {
15059 LocalContext context;
15060 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15061 context->Global()->Delete(v8_str("tmp"));
15062 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15067 // Test that cross-context new calls use the context of the callee to
15068 // create the new JavaScript object.
15069 THREADED_TEST(CrossContextNew) {
15070 v8::Isolate* isolate = CcTest::isolate();
15071 v8::HandleScope scope(isolate);
15072 v8::Local<Context> context0 = Context::New(isolate);
15073 v8::Local<Context> context1 = Context::New(isolate);
15075 // Allow cross-domain access.
15076 Local<String> token = v8_str("<security token>");
15077 context0->SetSecurityToken(token);
15078 context1->SetSecurityToken(token);
15080 // Set an 'x' property on the Object prototype and define a
15081 // constructor function in context0.
15083 CompileRun("Object.prototype.x = 42; function C() {};");
15086 // Call the constructor function from context0 and check that the
15087 // result has the 'x' property.
15089 context1->Global()->Set(v8_str("other"), context0->Global());
15090 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15091 CHECK(value->IsInt32());
15092 CHECK_EQ(42, value->Int32Value());
15097 // Verify that we can clone an object
15098 TEST(ObjectClone) {
15100 v8::Isolate* isolate = env->GetIsolate();
15101 v8::HandleScope scope(isolate);
15103 const char* sample =
15105 "rv.alpha = 'hello';" \
15109 // Create an object, verify basics.
15110 Local<Value> val = CompileRun(sample);
15111 CHECK(val->IsObject());
15112 Local<v8::Object> obj = val.As<v8::Object>();
15113 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15115 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15116 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15117 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15120 Local<v8::Object> clone = obj->Clone();
15121 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15122 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15123 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15125 // Set a property on the clone, verify each object.
15126 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15127 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15128 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15132 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15134 explicit AsciiVectorResource(i::Vector<const char> vector)
15136 virtual ~AsciiVectorResource() {}
15137 virtual size_t length() const { return data_.length(); }
15138 virtual const char* data() const { return data_.start(); }
15140 i::Vector<const char> data_;
15144 class UC16VectorResource : public v8::String::ExternalStringResource {
15146 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15148 virtual ~UC16VectorResource() {}
15149 virtual size_t length() const { return data_.length(); }
15150 virtual const i::uc16* data() const { return data_.start(); }
15152 i::Vector<const i::uc16> data_;
15156 static void MorphAString(i::String* string,
15157 AsciiVectorResource* ascii_resource,
15158 UC16VectorResource* uc16_resource) {
15159 CHECK(i::StringShape(string).IsExternal());
15160 if (string->IsOneByteRepresentation()) {
15161 // Check old map is not internalized or long.
15162 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15163 // Morph external string to be TwoByte string.
15164 string->set_map(CcTest::heap()->external_string_map());
15165 i::ExternalTwoByteString* morphed =
15166 i::ExternalTwoByteString::cast(string);
15167 morphed->set_resource(uc16_resource);
15169 // Check old map is not internalized or long.
15170 CHECK(string->map() == CcTest::heap()->external_string_map());
15171 // Morph external string to be ASCII string.
15172 string->set_map(CcTest::heap()->external_ascii_string_map());
15173 i::ExternalAsciiString* morphed =
15174 i::ExternalAsciiString::cast(string);
15175 morphed->set_resource(ascii_resource);
15180 // Test that we can still flatten a string if the components it is built up
15181 // from have been turned into 16 bit strings in the mean time.
15182 THREADED_TEST(MorphCompositeStringTest) {
15183 char utf_buffer[129];
15184 const char* c_string = "Now is the time for all good men"
15185 " to come to the aid of the party";
15186 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15189 i::Factory* factory = CcTest::i_isolate()->factory();
15190 v8::HandleScope scope(env->GetIsolate());
15191 AsciiVectorResource ascii_resource(
15192 i::Vector<const char>(c_string, i::StrLength(c_string)));
15193 UC16VectorResource uc16_resource(
15194 i::Vector<const uint16_t>(two_byte_string,
15195 i::StrLength(c_string)));
15197 Local<String> lhs(v8::Utils::ToLocal(
15198 factory->NewExternalStringFromAscii(&ascii_resource)
15199 .ToHandleChecked()));
15200 Local<String> rhs(v8::Utils::ToLocal(
15201 factory->NewExternalStringFromAscii(&ascii_resource)
15202 .ToHandleChecked()));
15204 env->Global()->Set(v8_str("lhs"), lhs);
15205 env->Global()->Set(v8_str("rhs"), rhs);
15208 "var cons = lhs + rhs;"
15209 "var slice = lhs.substring(1, lhs.length - 1);"
15210 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15212 CHECK(lhs->IsOneByte());
15213 CHECK(rhs->IsOneByte());
15215 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15216 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15218 // This should UTF-8 without flattening, since everything is ASCII.
15219 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15220 CHECK_EQ(128, cons->Utf8Length());
15222 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15223 CHECK_EQ(128, nchars);
15224 CHECK_EQ(0, strcmp(
15226 "Now is the time for all good men to come to the aid of the party"
15227 "Now is the time for all good men to come to the aid of the party"));
15229 // Now do some stuff to make sure the strings are flattened, etc.
15231 "/[^a-z]/.test(cons);"
15232 "/[^a-z]/.test(slice);"
15233 "/[^a-z]/.test(slice_on_cons);");
15234 const char* expected_cons =
15235 "Now is the time for all good men to come to the aid of the party"
15236 "Now is the time for all good men to come to the aid of the party";
15237 const char* expected_slice =
15238 "ow is the time for all good men to come to the aid of the part";
15239 const char* expected_slice_on_cons =
15240 "ow is the time for all good men to come to the aid of the party"
15241 "Now is the time for all good men to come to the aid of the part";
15242 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15243 env->Global()->Get(v8_str("cons")));
15244 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15245 env->Global()->Get(v8_str("slice")));
15246 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15247 env->Global()->Get(v8_str("slice_on_cons")));
15249 i::DeleteArray(two_byte_string);
15253 TEST(CompileExternalTwoByteSource) {
15254 LocalContext context;
15255 v8::HandleScope scope(context->GetIsolate());
15257 // This is a very short list of sources, which currently is to check for a
15258 // regression caused by r2703.
15259 const char* ascii_sources[] = {
15261 "-0.5", // This mainly testes PushBack in the Scanner.
15262 "--0.5", // This mainly testes PushBack in the Scanner.
15266 // Compile the sources as external two byte strings.
15267 for (int i = 0; ascii_sources[i] != NULL; i++) {
15268 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15269 TestResource* uc16_resource = new TestResource(two_byte_string);
15270 v8::Local<v8::String> source =
15271 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15272 v8::Script::Compile(source);
15277 #ifndef V8_INTERPRETED_REGEXP
15279 struct RegExpInterruptionData {
15281 UC16VectorResource* string_resource;
15282 v8::Persistent<v8::String> string;
15283 } regexp_interruption_data;
15286 class RegExpInterruptionThread : public i::Thread {
15288 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15289 : Thread("TimeoutThread"), isolate_(isolate) {}
15291 virtual void Run() {
15292 for (regexp_interruption_data.loop_count = 0;
15293 regexp_interruption_data.loop_count < 7;
15294 regexp_interruption_data.loop_count++) {
15295 i::OS::Sleep(50); // Wait a bit before requesting GC.
15296 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15298 i::OS::Sleep(50); // Wait a bit before terminating.
15299 v8::V8::TerminateExecution(isolate_);
15303 v8::Isolate* isolate_;
15307 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15308 if (regexp_interruption_data.loop_count != 2) return;
15309 v8::HandleScope scope(CcTest::isolate());
15310 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15311 CcTest::isolate(), regexp_interruption_data.string);
15312 string->MakeExternal(regexp_interruption_data.string_resource);
15316 // Test that RegExp execution can be interrupted. Specifically, we test
15317 // * interrupting with GC
15318 // * turn the subject string from one-byte internal to two-byte external string
15319 // * force termination
15320 TEST(RegExpInterruption) {
15321 v8::HandleScope scope(CcTest::isolate());
15324 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15326 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15327 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15328 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15329 v8::Local<v8::String> string = v8_str(ascii_content);
15331 CcTest::global()->Set(v8_str("a"), string);
15332 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15333 regexp_interruption_data.string_resource = new UC16VectorResource(
15334 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15336 v8::TryCatch try_catch;
15337 timeout_thread.Start();
15339 CompileRun("/((a*)*)*b/.exec(a)");
15340 CHECK(try_catch.HasTerminated());
15342 timeout_thread.Join();
15344 regexp_interruption_data.string.Reset();
15345 i::DeleteArray(uc16_content);
15348 #endif // V8_INTERPRETED_REGEXP
15351 // Test that we cannot set a property on the global object if there
15352 // is a read-only property in the prototype chain.
15353 TEST(ReadOnlyPropertyInGlobalProto) {
15354 v8::Isolate* isolate = CcTest::isolate();
15355 v8::HandleScope scope(isolate);
15356 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15357 LocalContext context(0, templ);
15358 v8::Handle<v8::Object> global = context->Global();
15359 v8::Handle<v8::Object> global_proto =
15360 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15361 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15362 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15363 // Check without 'eval' or 'with'.
15364 v8::Handle<v8::Value> res =
15365 CompileRun("function f() { x = 42; return x; }; f()");
15366 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15367 // Check with 'eval'.
15368 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15369 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15370 // Check with 'with'.
15371 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15372 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15375 static int force_set_set_count = 0;
15376 static int force_set_get_count = 0;
15377 bool pass_on_get = false;
15379 static void ForceSetGetter(v8::Local<v8::String> name,
15380 const v8::PropertyCallbackInfo<v8::Value>& info) {
15381 force_set_get_count++;
15385 info.GetReturnValue().Set(3);
15388 static void ForceSetSetter(v8::Local<v8::String> name,
15389 v8::Local<v8::Value> value,
15390 const v8::PropertyCallbackInfo<void>& info) {
15391 force_set_set_count++;
15394 static void ForceSetInterceptSetter(
15395 v8::Local<v8::String> name,
15396 v8::Local<v8::Value> value,
15397 const v8::PropertyCallbackInfo<v8::Value>& info) {
15398 force_set_set_count++;
15399 info.GetReturnValue().SetUndefined();
15404 force_set_get_count = 0;
15405 force_set_set_count = 0;
15406 pass_on_get = false;
15408 v8::Isolate* isolate = CcTest::isolate();
15409 v8::HandleScope scope(isolate);
15410 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15411 v8::Handle<v8::String> access_property =
15412 v8::String::NewFromUtf8(isolate, "a");
15413 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15414 LocalContext context(NULL, templ);
15415 v8::Handle<v8::Object> global = context->Global();
15417 // Ordinary properties
15418 v8::Handle<v8::String> simple_property =
15419 v8::String::NewFromUtf8(isolate, "p");
15420 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15421 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15422 // This should fail because the property is read-only
15423 global->Set(simple_property, v8::Int32::New(isolate, 5));
15424 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15425 // This should succeed even though the property is read-only
15426 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15427 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15430 CHECK_EQ(0, force_set_set_count);
15431 CHECK_EQ(0, force_set_get_count);
15432 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15433 // CHECK_EQ the property shouldn't override it, just call the setter
15434 // which in this case does nothing.
15435 global->Set(access_property, v8::Int32::New(isolate, 7));
15436 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15437 CHECK_EQ(1, force_set_set_count);
15438 CHECK_EQ(2, force_set_get_count);
15439 // Forcing the property to be set should override the accessor without
15441 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15442 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15443 CHECK_EQ(1, force_set_set_count);
15444 CHECK_EQ(2, force_set_get_count);
15448 TEST(ForceSetWithInterceptor) {
15449 force_set_get_count = 0;
15450 force_set_set_count = 0;
15451 pass_on_get = false;
15453 v8::Isolate* isolate = CcTest::isolate();
15454 v8::HandleScope scope(isolate);
15455 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15456 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15457 LocalContext context(NULL, templ);
15458 v8::Handle<v8::Object> global = context->Global();
15460 v8::Handle<v8::String> some_property =
15461 v8::String::NewFromUtf8(isolate, "a");
15462 CHECK_EQ(0, force_set_set_count);
15463 CHECK_EQ(0, force_set_get_count);
15464 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15465 // Setting the property shouldn't override it, just call the setter
15466 // which in this case does nothing.
15467 global->Set(some_property, v8::Int32::New(isolate, 7));
15468 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15469 CHECK_EQ(1, force_set_set_count);
15470 CHECK_EQ(2, force_set_get_count);
15471 // Getting the property when the interceptor returns an empty handle
15472 // should yield undefined, since the property isn't present on the
15473 // object itself yet.
15474 pass_on_get = true;
15475 CHECK(global->Get(some_property)->IsUndefined());
15476 CHECK_EQ(1, force_set_set_count);
15477 CHECK_EQ(3, force_set_get_count);
15478 // Forcing the property to be set should cause the value to be
15479 // set locally without calling the interceptor.
15480 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15481 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15482 CHECK_EQ(1, force_set_set_count);
15483 CHECK_EQ(4, force_set_get_count);
15484 // Reenabling the interceptor should cause it to take precedence over
15486 pass_on_get = false;
15487 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15488 CHECK_EQ(1, force_set_set_count);
15489 CHECK_EQ(5, force_set_get_count);
15490 // The interceptor should also work for other properties
15491 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15493 CHECK_EQ(1, force_set_set_count);
15494 CHECK_EQ(6, force_set_get_count);
15498 THREADED_TEST(ForceDelete) {
15499 v8::Isolate* isolate = CcTest::isolate();
15500 v8::HandleScope scope(isolate);
15501 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15502 LocalContext context(NULL, templ);
15503 v8::Handle<v8::Object> global = context->Global();
15505 // Ordinary properties
15506 v8::Handle<v8::String> simple_property =
15507 v8::String::NewFromUtf8(isolate, "p");
15508 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15509 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15510 // This should fail because the property is dont-delete.
15511 CHECK(!global->Delete(simple_property));
15512 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15513 // This should succeed even though the property is dont-delete.
15514 CHECK(global->ForceDelete(simple_property));
15515 CHECK(global->Get(simple_property)->IsUndefined());
15519 static int force_delete_interceptor_count = 0;
15520 static bool pass_on_delete = false;
15523 static void ForceDeleteDeleter(
15524 v8::Local<v8::String> name,
15525 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15526 force_delete_interceptor_count++;
15527 if (pass_on_delete) return;
15528 info.GetReturnValue().Set(true);
15532 THREADED_TEST(ForceDeleteWithInterceptor) {
15533 force_delete_interceptor_count = 0;
15534 pass_on_delete = false;
15536 v8::Isolate* isolate = CcTest::isolate();
15537 v8::HandleScope scope(isolate);
15538 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15539 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15540 LocalContext context(NULL, templ);
15541 v8::Handle<v8::Object> global = context->Global();
15543 v8::Handle<v8::String> some_property =
15544 v8::String::NewFromUtf8(isolate, "a");
15545 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15547 // Deleting a property should get intercepted and nothing should
15549 CHECK_EQ(0, force_delete_interceptor_count);
15550 CHECK(global->Delete(some_property));
15551 CHECK_EQ(1, force_delete_interceptor_count);
15552 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15553 // Deleting the property when the interceptor returns an empty
15554 // handle should not delete the property since it is DontDelete.
15555 pass_on_delete = true;
15556 CHECK(!global->Delete(some_property));
15557 CHECK_EQ(2, force_delete_interceptor_count);
15558 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15559 // Forcing the property to be deleted should delete the value
15560 // without calling the interceptor.
15561 CHECK(global->ForceDelete(some_property));
15562 CHECK(global->Get(some_property)->IsUndefined());
15563 CHECK_EQ(2, force_delete_interceptor_count);
15567 // Make sure that forcing a delete invalidates any IC stubs, so we
15568 // don't read the hole value.
15569 THREADED_TEST(ForceDeleteIC) {
15570 LocalContext context;
15571 v8::HandleScope scope(context->GetIsolate());
15572 // Create a DontDelete variable on the global object.
15573 CompileRun("this.__proto__ = { foo: 'horse' };"
15574 "var foo = 'fish';"
15575 "function f() { return foo.length; }");
15576 // Initialize the IC for foo in f.
15577 CompileRun("for (var i = 0; i < 4; i++) f();");
15578 // Make sure the value of foo is correct before the deletion.
15579 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15580 // Force the deletion of foo.
15581 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15582 // Make sure the value for foo is read from the prototype, and that
15583 // we don't get in trouble with reading the deleted cell value
15585 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15589 TEST(InlinedFunctionAcrossContexts) {
15590 i::FLAG_allow_natives_syntax = true;
15591 v8::Isolate* isolate = CcTest::isolate();
15592 v8::HandleScope outer_scope(isolate);
15593 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15594 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15598 v8::HandleScope inner_scope(CcTest::isolate());
15599 CompileRun("var G = 42; function foo() { return G; }");
15600 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15602 ctx2->Global()->Set(v8_str("o"), foo);
15603 v8::Local<v8::Value> res = CompileRun(
15604 "function f() { return o(); }"
15605 "for (var i = 0; i < 10; ++i) f();"
15606 "%OptimizeFunctionOnNextCall(f);"
15608 CHECK_EQ(42, res->Int32Value());
15610 v8::Handle<v8::String> G_property =
15611 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15612 CHECK(ctx1->Global()->ForceDelete(G_property));
15619 " return e.toString();"
15622 "ReferenceError: G is not defined");
15629 static v8::Local<Context> calling_context0;
15630 static v8::Local<Context> calling_context1;
15631 static v8::Local<Context> calling_context2;
15634 // Check that the call to the callback is initiated in
15635 // calling_context2, the directly calling context is calling_context1
15636 // and the callback itself is in calling_context0.
15637 static void GetCallingContextCallback(
15638 const v8::FunctionCallbackInfo<v8::Value>& args) {
15639 ApiTestFuzzer::Fuzz();
15640 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15641 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15642 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15643 args.GetReturnValue().Set(42);
15647 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15648 i::Isolate* isolate = CcTest::i_isolate();
15649 CHECK(isolate != NULL);
15650 CHECK(isolate->context() == NULL);
15651 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15652 v8::HandleScope scope(v8_isolate);
15653 // The following should not crash, but return an empty handle.
15654 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15655 CHECK(current.IsEmpty());
15659 THREADED_TEST(GetCallingContext) {
15660 v8::Isolate* isolate = CcTest::isolate();
15661 v8::HandleScope scope(isolate);
15663 Local<Context> calling_context0(Context::New(isolate));
15664 Local<Context> calling_context1(Context::New(isolate));
15665 Local<Context> calling_context2(Context::New(isolate));
15666 ::calling_context0 = calling_context0;
15667 ::calling_context1 = calling_context1;
15668 ::calling_context2 = calling_context2;
15670 // Allow cross-domain access.
15671 Local<String> token = v8_str("<security token>");
15672 calling_context0->SetSecurityToken(token);
15673 calling_context1->SetSecurityToken(token);
15674 calling_context2->SetSecurityToken(token);
15676 // Create an object with a C++ callback in context0.
15677 calling_context0->Enter();
15678 Local<v8::FunctionTemplate> callback_templ =
15679 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15680 calling_context0->Global()->Set(v8_str("callback"),
15681 callback_templ->GetFunction());
15682 calling_context0->Exit();
15684 // Expose context0 in context1 and set up a function that calls the
15685 // callback function.
15686 calling_context1->Enter();
15687 calling_context1->Global()->Set(v8_str("context0"),
15688 calling_context0->Global());
15689 CompileRun("function f() { context0.callback() }");
15690 calling_context1->Exit();
15692 // Expose context1 in context2 and call the callback function in
15693 // context0 indirectly through f in context1.
15694 calling_context2->Enter();
15695 calling_context2->Global()->Set(v8_str("context1"),
15696 calling_context1->Global());
15697 CompileRun("context1.f()");
15698 calling_context2->Exit();
15699 ::calling_context0.Clear();
15700 ::calling_context1.Clear();
15701 ::calling_context2.Clear();
15705 // Check that a variable declaration with no explicit initialization
15706 // value does shadow an existing property in the prototype chain.
15707 THREADED_TEST(InitGlobalVarInProtoChain) {
15708 LocalContext context;
15709 v8::HandleScope scope(context->GetIsolate());
15710 // Introduce a variable in the prototype chain.
15711 CompileRun("__proto__.x = 42");
15712 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15713 CHECK(!result->IsUndefined());
15714 CHECK_EQ(43, result->Int32Value());
15718 // Regression test for issue 398.
15719 // If a function is added to an object, creating a constant function
15720 // field, and the result is cloned, replacing the constant function on the
15721 // original should not affect the clone.
15722 // See http://code.google.com/p/v8/issues/detail?id=398
15723 THREADED_TEST(ReplaceConstantFunction) {
15724 LocalContext context;
15725 v8::Isolate* isolate = context->GetIsolate();
15726 v8::HandleScope scope(isolate);
15727 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15728 v8::Handle<v8::FunctionTemplate> func_templ =
15729 v8::FunctionTemplate::New(isolate);
15730 v8::Handle<v8::String> foo_string =
15731 v8::String::NewFromUtf8(isolate, "foo");
15732 obj->Set(foo_string, func_templ->GetFunction());
15733 v8::Handle<v8::Object> obj_clone = obj->Clone();
15734 obj_clone->Set(foo_string,
15735 v8::String::NewFromUtf8(isolate, "Hello"));
15736 CHECK(!obj->Get(foo_string)->IsUndefined());
15740 static void CheckElementValue(i::Isolate* isolate,
15742 i::Handle<i::Object> obj,
15744 i::Object* element =
15745 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15746 CHECK_EQ(expected, i::Smi::cast(element)->value());
15750 THREADED_TEST(PixelArray) {
15751 LocalContext context;
15752 i::Isolate* isolate = CcTest::i_isolate();
15753 i::Factory* factory = isolate->factory();
15754 v8::HandleScope scope(context->GetIsolate());
15755 const int kElementCount = 260;
15756 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15757 i::Handle<i::ExternalUint8ClampedArray> pixels =
15758 i::Handle<i::ExternalUint8ClampedArray>::cast(
15759 factory->NewExternalArray(kElementCount,
15760 v8::kExternalUint8ClampedArray,
15762 // Force GC to trigger verification.
15763 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15764 for (int i = 0; i < kElementCount; i++) {
15765 pixels->set(i, i % 256);
15767 // Force GC to trigger verification.
15768 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15769 for (int i = 0; i < kElementCount; i++) {
15770 CHECK_EQ(i % 256, pixels->get_scalar(i));
15771 CHECK_EQ(i % 256, pixel_data[i]);
15774 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15775 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15776 // Set the elements to be the pixels.
15777 // jsobj->set_elements(*pixels);
15778 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15779 CheckElementValue(isolate, 1, jsobj, 1);
15780 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15781 context->Global()->Set(v8_str("pixels"), obj);
15782 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15783 CHECK_EQ(1503, result->Int32Value());
15784 result = CompileRun("pixels[1]");
15785 CHECK_EQ(1, result->Int32Value());
15787 result = CompileRun("var sum = 0;"
15788 "for (var i = 0; i < 8; i++) {"
15789 " sum += pixels[i] = pixels[i] = -i;"
15792 CHECK_EQ(-28, result->Int32Value());
15794 result = CompileRun("var sum = 0;"
15795 "for (var i = 0; i < 8; i++) {"
15796 " sum += pixels[i] = pixels[i] = 0;"
15799 CHECK_EQ(0, result->Int32Value());
15801 result = CompileRun("var sum = 0;"
15802 "for (var i = 0; i < 8; i++) {"
15803 " sum += pixels[i] = pixels[i] = 255;"
15806 CHECK_EQ(8 * 255, result->Int32Value());
15808 result = CompileRun("var sum = 0;"
15809 "for (var i = 0; i < 8; i++) {"
15810 " sum += pixels[i] = pixels[i] = 256 + i;"
15813 CHECK_EQ(2076, result->Int32Value());
15815 result = CompileRun("var sum = 0;"
15816 "for (var i = 0; i < 8; i++) {"
15817 " sum += pixels[i] = pixels[i] = i;"
15820 CHECK_EQ(28, result->Int32Value());
15822 result = CompileRun("var sum = 0;"
15823 "for (var i = 0; i < 8; i++) {"
15824 " sum += pixels[i];"
15827 CHECK_EQ(28, result->Int32Value());
15829 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15830 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15831 i::Handle<i::Object> no_failure;
15832 no_failure = i::JSObject::SetElement(
15833 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15834 ASSERT(!no_failure.is_null());
15836 CheckElementValue(isolate, 2, jsobj, 1);
15837 *value.location() = i::Smi::FromInt(256);
15838 no_failure = i::JSObject::SetElement(
15839 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15840 ASSERT(!no_failure.is_null());
15842 CheckElementValue(isolate, 255, jsobj, 1);
15843 *value.location() = i::Smi::FromInt(-1);
15844 no_failure = i::JSObject::SetElement(
15845 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15846 ASSERT(!no_failure.is_null());
15848 CheckElementValue(isolate, 0, jsobj, 1);
15850 result = CompileRun("for (var i = 0; i < 8; i++) {"
15851 " pixels[i] = (i * 65) - 109;"
15853 "pixels[1] + pixels[6];");
15854 CHECK_EQ(255, result->Int32Value());
15855 CheckElementValue(isolate, 0, jsobj, 0);
15856 CheckElementValue(isolate, 0, jsobj, 1);
15857 CheckElementValue(isolate, 21, jsobj, 2);
15858 CheckElementValue(isolate, 86, jsobj, 3);
15859 CheckElementValue(isolate, 151, jsobj, 4);
15860 CheckElementValue(isolate, 216, jsobj, 5);
15861 CheckElementValue(isolate, 255, jsobj, 6);
15862 CheckElementValue(isolate, 255, jsobj, 7);
15863 result = CompileRun("var sum = 0;"
15864 "for (var i = 0; i < 8; i++) {"
15865 " sum += pixels[i];"
15868 CHECK_EQ(984, result->Int32Value());
15870 result = CompileRun("for (var i = 0; i < 8; i++) {"
15871 " pixels[i] = (i * 1.1);"
15873 "pixels[1] + pixels[6];");
15874 CHECK_EQ(8, result->Int32Value());
15875 CheckElementValue(isolate, 0, jsobj, 0);
15876 CheckElementValue(isolate, 1, jsobj, 1);
15877 CheckElementValue(isolate, 2, jsobj, 2);
15878 CheckElementValue(isolate, 3, jsobj, 3);
15879 CheckElementValue(isolate, 4, jsobj, 4);
15880 CheckElementValue(isolate, 6, jsobj, 5);
15881 CheckElementValue(isolate, 7, jsobj, 6);
15882 CheckElementValue(isolate, 8, jsobj, 7);
15884 result = CompileRun("for (var i = 0; i < 8; i++) {"
15885 " pixels[7] = undefined;"
15888 CHECK_EQ(0, result->Int32Value());
15889 CheckElementValue(isolate, 0, jsobj, 7);
15891 result = CompileRun("for (var i = 0; i < 8; i++) {"
15892 " pixels[6] = '2.3';"
15895 CHECK_EQ(2, result->Int32Value());
15896 CheckElementValue(isolate, 2, jsobj, 6);
15898 result = CompileRun("for (var i = 0; i < 8; i++) {"
15899 " pixels[5] = NaN;"
15902 CHECK_EQ(0, result->Int32Value());
15903 CheckElementValue(isolate, 0, jsobj, 5);
15905 result = CompileRun("for (var i = 0; i < 8; i++) {"
15906 " pixels[8] = Infinity;"
15909 CHECK_EQ(255, result->Int32Value());
15910 CheckElementValue(isolate, 255, jsobj, 8);
15912 result = CompileRun("for (var i = 0; i < 8; i++) {"
15913 " pixels[9] = -Infinity;"
15916 CHECK_EQ(0, result->Int32Value());
15917 CheckElementValue(isolate, 0, jsobj, 9);
15919 result = CompileRun("pixels[3] = 33;"
15920 "delete pixels[3];"
15922 CHECK_EQ(33, result->Int32Value());
15924 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15925 "pixels[2] = 12; pixels[3] = 13;"
15926 "pixels.__defineGetter__('2',"
15927 "function() { return 120; });"
15929 CHECK_EQ(12, result->Int32Value());
15931 result = CompileRun("var js_array = new Array(40);"
15932 "js_array[0] = 77;"
15934 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15936 result = CompileRun("pixels[1] = 23;"
15937 "pixels.__proto__ = [];"
15938 "js_array.__proto__ = pixels;"
15939 "js_array.concat(pixels);");
15940 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15941 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15943 result = CompileRun("pixels[1] = 23;");
15944 CHECK_EQ(23, result->Int32Value());
15946 // Test for index greater than 255. Regression test for:
15947 // http://code.google.com/p/chromium/issues/detail?id=26337.
15948 result = CompileRun("pixels[256] = 255;");
15949 CHECK_EQ(255, result->Int32Value());
15950 result = CompileRun("var i = 0;"
15951 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15953 CHECK_EQ(255, result->Int32Value());
15955 // Make sure that pixel array ICs recognize when a non-pixel array
15956 // is passed to it.
15957 result = CompileRun("function pa_load(p) {"
15959 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15962 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15963 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15964 "just_ints = new Object();"
15965 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15966 "for (var i = 0; i < 10; ++i) {"
15967 " result = pa_load(just_ints);"
15970 CHECK_EQ(32640, result->Int32Value());
15972 // Make sure that pixel array ICs recognize out-of-bound accesses.
15973 result = CompileRun("function pa_load(p, start) {"
15975 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15978 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15979 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15980 "for (var i = 0; i < 10; ++i) {"
15981 " result = pa_load(pixels,-10);"
15984 CHECK_EQ(0, result->Int32Value());
15986 // Make sure that generic ICs properly handles a pixel array.
15987 result = CompileRun("function pa_load(p) {"
15989 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15992 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15993 "just_ints = new Object();"
15994 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15995 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15996 "for (var i = 0; i < 10; ++i) {"
15997 " result = pa_load(pixels);"
16000 CHECK_EQ(32640, result->Int32Value());
16002 // Make sure that generic load ICs recognize out-of-bound accesses in
16004 result = CompileRun("function pa_load(p, start) {"
16006 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16009 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16010 "just_ints = new Object();"
16011 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16012 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16013 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16014 "for (var i = 0; i < 10; ++i) {"
16015 " result = pa_load(pixels,-10);"
16018 CHECK_EQ(0, result->Int32Value());
16020 // Make sure that generic ICs properly handles other types than pixel
16021 // arrays (that the inlined fast pixel array test leaves the right information
16022 // in the right registers).
16023 result = CompileRun("function pa_load(p) {"
16025 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16028 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16029 "just_ints = new Object();"
16030 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16031 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16032 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16033 "sparse_array = new Object();"
16034 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16035 "sparse_array[1000000] = 3;"
16036 "for (var i = 0; i < 10; ++i) {"
16037 " result = pa_load(sparse_array);"
16040 CHECK_EQ(32640, result->Int32Value());
16042 // Make sure that pixel array store ICs clamp values correctly.
16043 result = CompileRun("function pa_store(p) {"
16044 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16046 "pa_store(pixels);"
16048 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16050 CHECK_EQ(48896, result->Int32Value());
16052 // Make sure that pixel array stores correctly handle accesses outside
16053 // of the pixel array..
16054 result = CompileRun("function pa_store(p,start) {"
16055 " for (var j = 0; j < 256; j++) {"
16056 " p[j+start] = j * 2;"
16059 "pa_store(pixels,0);"
16060 "pa_store(pixels,-128);"
16062 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16064 CHECK_EQ(65280, result->Int32Value());
16066 // Make sure that the generic store stub correctly handle accesses outside
16067 // of the pixel array..
16068 result = CompileRun("function pa_store(p,start) {"
16069 " for (var j = 0; j < 256; j++) {"
16070 " p[j+start] = j * 2;"
16073 "pa_store(pixels,0);"
16074 "just_ints = new Object();"
16075 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16076 "pa_store(just_ints, 0);"
16077 "pa_store(pixels,-128);"
16079 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16081 CHECK_EQ(65280, result->Int32Value());
16083 // Make sure that the generic keyed store stub clamps pixel array values
16085 result = CompileRun("function pa_store(p) {"
16086 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16088 "pa_store(pixels);"
16089 "just_ints = new Object();"
16090 "pa_store(just_ints);"
16091 "pa_store(pixels);"
16093 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16095 CHECK_EQ(48896, result->Int32Value());
16097 // Make sure that pixel array loads are optimized by crankshaft.
16098 result = CompileRun("function pa_load(p) {"
16100 " for (var i=0; i<256; ++i) {"
16105 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16106 "for (var i = 0; i < 5000; ++i) {"
16107 " result = pa_load(pixels);"
16110 CHECK_EQ(32640, result->Int32Value());
16112 // Make sure that pixel array stores are optimized by crankshaft.
16113 result = CompileRun("function pa_init(p) {"
16114 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16116 "function pa_load(p) {"
16118 " for (var i=0; i<256; ++i) {"
16123 "for (var i = 0; i < 5000; ++i) {"
16124 " pa_init(pixels);"
16126 "result = pa_load(pixels);"
16128 CHECK_EQ(32640, result->Int32Value());
16134 THREADED_TEST(PixelArrayInfo) {
16135 LocalContext context;
16136 v8::HandleScope scope(context->GetIsolate());
16137 for (int size = 0; size < 100; size += 10) {
16138 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16139 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16140 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16141 CHECK(obj->HasIndexedPropertiesInPixelData());
16142 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16143 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16149 static void NotHandledIndexedPropertyGetter(
16151 const v8::PropertyCallbackInfo<v8::Value>& info) {
16152 ApiTestFuzzer::Fuzz();
16156 static void NotHandledIndexedPropertySetter(
16158 Local<Value> value,
16159 const v8::PropertyCallbackInfo<v8::Value>& info) {
16160 ApiTestFuzzer::Fuzz();
16164 THREADED_TEST(PixelArrayWithInterceptor) {
16165 LocalContext context;
16166 i::Factory* factory = CcTest::i_isolate()->factory();
16167 v8::Isolate* isolate = context->GetIsolate();
16168 v8::HandleScope scope(isolate);
16169 const int kElementCount = 260;
16170 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16171 i::Handle<i::ExternalUint8ClampedArray> pixels =
16172 i::Handle<i::ExternalUint8ClampedArray>::cast(
16173 factory->NewExternalArray(kElementCount,
16174 v8::kExternalUint8ClampedArray,
16176 for (int i = 0; i < kElementCount; i++) {
16177 pixels->set(i, i % 256);
16179 v8::Handle<v8::ObjectTemplate> templ =
16180 v8::ObjectTemplate::New(context->GetIsolate());
16181 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16182 NotHandledIndexedPropertySetter);
16183 v8::Handle<v8::Object> obj = templ->NewInstance();
16184 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16185 context->Global()->Set(v8_str("pixels"), obj);
16186 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16187 CHECK_EQ(1, result->Int32Value());
16188 result = CompileRun("var sum = 0;"
16189 "for (var i = 0; i < 8; i++) {"
16190 " sum += pixels[i] = pixels[i] = -i;"
16193 CHECK_EQ(-28, result->Int32Value());
16194 result = CompileRun("pixels.hasOwnProperty('1')");
16195 CHECK(result->BooleanValue());
16200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16201 switch (array_type) {
16202 case v8::kExternalInt8Array:
16203 case v8::kExternalUint8Array:
16204 case v8::kExternalUint8ClampedArray:
16207 case v8::kExternalInt16Array:
16208 case v8::kExternalUint16Array:
16211 case v8::kExternalInt32Array:
16212 case v8::kExternalUint32Array:
16213 case v8::kExternalFloat32Array:
16216 case v8::kExternalFloat64Array:
16228 template <class ExternalArrayClass, class ElementType>
16229 static void ObjectWithExternalArrayTestHelper(
16230 Handle<Context> context,
16231 v8::Handle<Object> obj,
16233 v8::ExternalArrayType array_type,
16234 int64_t low, int64_t high) {
16235 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16236 i::Isolate* isolate = jsobj->GetIsolate();
16237 obj->Set(v8_str("field"),
16238 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16239 context->Global()->Set(v8_str("ext_array"), obj);
16240 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16241 CHECK_EQ(1503, result->Int32Value());
16242 result = CompileRun("ext_array[1]");
16243 CHECK_EQ(1, result->Int32Value());
16245 // Check assigned smis
16246 result = CompileRun("for (var i = 0; i < 8; i++) {"
16247 " ext_array[i] = i;"
16250 "for (var i = 0; i < 8; i++) {"
16251 " sum += ext_array[i];"
16255 CHECK_EQ(28, result->Int32Value());
16256 // Check pass through of assigned smis
16257 result = CompileRun("var sum = 0;"
16258 "for (var i = 0; i < 8; i++) {"
16259 " sum += ext_array[i] = ext_array[i] = -i;"
16262 CHECK_EQ(-28, result->Int32Value());
16265 // Check assigned smis in reverse order
16266 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16267 " ext_array[i] = i;"
16270 "for (var i = 0; i < 8; i++) {"
16271 " sum += ext_array[i];"
16274 CHECK_EQ(28, result->Int32Value());
16276 // Check pass through of assigned HeapNumbers
16277 result = CompileRun("var sum = 0;"
16278 "for (var i = 0; i < 16; i+=2) {"
16279 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16282 CHECK_EQ(-28, result->Int32Value());
16284 // Check assigned HeapNumbers
16285 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16286 " ext_array[i] = (i * 0.5);"
16289 "for (var i = 0; i < 16; i+=2) {"
16290 " sum += ext_array[i];"
16293 CHECK_EQ(28, result->Int32Value());
16295 // Check assigned HeapNumbers in reverse order
16296 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16297 " ext_array[i] = (i * 0.5);"
16300 "for (var i = 0; i < 16; i+=2) {"
16301 " sum += ext_array[i];"
16304 CHECK_EQ(28, result->Int32Value());
16306 i::ScopedVector<char> test_buf(1024);
16308 // Check legal boundary conditions.
16309 // The repeated loads and stores ensure the ICs are exercised.
16310 const char* boundary_program =
16312 "for (var i = 0; i < 16; i++) {"
16313 " ext_array[i] = %lld;"
16315 " res = ext_array[i];"
16319 i::SNPrintF(test_buf,
16322 result = CompileRun(test_buf.start());
16323 CHECK_EQ(low, result->IntegerValue());
16325 i::SNPrintF(test_buf,
16328 result = CompileRun(test_buf.start());
16329 CHECK_EQ(high, result->IntegerValue());
16331 // Check misprediction of type in IC.
16332 result = CompileRun("var tmp_array = ext_array;"
16334 "for (var i = 0; i < 8; i++) {"
16335 " tmp_array[i] = i;"
16336 " sum += tmp_array[i];"
16342 // Force GC to trigger verification.
16343 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16344 CHECK_EQ(28, result->Int32Value());
16346 // Make sure out-of-range loads do not throw.
16347 i::SNPrintF(test_buf,
16348 "var caught_exception = false;"
16352 " caught_exception = true;"
16354 "caught_exception;",
16356 result = CompileRun(test_buf.start());
16357 CHECK_EQ(false, result->BooleanValue());
16359 // Make sure out-of-range stores do not throw.
16360 i::SNPrintF(test_buf,
16361 "var caught_exception = false;"
16363 " ext_array[%d] = 1;"
16365 " caught_exception = true;"
16367 "caught_exception;",
16369 result = CompileRun(test_buf.start());
16370 CHECK_EQ(false, result->BooleanValue());
16372 // Check other boundary conditions, values and operations.
16373 result = CompileRun("for (var i = 0; i < 8; i++) {"
16374 " ext_array[7] = undefined;"
16377 CHECK_EQ(0, result->Int32Value());
16378 if (array_type == v8::kExternalFloat64Array ||
16379 array_type == v8::kExternalFloat32Array) {
16380 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16382 i::Object::GetElement(
16383 isolate, jsobj, 7).ToHandleChecked()->Number()));
16385 CheckElementValue(isolate, 0, jsobj, 7);
16388 result = CompileRun("for (var i = 0; i < 8; i++) {"
16389 " ext_array[6] = '2.3';"
16392 CHECK_EQ(2, result->Int32Value());
16395 i::Object::GetElement(
16396 isolate, jsobj, 6).ToHandleChecked()->Number()));
16398 if (array_type != v8::kExternalFloat32Array &&
16399 array_type != v8::kExternalFloat64Array) {
16400 // Though the specification doesn't state it, be explicit about
16401 // converting NaNs and +/-Infinity to zero.
16402 result = CompileRun("for (var i = 0; i < 8; i++) {"
16403 " ext_array[i] = 5;"
16405 "for (var i = 0; i < 8; i++) {"
16406 " ext_array[i] = NaN;"
16409 CHECK_EQ(0, result->Int32Value());
16410 CheckElementValue(isolate, 0, jsobj, 5);
16412 result = CompileRun("for (var i = 0; i < 8; i++) {"
16413 " ext_array[i] = 5;"
16415 "for (var i = 0; i < 8; i++) {"
16416 " ext_array[i] = Infinity;"
16419 int expected_value =
16420 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16421 CHECK_EQ(expected_value, result->Int32Value());
16422 CheckElementValue(isolate, expected_value, jsobj, 5);
16424 result = CompileRun("for (var i = 0; i < 8; i++) {"
16425 " ext_array[i] = 5;"
16427 "for (var i = 0; i < 8; i++) {"
16428 " ext_array[i] = -Infinity;"
16431 CHECK_EQ(0, result->Int32Value());
16432 CheckElementValue(isolate, 0, jsobj, 5);
16434 // Check truncation behavior of integral arrays.
16435 const char* unsigned_data =
16436 "var source_data = [0.6, 10.6];"
16437 "var expected_results = [0, 10];";
16438 const char* signed_data =
16439 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16440 "var expected_results = [0, 10, 0, -10];";
16441 const char* pixel_data =
16442 "var source_data = [0.6, 10.6];"
16443 "var expected_results = [1, 11];";
16445 (array_type == v8::kExternalUint8Array ||
16446 array_type == v8::kExternalUint16Array ||
16447 array_type == v8::kExternalUint32Array);
16448 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16450 i::SNPrintF(test_buf,
16452 "var all_passed = true;"
16453 "for (var i = 0; i < source_data.length; i++) {"
16454 " for (var j = 0; j < 8; j++) {"
16455 " ext_array[j] = source_data[i];"
16457 " all_passed = all_passed &&"
16458 " (ext_array[5] == expected_results[i]);"
16463 (is_pixel_data ? pixel_data : signed_data)));
16464 result = CompileRun(test_buf.start());
16465 CHECK_EQ(true, result->BooleanValue());
16468 i::Handle<ExternalArrayClass> array(
16469 ExternalArrayClass::cast(jsobj->elements()));
16470 for (int i = 0; i < element_count; i++) {
16471 array->set(i, static_cast<ElementType>(i));
16474 // Test complex assignments
16475 result = CompileRun("function ee_op_test_complex_func(sum) {"
16476 " for (var i = 0; i < 40; ++i) {"
16477 " sum += (ext_array[i] += 1);"
16478 " sum += (ext_array[i] -= 1);"
16483 "for (var i=0;i<10000;++i) {"
16484 " sum=ee_op_test_complex_func(sum);"
16487 CHECK_EQ(16000000, result->Int32Value());
16489 // Test count operations
16490 result = CompileRun("function ee_op_test_count_func(sum) {"
16491 " for (var i = 0; i < 40; ++i) {"
16492 " sum += (++ext_array[i]);"
16493 " sum += (--ext_array[i]);"
16498 "for (var i=0;i<10000;++i) {"
16499 " sum=ee_op_test_count_func(sum);"
16502 CHECK_EQ(16000000, result->Int32Value());
16504 result = CompileRun("ext_array[3] = 33;"
16505 "delete ext_array[3];"
16507 CHECK_EQ(33, result->Int32Value());
16509 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16510 "ext_array[2] = 12; ext_array[3] = 13;"
16511 "ext_array.__defineGetter__('2',"
16512 "function() { return 120; });"
16514 CHECK_EQ(12, result->Int32Value());
16516 result = CompileRun("var js_array = new Array(40);"
16517 "js_array[0] = 77;"
16519 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16521 result = CompileRun("ext_array[1] = 23;"
16522 "ext_array.__proto__ = [];"
16523 "js_array.__proto__ = ext_array;"
16524 "js_array.concat(ext_array);");
16525 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16526 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16528 result = CompileRun("ext_array[1] = 23;");
16529 CHECK_EQ(23, result->Int32Value());
16533 template <class FixedTypedArrayClass,
16534 i::ElementsKind elements_kind,
16536 static void FixedTypedArrayTestHelper(
16537 v8::ExternalArrayType array_type,
16539 ElementType high) {
16540 i::FLAG_allow_natives_syntax = true;
16541 LocalContext context;
16542 i::Isolate* isolate = CcTest::i_isolate();
16543 i::Factory* factory = isolate->factory();
16544 v8::HandleScope scope(context->GetIsolate());
16545 const int kElementCount = 260;
16546 i::Handle<FixedTypedArrayClass> fixed_array =
16547 i::Handle<FixedTypedArrayClass>::cast(
16548 factory->NewFixedTypedArray(kElementCount, array_type));
16549 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16550 fixed_array->map()->instance_type());
16551 CHECK_EQ(kElementCount, fixed_array->length());
16552 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16553 for (int i = 0; i < kElementCount; i++) {
16554 fixed_array->set(i, static_cast<ElementType>(i));
16556 // Force GC to trigger verification.
16557 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16558 for (int i = 0; i < kElementCount; i++) {
16559 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16560 static_cast<int64_t>(fixed_array->get_scalar(i)));
16562 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16563 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16564 i::Handle<i::Map> fixed_array_map =
16565 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16566 jsobj->set_map(*fixed_array_map);
16567 jsobj->set_elements(*fixed_array);
16569 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16570 context.local(), obj, kElementCount, array_type,
16571 static_cast<int64_t>(low),
16572 static_cast<int64_t>(high));
16576 THREADED_TEST(FixedUint8Array) {
16577 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16578 v8::kExternalUint8Array,
16583 THREADED_TEST(FixedUint8ClampedArray) {
16584 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16585 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16586 v8::kExternalUint8ClampedArray,
16591 THREADED_TEST(FixedInt8Array) {
16592 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16593 v8::kExternalInt8Array,
16598 THREADED_TEST(FixedUint16Array) {
16599 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16600 v8::kExternalUint16Array,
16605 THREADED_TEST(FixedInt16Array) {
16606 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16607 v8::kExternalInt16Array,
16612 THREADED_TEST(FixedUint32Array) {
16613 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16614 v8::kExternalUint32Array,
16619 THREADED_TEST(FixedInt32Array) {
16620 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16621 v8::kExternalInt32Array,
16626 THREADED_TEST(FixedFloat32Array) {
16627 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16628 v8::kExternalFloat32Array,
16633 THREADED_TEST(FixedFloat64Array) {
16634 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16635 v8::kExternalFloat64Array,
16640 template <class ExternalArrayClass, class ElementType>
16641 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16644 LocalContext context;
16645 i::Isolate* isolate = CcTest::i_isolate();
16646 i::Factory* factory = isolate->factory();
16647 v8::HandleScope scope(context->GetIsolate());
16648 const int kElementCount = 40;
16649 int element_size = ExternalArrayElementSize(array_type);
16650 ElementType* array_data =
16651 static_cast<ElementType*>(malloc(kElementCount * element_size));
16652 i::Handle<ExternalArrayClass> array =
16653 i::Handle<ExternalArrayClass>::cast(
16654 factory->NewExternalArray(kElementCount, array_type, array_data));
16655 // Force GC to trigger verification.
16656 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16657 for (int i = 0; i < kElementCount; i++) {
16658 array->set(i, static_cast<ElementType>(i));
16660 // Force GC to trigger verification.
16661 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16662 for (int i = 0; i < kElementCount; i++) {
16663 CHECK_EQ(static_cast<int64_t>(i),
16664 static_cast<int64_t>(array->get_scalar(i)));
16665 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16668 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16669 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16670 // Set the elements to be the external array.
16671 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16676 i::Object::GetElement(
16677 isolate, jsobj, 1).ToHandleChecked()->Number()));
16679 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16680 context.local(), obj, kElementCount, array_type, low, high);
16682 v8::Handle<v8::Value> result;
16684 // Test more complex manipulations which cause eax to contain values
16685 // that won't be completely overwritten by loads from the arrays.
16686 // This catches bugs in the instructions used for the KeyedLoadIC
16687 // for byte and word types.
16689 const int kXSize = 300;
16690 const int kYSize = 300;
16691 const int kLargeElementCount = kXSize * kYSize * 4;
16692 ElementType* large_array_data =
16693 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16694 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16695 // Set the elements to be the external array.
16696 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16698 kLargeElementCount);
16699 context->Global()->Set(v8_str("large_array"), large_obj);
16700 // Initialize contents of a few rows.
16701 for (int x = 0; x < 300; x++) {
16703 int offset = row * 300 * 4;
16704 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16705 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16706 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16707 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16709 offset = row * 300 * 4;
16710 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16711 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16712 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16713 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16715 offset = row * 300 * 4;
16716 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16717 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16718 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16719 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16721 // The goal of the code below is to make "offset" large enough
16722 // that the computation of the index (which goes into eax) has
16723 // high bits set which will not be overwritten by a byte or short
16725 result = CompileRun("var failed = false;"
16727 "for (var i = 0; i < 300; i++) {"
16728 " if (large_array[4 * i] != 127 ||"
16729 " large_array[4 * i + 1] != 0 ||"
16730 " large_array[4 * i + 2] != 0 ||"
16731 " large_array[4 * i + 3] != 127) {"
16735 "offset = 150 * 300 * 4;"
16736 "for (var i = 0; i < 300; i++) {"
16737 " if (large_array[offset + 4 * i] != 127 ||"
16738 " large_array[offset + 4 * i + 1] != 0 ||"
16739 " large_array[offset + 4 * i + 2] != 0 ||"
16740 " large_array[offset + 4 * i + 3] != 127) {"
16744 "offset = 298 * 300 * 4;"
16745 "for (var i = 0; i < 300; i++) {"
16746 " if (large_array[offset + 4 * i] != 127 ||"
16747 " large_array[offset + 4 * i + 1] != 0 ||"
16748 " large_array[offset + 4 * i + 2] != 0 ||"
16749 " large_array[offset + 4 * i + 3] != 127) {"
16754 CHECK_EQ(true, result->BooleanValue());
16755 free(large_array_data);
16758 // The "" property descriptor is overloaded to store information about
16759 // the external array. Ensure that setting and accessing the "" property
16760 // works (it should overwrite the information cached about the external
16761 // array in the DescriptorArray) in various situations.
16762 result = CompileRun("ext_array[''] = 23; ext_array['']");
16763 CHECK_EQ(23, result->Int32Value());
16765 // Property "" set after the external array is associated with the object.
16767 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16768 obj2->Set(v8_str("ee_test_field"),
16769 v8::Int32::New(context->GetIsolate(), 256));
16770 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16771 // Set the elements to be the external array.
16772 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16775 context->Global()->Set(v8_str("ext_array"), obj2);
16776 result = CompileRun("ext_array['']");
16777 CHECK_EQ(1503, result->Int32Value());
16780 // Property "" set after the external array is associated with the object.
16782 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16783 obj2->Set(v8_str("ee_test_field_2"),
16784 v8::Int32::New(context->GetIsolate(), 256));
16785 // Set the elements to be the external array.
16786 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16789 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16790 context->Global()->Set(v8_str("ext_array"), obj2);
16791 result = CompileRun("ext_array['']");
16792 CHECK_EQ(1503, result->Int32Value());
16795 // Should reuse the map from previous test.
16797 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16798 obj2->Set(v8_str("ee_test_field_2"),
16799 v8::Int32::New(context->GetIsolate(), 256));
16800 // Set the elements to be the external array. Should re-use the map
16801 // from previous test.
16802 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16805 context->Global()->Set(v8_str("ext_array"), obj2);
16806 result = CompileRun("ext_array['']");
16809 // Property "" is a constant function that shouldn't not be interfered with
16810 // when an external array is set.
16812 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16814 obj2->Set(v8_str("ee_test_field3"),
16815 v8::Int32::New(context->GetIsolate(), 256));
16817 // Add a constant function to an object.
16818 context->Global()->Set(v8_str("ext_array"), obj2);
16819 result = CompileRun("ext_array[''] = function() {return 1503;};"
16820 "ext_array['']();");
16822 // Add an external array transition to the same map that
16823 // has the constant transition.
16824 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16825 obj3->Set(v8_str("ee_test_field3"),
16826 v8::Int32::New(context->GetIsolate(), 256));
16827 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16830 context->Global()->Set(v8_str("ext_array"), obj3);
16833 // If a external array transition is in the map, it should get clobbered
16834 // by a constant function.
16836 // Add an external array transition.
16837 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16838 obj3->Set(v8_str("ee_test_field4"),
16839 v8::Int32::New(context->GetIsolate(), 256));
16840 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16844 // Add a constant function to the same map that just got an external array
16846 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16847 obj2->Set(v8_str("ee_test_field4"),
16848 v8::Int32::New(context->GetIsolate(), 256));
16849 context->Global()->Set(v8_str("ext_array"), obj2);
16850 result = CompileRun("ext_array[''] = function() {return 1503;};"
16851 "ext_array['']();");
16858 THREADED_TEST(ExternalInt8Array) {
16859 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16860 v8::kExternalInt8Array,
16866 THREADED_TEST(ExternalUint8Array) {
16867 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16868 v8::kExternalUint8Array,
16874 THREADED_TEST(ExternalUint8ClampedArray) {
16875 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16876 v8::kExternalUint8ClampedArray,
16882 THREADED_TEST(ExternalInt16Array) {
16883 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16884 v8::kExternalInt16Array,
16890 THREADED_TEST(ExternalUint16Array) {
16891 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16892 v8::kExternalUint16Array,
16898 THREADED_TEST(ExternalInt32Array) {
16899 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16900 v8::kExternalInt32Array,
16901 INT_MIN, // -2147483648
16902 INT_MAX); // 2147483647
16906 THREADED_TEST(ExternalUint32Array) {
16907 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16908 v8::kExternalUint32Array,
16910 UINT_MAX); // 4294967295
16914 THREADED_TEST(ExternalFloat32Array) {
16915 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16916 v8::kExternalFloat32Array,
16922 THREADED_TEST(ExternalFloat64Array) {
16923 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16924 v8::kExternalFloat64Array,
16930 THREADED_TEST(ExternalArrays) {
16931 TestExternalInt8Array();
16932 TestExternalUint8Array();
16933 TestExternalInt16Array();
16934 TestExternalUint16Array();
16935 TestExternalInt32Array();
16936 TestExternalUint32Array();
16937 TestExternalFloat32Array();
16941 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16942 LocalContext context;
16943 v8::HandleScope scope(context->GetIsolate());
16944 for (int size = 0; size < 100; size += 10) {
16945 int element_size = ExternalArrayElementSize(array_type);
16946 void* external_data = malloc(size * element_size);
16947 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16948 obj->SetIndexedPropertiesToExternalArrayData(
16949 external_data, array_type, size);
16950 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16951 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16952 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16953 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16954 free(external_data);
16959 THREADED_TEST(ExternalArrayInfo) {
16960 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16961 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16962 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16963 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16964 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16965 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16966 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16967 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16968 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16972 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16973 v8::ExternalArrayType array_type,
16975 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16976 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16977 last_location = last_message = NULL;
16978 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16979 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16980 CHECK_NE(NULL, last_location);
16981 CHECK_NE(NULL, last_message);
16985 TEST(ExternalArrayLimits) {
16986 LocalContext context;
16987 v8::Isolate* isolate = context->GetIsolate();
16988 v8::HandleScope scope(isolate);
16989 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16990 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16991 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16992 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16993 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16994 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16995 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16996 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16997 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16998 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16999 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17000 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17001 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17002 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17003 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17004 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17005 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17006 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17010 template <typename ElementType, typename TypedArray,
17011 class ExternalArrayClass>
17012 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17013 int64_t low, int64_t high) {
17014 const int kElementCount = 50;
17016 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17019 v8::Isolate* isolate = env->GetIsolate();
17020 v8::HandleScope handle_scope(isolate);
17022 Local<v8::ArrayBuffer> ab =
17023 v8::ArrayBuffer::New(isolate, backing_store.start(),
17024 (kElementCount + 2) * sizeof(ElementType));
17025 Local<TypedArray> ta =
17026 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17027 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17028 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17029 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17030 CHECK_EQ(kElementCount*sizeof(ElementType),
17031 static_cast<int>(ta->ByteLength()));
17032 CHECK_EQ(ab, ta->Buffer());
17034 ElementType* data = backing_store.start() + 2;
17035 for (int i = 0; i < kElementCount; i++) {
17036 data[i] = static_cast<ElementType>(i);
17039 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17040 env.local(), ta, kElementCount, array_type, low, high);
17044 THREADED_TEST(Uint8Array) {
17045 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17046 v8::kExternalUint8Array, 0, 0xFF);
17050 THREADED_TEST(Int8Array) {
17051 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17052 v8::kExternalInt8Array, -0x80, 0x7F);
17056 THREADED_TEST(Uint16Array) {
17057 TypedArrayTestHelper<uint16_t,
17059 i::ExternalUint16Array>(
17060 v8::kExternalUint16Array, 0, 0xFFFF);
17064 THREADED_TEST(Int16Array) {
17065 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17066 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17070 THREADED_TEST(Uint32Array) {
17071 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17072 v8::kExternalUint32Array, 0, UINT_MAX);
17076 THREADED_TEST(Int32Array) {
17077 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17078 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17082 THREADED_TEST(Float32Array) {
17083 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17084 v8::kExternalFloat32Array, -500, 500);
17088 THREADED_TEST(Float64Array) {
17089 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17090 v8::kExternalFloat64Array, -500, 500);
17094 THREADED_TEST(Uint8ClampedArray) {
17095 TypedArrayTestHelper<uint8_t,
17096 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17097 v8::kExternalUint8ClampedArray, 0, 0xFF);
17101 THREADED_TEST(DataView) {
17102 const int kSize = 50;
17104 i::ScopedVector<uint8_t> backing_store(kSize+2);
17107 v8::Isolate* isolate = env->GetIsolate();
17108 v8::HandleScope handle_scope(isolate);
17110 Local<v8::ArrayBuffer> ab =
17111 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17112 Local<v8::DataView> dv =
17113 v8::DataView::New(ab, 2, kSize);
17114 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17115 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17116 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17117 CHECK_EQ(ab, dv->Buffer());
17121 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17122 THREADED_TEST(Is##View) { \
17123 LocalContext env; \
17124 v8::Isolate* isolate = env->GetIsolate(); \
17125 v8::HandleScope handle_scope(isolate); \
17127 Handle<Value> result = CompileRun( \
17128 "var ab = new ArrayBuffer(128);" \
17129 "new " #View "(ab)"); \
17130 CHECK(result->IsArrayBufferView()); \
17131 CHECK(result->Is##View()); \
17132 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17135 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17136 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17137 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17138 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17139 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17140 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17141 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17142 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17143 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17144 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17146 #undef IS_ARRAY_BUFFER_VIEW_TEST
17150 THREADED_TEST(ScriptContextDependence) {
17152 v8::HandleScope scope(c1->GetIsolate());
17153 const char *source = "foo";
17154 v8::Handle<v8::Script> dep = v8_compile(source);
17155 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17156 c1->GetIsolate(), source));
17157 v8::Handle<v8::UnboundScript> indep =
17158 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17159 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17160 v8::Integer::New(c1->GetIsolate(), 100));
17161 CHECK_EQ(dep->Run()->Int32Value(), 100);
17162 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17164 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17165 v8::Integer::New(c2->GetIsolate(), 101));
17166 CHECK_EQ(dep->Run()->Int32Value(), 100);
17167 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17171 THREADED_TEST(StackTrace) {
17172 LocalContext context;
17173 v8::HandleScope scope(context->GetIsolate());
17174 v8::TryCatch try_catch;
17175 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17176 v8::Handle<v8::String> src =
17177 v8::String::NewFromUtf8(context->GetIsolate(), source);
17178 v8::Handle<v8::String> origin =
17179 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17180 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17181 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17182 ->BindToCurrentContext()
17184 CHECK(try_catch.HasCaught());
17185 v8::String::Utf8Value stack(try_catch.StackTrace());
17186 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17190 // Checks that a StackFrame has certain expected values.
17191 void checkStackFrame(const char* expected_script_name,
17192 const char* expected_func_name, int expected_line_number,
17193 int expected_column, bool is_eval, bool is_constructor,
17194 v8::Handle<v8::StackFrame> frame) {
17195 v8::HandleScope scope(CcTest::isolate());
17196 v8::String::Utf8Value func_name(frame->GetFunctionName());
17197 v8::String::Utf8Value script_name(frame->GetScriptName());
17198 if (*script_name == NULL) {
17199 // The situation where there is no associated script, like for evals.
17200 CHECK(expected_script_name == NULL);
17202 CHECK(strstr(*script_name, expected_script_name) != NULL);
17204 CHECK(strstr(*func_name, expected_func_name) != NULL);
17205 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17206 CHECK_EQ(expected_column, frame->GetColumn());
17207 CHECK_EQ(is_eval, frame->IsEval());
17208 CHECK_EQ(is_constructor, frame->IsConstructor());
17212 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17213 v8::HandleScope scope(args.GetIsolate());
17214 const char* origin = "capture-stack-trace-test";
17215 const int kOverviewTest = 1;
17216 const int kDetailedTest = 2;
17218 ASSERT(args.Length() == 1);
17220 int testGroup = args[0]->Int32Value();
17221 if (testGroup == kOverviewTest) {
17222 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17223 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17224 CHECK_EQ(4, stackTrace->GetFrameCount());
17225 checkStackFrame(origin, "bar", 2, 10, false, false,
17226 stackTrace->GetFrame(0));
17227 checkStackFrame(origin, "foo", 6, 3, false, false,
17228 stackTrace->GetFrame(1));
17229 // This is the source string inside the eval which has the call to foo.
17230 checkStackFrame(NULL, "", 1, 5, false, false,
17231 stackTrace->GetFrame(2));
17232 // The last frame is an anonymous function which has the initial eval call.
17233 checkStackFrame(origin, "", 8, 7, false, false,
17234 stackTrace->GetFrame(3));
17236 CHECK(stackTrace->AsArray()->IsArray());
17237 } else if (testGroup == kDetailedTest) {
17238 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17239 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17240 CHECK_EQ(4, stackTrace->GetFrameCount());
17241 checkStackFrame(origin, "bat", 4, 22, false, false,
17242 stackTrace->GetFrame(0));
17243 checkStackFrame(origin, "baz", 8, 3, false, true,
17244 stackTrace->GetFrame(1));
17245 bool is_eval = true;
17246 // This is the source string inside the eval which has the call to baz.
17247 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17248 stackTrace->GetFrame(2));
17249 // The last frame is an anonymous function which has the initial eval call.
17250 checkStackFrame(origin, "", 10, 1, false, false,
17251 stackTrace->GetFrame(3));
17253 CHECK(stackTrace->AsArray()->IsArray());
17258 // Tests the C++ StackTrace API.
17259 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17260 // THREADED_TEST(CaptureStackTrace) {
17261 TEST(CaptureStackTrace) {
17262 v8::Isolate* isolate = CcTest::isolate();
17263 v8::HandleScope scope(isolate);
17264 v8::Handle<v8::String> origin =
17265 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17266 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17267 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17268 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17269 LocalContext context(0, templ);
17271 // Test getting OVERVIEW information. Should ignore information that is not
17272 // script name, function name, line number, and column offset.
17273 const char *overview_source =
17274 "function bar() {\n"
17275 " var y; AnalyzeStackInNativeCode(1);\n"
17277 "function foo() {\n"
17281 "var x;eval('new foo();');";
17282 v8::Handle<v8::String> overview_src =
17283 v8::String::NewFromUtf8(isolate, overview_source);
17284 v8::ScriptCompiler::Source script_source(overview_src,
17285 v8::ScriptOrigin(origin));
17286 v8::Handle<Value> overview_result(
17287 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17288 ->BindToCurrentContext()
17290 CHECK(!overview_result.IsEmpty());
17291 CHECK(overview_result->IsObject());
17293 // Test getting DETAILED information.
17294 const char *detailed_source =
17295 "function bat() {AnalyzeStackInNativeCode(2);\n"
17298 "function baz() {\n"
17301 "eval('new baz();');";
17302 v8::Handle<v8::String> detailed_src =
17303 v8::String::NewFromUtf8(isolate, detailed_source);
17304 // Make the script using a non-zero line and column offset.
17305 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17306 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17307 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17308 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17309 v8::Handle<v8::UnboundScript> detailed_script(
17310 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17311 v8::Handle<Value> detailed_result(
17312 detailed_script->BindToCurrentContext()->Run());
17313 CHECK(!detailed_result.IsEmpty());
17314 CHECK(detailed_result->IsObject());
17318 static void StackTraceForUncaughtExceptionListener(
17319 v8::Handle<v8::Message> message,
17320 v8::Handle<Value>) {
17321 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17322 CHECK_EQ(2, stack_trace->GetFrameCount());
17323 checkStackFrame("origin", "foo", 2, 3, false, false,
17324 stack_trace->GetFrame(0));
17325 checkStackFrame("origin", "bar", 5, 3, false, false,
17326 stack_trace->GetFrame(1));
17330 TEST(CaptureStackTraceForUncaughtException) {
17333 v8::HandleScope scope(env->GetIsolate());
17334 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17335 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17337 CompileRunWithOrigin(
17338 "function foo() {\n"
17341 "function bar() {\n"
17345 v8::Local<v8::Object> global = env->Global();
17346 Local<Value> trouble = global->Get(v8_str("bar"));
17347 CHECK(trouble->IsFunction());
17348 Function::Cast(*trouble)->Call(global, 0, NULL);
17349 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17350 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17354 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17356 v8::HandleScope scope(env->GetIsolate());
17357 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17359 v8::StackTrace::kDetailed);
17362 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17363 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17364 " 'isConstructor'];\n"
17365 "for (var i = 0; i < setters.length; i++) {\n"
17366 " var prop = setters[i];\n"
17367 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17369 CompileRun("throw 'exception';");
17370 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17374 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17375 v8::Handle<v8::Value> data) {
17376 // Use the frame where JavaScript is called from.
17377 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17378 CHECK(!stack_trace.IsEmpty());
17379 int frame_count = stack_trace->GetFrameCount();
17380 CHECK_EQ(3, frame_count);
17381 int line_number[] = {1, 2, 5};
17382 for (int i = 0; i < frame_count; i++) {
17383 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17388 // Test that we only return the stack trace at the site where the exception
17389 // is first thrown (not where it is rethrown).
17390 TEST(RethrowStackTrace) {
17392 v8::HandleScope scope(env->GetIsolate());
17393 // We make sure that
17394 // - the stack trace of the ReferenceError in g() is reported.
17395 // - the stack trace is not overwritten when e1 is rethrown by t().
17396 // - the stack trace of e2 does not overwrite that of e1.
17397 const char* source =
17398 "function g() { error; } \n"
17399 "function f() { g(); } \n"
17400 "function t(e) { throw e; } \n"
17403 "} catch (e1) { \n"
17406 " } catch (e2) { \n"
17410 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17411 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17412 CompileRun(source);
17413 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17414 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17418 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17419 v8::Handle<v8::Value> data) {
17420 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17421 CHECK(!stack_trace.IsEmpty());
17422 int frame_count = stack_trace->GetFrameCount();
17423 CHECK_EQ(2, frame_count);
17424 int line_number[] = {3, 7};
17425 for (int i = 0; i < frame_count; i++) {
17426 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17431 // Test that we do not recognize identity for primitive exceptions.
17432 TEST(RethrowPrimitiveStackTrace) {
17434 v8::HandleScope scope(env->GetIsolate());
17435 // We do not capture stack trace for non Error objects on creation time.
17436 // Instead, we capture the stack trace on last throw.
17437 const char* source =
17438 "function g() { throw 404; } \n"
17439 "function f() { g(); } \n"
17440 "function t(e) { throw e; } \n"
17443 "} catch (e1) { \n"
17446 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17447 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17448 CompileRun(source);
17449 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17450 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17454 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17455 v8::Handle<v8::Value> data) {
17456 // Use the frame where JavaScript is called from.
17457 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17458 CHECK(!stack_trace.IsEmpty());
17459 CHECK_EQ(1, stack_trace->GetFrameCount());
17460 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17464 // Test that the stack trace is captured when the error object is created and
17465 // not where it is thrown.
17466 TEST(RethrowExistingStackTrace) {
17468 v8::HandleScope scope(env->GetIsolate());
17469 const char* source =
17470 "var e = new Error(); \n"
17472 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17473 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17474 CompileRun(source);
17475 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17476 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17480 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17481 v8::Handle<v8::Value> data) {
17482 // Use the frame where JavaScript is called from.
17483 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17484 CHECK(!stack_trace.IsEmpty());
17485 CHECK_EQ(1, stack_trace->GetFrameCount());
17486 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17490 // Test that the stack trace is captured where the bogus Error object is thrown.
17491 TEST(RethrowBogusErrorStackTrace) {
17493 v8::HandleScope scope(env->GetIsolate());
17494 const char* source =
17495 "var e = {__proto__: new Error()} \n"
17497 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17498 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17499 CompileRun(source);
17500 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17501 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17505 void AnalyzeStackOfEvalWithSourceURL(
17506 const v8::FunctionCallbackInfo<v8::Value>& args) {
17507 v8::HandleScope scope(args.GetIsolate());
17508 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17509 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17510 CHECK_EQ(5, stackTrace->GetFrameCount());
17511 v8::Handle<v8::String> url = v8_str("eval_url");
17512 for (int i = 0; i < 3; i++) {
17513 v8::Handle<v8::String> name =
17514 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17515 CHECK(!name.IsEmpty());
17516 CHECK_EQ(url, name);
17521 TEST(SourceURLInStackTrace) {
17522 v8::Isolate* isolate = CcTest::isolate();
17523 v8::HandleScope scope(isolate);
17524 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17525 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17526 v8::FunctionTemplate::New(isolate,
17527 AnalyzeStackOfEvalWithSourceURL));
17528 LocalContext context(0, templ);
17530 const char *source =
17531 "function outer() {\n"
17532 "function bar() {\n"
17533 " AnalyzeStackOfEvalWithSourceURL();\n"
17535 "function foo() {\n"
17541 "eval('(' + outer +')()%s');";
17543 i::ScopedVector<char> code(1024);
17544 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17545 CHECK(CompileRun(code.start())->IsUndefined());
17546 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17547 CHECK(CompileRun(code.start())->IsUndefined());
17551 static int scriptIdInStack[2];
17553 void AnalyzeScriptIdInStack(
17554 const v8::FunctionCallbackInfo<v8::Value>& args) {
17555 v8::HandleScope scope(args.GetIsolate());
17556 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17557 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17558 CHECK_EQ(2, stackTrace->GetFrameCount());
17559 for (int i = 0; i < 2; i++) {
17560 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17565 TEST(ScriptIdInStackTrace) {
17566 v8::Isolate* isolate = CcTest::isolate();
17567 v8::HandleScope scope(isolate);
17568 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17569 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17570 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17571 LocalContext context(0, templ);
17573 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17575 "function foo() {\n"
17576 " AnalyzeScriptIdInStack();"
17579 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17581 for (int i = 0; i < 2; i++) {
17582 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17583 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17588 void AnalyzeStackOfInlineScriptWithSourceURL(
17589 const v8::FunctionCallbackInfo<v8::Value>& args) {
17590 v8::HandleScope scope(args.GetIsolate());
17591 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17592 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17593 CHECK_EQ(4, stackTrace->GetFrameCount());
17594 v8::Handle<v8::String> url = v8_str("url");
17595 for (int i = 0; i < 3; i++) {
17596 v8::Handle<v8::String> name =
17597 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17598 CHECK(!name.IsEmpty());
17599 CHECK_EQ(url, name);
17604 TEST(InlineScriptWithSourceURLInStackTrace) {
17605 v8::Isolate* isolate = CcTest::isolate();
17606 v8::HandleScope scope(isolate);
17607 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17608 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17609 v8::FunctionTemplate::New(
17610 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17611 LocalContext context(0, templ);
17613 const char *source =
17614 "function outer() {\n"
17615 "function bar() {\n"
17616 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17618 "function foo() {\n"
17626 i::ScopedVector<char> code(1024);
17627 i::SNPrintF(code, source, "//# sourceURL=source_url");
17628 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17629 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17630 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17634 void AnalyzeStackOfDynamicScriptWithSourceURL(
17635 const v8::FunctionCallbackInfo<v8::Value>& args) {
17636 v8::HandleScope scope(args.GetIsolate());
17637 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17638 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17639 CHECK_EQ(4, stackTrace->GetFrameCount());
17640 v8::Handle<v8::String> url = v8_str("source_url");
17641 for (int i = 0; i < 3; i++) {
17642 v8::Handle<v8::String> name =
17643 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17644 CHECK(!name.IsEmpty());
17645 CHECK_EQ(url, name);
17650 TEST(DynamicWithSourceURLInStackTrace) {
17651 v8::Isolate* isolate = CcTest::isolate();
17652 v8::HandleScope scope(isolate);
17653 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17654 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17655 v8::FunctionTemplate::New(
17656 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17657 LocalContext context(0, templ);
17659 const char *source =
17660 "function outer() {\n"
17661 "function bar() {\n"
17662 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17664 "function foo() {\n"
17672 i::ScopedVector<char> code(1024);
17673 i::SNPrintF(code, source, "//# sourceURL=source_url");
17674 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17675 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17676 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17680 TEST(DynamicWithSourceURLInStackTraceString) {
17681 LocalContext context;
17682 v8::HandleScope scope(context->GetIsolate());
17684 const char *source =
17685 "function outer() {\n"
17686 " function foo() {\n"
17693 i::ScopedVector<char> code(1024);
17694 i::SNPrintF(code, source, "//# sourceURL=source_url");
17695 v8::TryCatch try_catch;
17696 CompileRunWithOrigin(code.start(), "", 0, 0);
17697 CHECK(try_catch.HasCaught());
17698 v8::String::Utf8Value stack(try_catch.StackTrace());
17699 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17703 static void CreateGarbageInOldSpace() {
17704 i::Factory* factory = CcTest::i_isolate()->factory();
17705 v8::HandleScope scope(CcTest::isolate());
17706 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17707 for (int i = 0; i < 1000; i++) {
17708 factory->NewFixedArray(1000, i::TENURED);
17713 // Test that idle notification can be handled and eventually returns true.
17714 TEST(IdleNotification) {
17715 const intptr_t MB = 1024 * 1024;
17717 v8::HandleScope scope(env->GetIsolate());
17718 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17719 CreateGarbageInOldSpace();
17720 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17721 CHECK_GT(size_with_garbage, initial_size + MB);
17722 bool finished = false;
17723 for (int i = 0; i < 200 && !finished; i++) {
17724 finished = v8::V8::IdleNotification();
17726 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17728 CHECK_LT(final_size, initial_size + 1);
17732 // Test that idle notification can be handled and eventually collects garbage.
17733 TEST(IdleNotificationWithSmallHint) {
17734 const intptr_t MB = 1024 * 1024;
17735 const int IdlePauseInMs = 900;
17737 v8::HandleScope scope(env->GetIsolate());
17738 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17739 CreateGarbageInOldSpace();
17740 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17741 CHECK_GT(size_with_garbage, initial_size + MB);
17742 bool finished = false;
17743 for (int i = 0; i < 200 && !finished; i++) {
17744 finished = v8::V8::IdleNotification(IdlePauseInMs);
17746 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17748 CHECK_LT(final_size, initial_size + 1);
17752 // Test that idle notification can be handled and eventually collects garbage.
17753 TEST(IdleNotificationWithLargeHint) {
17754 const intptr_t MB = 1024 * 1024;
17755 const int IdlePauseInMs = 900;
17757 v8::HandleScope scope(env->GetIsolate());
17758 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17759 CreateGarbageInOldSpace();
17760 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17761 CHECK_GT(size_with_garbage, initial_size + MB);
17762 bool finished = false;
17763 for (int i = 0; i < 200 && !finished; i++) {
17764 finished = v8::V8::IdleNotification(IdlePauseInMs);
17766 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17768 CHECK_LT(final_size, initial_size + 1);
17772 TEST(Regress2107) {
17773 const intptr_t MB = 1024 * 1024;
17774 const int kShortIdlePauseInMs = 100;
17775 const int kLongIdlePauseInMs = 1000;
17777 v8::Isolate* isolate = env->GetIsolate();
17778 v8::HandleScope scope(env->GetIsolate());
17779 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17780 // Send idle notification to start a round of incremental GCs.
17781 v8::V8::IdleNotification(kShortIdlePauseInMs);
17782 // Emulate 7 page reloads.
17783 for (int i = 0; i < 7; i++) {
17785 v8::HandleScope inner_scope(env->GetIsolate());
17786 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17788 CreateGarbageInOldSpace();
17791 v8::V8::ContextDisposedNotification();
17792 v8::V8::IdleNotification(kLongIdlePauseInMs);
17794 // Create garbage and check that idle notification still collects it.
17795 CreateGarbageInOldSpace();
17796 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17797 CHECK_GT(size_with_garbage, initial_size + MB);
17798 bool finished = false;
17799 for (int i = 0; i < 200 && !finished; i++) {
17800 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17802 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17803 CHECK_LT(final_size, initial_size + 1);
17807 TEST(Regress2333) {
17809 for (int i = 0; i < 3; i++) {
17810 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17814 static uint32_t* stack_limit;
17816 static void GetStackLimitCallback(
17817 const v8::FunctionCallbackInfo<v8::Value>& args) {
17818 stack_limit = reinterpret_cast<uint32_t*>(
17819 CcTest::i_isolate()->stack_guard()->real_climit());
17823 // Uses the address of a local variable to determine the stack top now.
17824 // Given a size, returns an address that is that far from the current
17826 static uint32_t* ComputeStackLimit(uint32_t size) {
17827 uint32_t* answer = &size - (size / sizeof(size));
17828 // If the size is very large and the stack is very near the bottom of
17829 // memory then the calculation above may wrap around and give an address
17830 // that is above the (downwards-growing) stack. In that case we return
17831 // a very low address.
17832 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17837 // We need at least 165kB for an x64 debug build with clang and ASAN.
17838 static const int stack_breathing_room = 256 * i::KB;
17841 TEST(SetResourceConstraints) {
17842 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17844 // Set stack limit.
17845 v8::ResourceConstraints constraints;
17846 constraints.set_stack_limit(set_limit);
17847 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17849 // Execute a script.
17851 v8::HandleScope scope(env->GetIsolate());
17852 Local<v8::FunctionTemplate> fun_templ =
17853 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17854 Local<Function> fun = fun_templ->GetFunction();
17855 env->Global()->Set(v8_str("get_stack_limit"), fun);
17856 CompileRun("get_stack_limit();");
17858 CHECK(stack_limit == set_limit);
17862 TEST(SetResourceConstraintsInThread) {
17863 uint32_t* set_limit;
17865 v8::Locker locker(CcTest::isolate());
17866 set_limit = ComputeStackLimit(stack_breathing_room);
17868 // Set stack limit.
17869 v8::ResourceConstraints constraints;
17870 constraints.set_stack_limit(set_limit);
17871 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17873 // Execute a script.
17874 v8::HandleScope scope(CcTest::isolate());
17876 Local<v8::FunctionTemplate> fun_templ =
17877 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17878 Local<Function> fun = fun_templ->GetFunction();
17879 env->Global()->Set(v8_str("get_stack_limit"), fun);
17880 CompileRun("get_stack_limit();");
17882 CHECK(stack_limit == set_limit);
17885 v8::Locker locker(CcTest::isolate());
17886 CHECK(stack_limit == set_limit);
17891 THREADED_TEST(GetHeapStatistics) {
17893 v8::HandleScope scope(c1->GetIsolate());
17894 v8::HeapStatistics heap_statistics;
17895 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17896 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17897 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17898 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17899 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17903 class VisitorImpl : public v8::ExternalResourceVisitor {
17905 explicit VisitorImpl(TestResource** resource) {
17906 for (int i = 0; i < 4; i++) {
17907 resource_[i] = resource[i];
17908 found_resource_[i] = false;
17911 virtual ~VisitorImpl() {}
17912 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17913 if (!string->IsExternal()) {
17914 CHECK(string->IsExternalAscii());
17917 v8::String::ExternalStringResource* resource =
17918 string->GetExternalStringResource();
17920 for (int i = 0; i < 4; i++) {
17921 if (resource_[i] == resource) {
17922 CHECK(!found_resource_[i]);
17923 found_resource_[i] = true;
17927 void CheckVisitedResources() {
17928 for (int i = 0; i < 4; i++) {
17929 CHECK(found_resource_[i]);
17934 v8::String::ExternalStringResource* resource_[4];
17935 bool found_resource_[4];
17939 TEST(ExternalizeOldSpaceTwoByteCons) {
17941 v8::HandleScope scope(env->GetIsolate());
17942 v8::Local<v8::String> cons =
17943 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17944 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17945 CcTest::heap()->CollectAllAvailableGarbage();
17946 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17947 *v8::Utils::OpenHandle(*cons)));
17949 TestResource* resource = new TestResource(
17950 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17951 cons->MakeExternal(resource);
17953 CHECK(cons->IsExternal());
17954 CHECK_EQ(resource, cons->GetExternalStringResource());
17955 String::Encoding encoding;
17956 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17957 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17961 TEST(ExternalizeOldSpaceOneByteCons) {
17963 v8::HandleScope scope(env->GetIsolate());
17964 v8::Local<v8::String> cons =
17965 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17966 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17967 CcTest::heap()->CollectAllAvailableGarbage();
17968 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17969 *v8::Utils::OpenHandle(*cons)));
17971 TestAsciiResource* resource =
17972 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17973 cons->MakeExternal(resource);
17975 CHECK(cons->IsExternalAscii());
17976 CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17977 String::Encoding encoding;
17978 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17979 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17983 TEST(VisitExternalStrings) {
17985 v8::HandleScope scope(env->GetIsolate());
17986 const char* string = "Some string";
17987 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17988 TestResource* resource[4];
17989 resource[0] = new TestResource(two_byte_string);
17990 v8::Local<v8::String> string0 =
17991 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17992 resource[1] = new TestResource(two_byte_string, NULL, false);
17993 v8::Local<v8::String> string1 =
17994 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17996 // Externalized symbol.
17997 resource[2] = new TestResource(two_byte_string, NULL, false);
17998 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17999 env->GetIsolate(), string, v8::String::kInternalizedString);
18000 CHECK(string2->MakeExternal(resource[2]));
18002 // Symbolized External.
18003 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18004 v8::Local<v8::String> string3 =
18005 v8::String::NewExternal(env->GetIsolate(), resource[3]);
18006 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
18007 // Turn into a symbol.
18008 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18009 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18010 string3_i).is_null());
18011 CHECK(string3_i->IsInternalizedString());
18013 // We need to add usages for string* to avoid warnings in GCC 4.7
18014 CHECK(string0->IsExternal());
18015 CHECK(string1->IsExternal());
18016 CHECK(string2->IsExternal());
18017 CHECK(string3->IsExternal());
18019 VisitorImpl visitor(resource);
18020 v8::V8::VisitExternalResources(&visitor);
18021 visitor.CheckVisitedResources();
18025 TEST(ExternalStringCollectedAtTearDown) {
18027 v8::Isolate* isolate = v8::Isolate::New();
18028 { v8::Isolate::Scope isolate_scope(isolate);
18029 v8::HandleScope handle_scope(isolate);
18030 const char* s = "One string to test them all, one string to find them.";
18031 TestAsciiResource* inscription =
18032 new TestAsciiResource(i::StrDup(s), &destroyed);
18033 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18034 // Ring is still alive. Orcs are roaming freely across our lands.
18035 CHECK_EQ(0, destroyed);
18039 isolate->Dispose();
18040 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18041 CHECK_EQ(1, destroyed);
18045 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18047 v8::Isolate* isolate = v8::Isolate::New();
18048 { v8::Isolate::Scope isolate_scope(isolate);
18049 LocalContext env(isolate);
18050 v8::HandleScope handle_scope(isolate);
18051 CompileRun("var ring = 'One string to test them all';");
18052 const char* s = "One string to test them all";
18053 TestAsciiResource* inscription =
18054 new TestAsciiResource(i::StrDup(s), &destroyed);
18055 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18056 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18057 ring->MakeExternal(inscription);
18058 // Ring is still alive. Orcs are roaming freely across our lands.
18059 CHECK_EQ(0, destroyed);
18063 isolate->Dispose();
18064 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18065 CHECK_EQ(1, destroyed);
18069 TEST(ExternalInternalizedStringCollectedAtGC) {
18071 { LocalContext env;
18072 v8::HandleScope handle_scope(env->GetIsolate());
18073 CompileRun("var ring = 'One string to test them all';");
18074 const char* s = "One string to test them all";
18075 TestAsciiResource* inscription =
18076 new TestAsciiResource(i::StrDup(s), &destroyed);
18077 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18078 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18079 ring->MakeExternal(inscription);
18080 // Ring is still alive. Orcs are roaming freely across our lands.
18081 CHECK_EQ(0, destroyed);
18085 // Garbage collector deals swift blows to evil.
18086 CcTest::i_isolate()->compilation_cache()->Clear();
18087 CcTest::heap()->CollectAllAvailableGarbage();
18089 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18090 CHECK_EQ(1, destroyed);
18094 static double DoubleFromBits(uint64_t value) {
18096 i::MemCopy(&target, &value, sizeof(target));
18101 static uint64_t DoubleToBits(double value) {
18103 i::MemCopy(&target, &value, sizeof(target));
18108 static double DoubleToDateTime(double input) {
18109 double date_limit = 864e13;
18110 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18111 return i::OS::nan_value();
18113 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18117 // We don't have a consistent way to write 64-bit constants syntactically, so we
18118 // split them into two 32-bit constants and combine them programmatically.
18119 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18120 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18124 THREADED_TEST(QuietSignalingNaNs) {
18125 LocalContext context;
18126 v8::Isolate* isolate = context->GetIsolate();
18127 v8::HandleScope scope(isolate);
18128 v8::TryCatch try_catch;
18130 // Special double values.
18131 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18132 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18133 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18134 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18135 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18136 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18137 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18139 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18140 // on either side of the epoch.
18141 double date_limit = 864e13;
18143 double test_values[] = {
18165 int num_test_values = 20;
18167 for (int i = 0; i < num_test_values; i++) {
18168 double test_value = test_values[i];
18170 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18171 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18172 double stored_number = number->NumberValue();
18173 if (!std::isnan(test_value)) {
18174 CHECK_EQ(test_value, stored_number);
18176 uint64_t stored_bits = DoubleToBits(stored_number);
18177 // Check if quiet nan (bits 51..62 all set).
18178 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18179 // Most significant fraction bit for quiet nan is set to 0
18180 // on MIPS architecture. Allowed by IEEE-754.
18181 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18183 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18187 // Check that Date::New preserves non-NaNs in the date range and
18189 v8::Handle<v8::Value> date =
18190 v8::Date::New(isolate, test_value);
18191 double expected_stored_date = DoubleToDateTime(test_value);
18192 double stored_date = date->NumberValue();
18193 if (!std::isnan(expected_stored_date)) {
18194 CHECK_EQ(expected_stored_date, stored_date);
18196 uint64_t stored_bits = DoubleToBits(stored_date);
18197 // Check if quiet nan (bits 51..62 all set).
18198 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18199 // Most significant fraction bit for quiet nan is set to 0
18200 // on MIPS architecture. Allowed by IEEE-754.
18201 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18203 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18210 static void SpaghettiIncident(
18211 const v8::FunctionCallbackInfo<v8::Value>& args) {
18212 v8::HandleScope scope(args.GetIsolate());
18214 v8::Handle<v8::String> str(args[0]->ToString());
18216 if (tc.HasCaught())
18221 // Test that an exception can be propagated down through a spaghetti
18222 // stack using ReThrow.
18223 THREADED_TEST(SpaghettiStackReThrow) {
18224 v8::Isolate* isolate = CcTest::isolate();
18225 v8::HandleScope scope(isolate);
18226 LocalContext context;
18227 context->Global()->Set(
18228 v8::String::NewFromUtf8(isolate, "s"),
18229 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18230 v8::TryCatch try_catch;
18234 " toString: function () {"
18244 CHECK(try_catch.HasCaught());
18245 v8::String::Utf8Value value(try_catch.Exception());
18246 CHECK_EQ(0, strcmp(*value, "Hey!"));
18251 v8::V8::Initialize();
18252 v8::Isolate* isolate = CcTest::isolate();
18253 v8::HandleScope scope(isolate);
18254 v8::Local<Context> other_context;
18257 // Create a context used to keep the code from aging in the compilation
18259 other_context = Context::New(isolate);
18261 // Context-dependent context data creates reference from the compilation
18262 // cache to the global object.
18263 const char* source_simple = "1";
18265 v8::HandleScope scope(isolate);
18266 v8::Local<Context> context = Context::New(isolate);
18269 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18270 context->SetEmbedderData(0, obj);
18271 CompileRun(source_simple);
18274 v8::V8::ContextDisposedNotification();
18275 for (gc_count = 1; gc_count < 10; gc_count++) {
18276 other_context->Enter();
18277 CompileRun(source_simple);
18278 other_context->Exit();
18279 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18280 if (GetGlobalObjectsCount() == 1) break;
18282 CHECK_GE(2, gc_count);
18283 CHECK_EQ(1, GetGlobalObjectsCount());
18285 // Eval in a function creates reference from the compilation cache to the
18287 const char* source_eval = "function f(){eval('1')}; f()";
18289 v8::HandleScope scope(isolate);
18290 v8::Local<Context> context = Context::New(isolate);
18293 CompileRun(source_eval);
18296 v8::V8::ContextDisposedNotification();
18297 for (gc_count = 1; gc_count < 10; gc_count++) {
18298 other_context->Enter();
18299 CompileRun(source_eval);
18300 other_context->Exit();
18301 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18302 if (GetGlobalObjectsCount() == 1) break;
18304 CHECK_GE(2, gc_count);
18305 CHECK_EQ(1, GetGlobalObjectsCount());
18307 // Looking up the line number for an exception creates reference from the
18308 // compilation cache to the global object.
18309 const char* source_exception = "function f(){throw 1;} f()";
18311 v8::HandleScope scope(isolate);
18312 v8::Local<Context> context = Context::New(isolate);
18315 v8::TryCatch try_catch;
18316 CompileRun(source_exception);
18317 CHECK(try_catch.HasCaught());
18318 v8::Handle<v8::Message> message = try_catch.Message();
18319 CHECK(!message.IsEmpty());
18320 CHECK_EQ(1, message->GetLineNumber());
18323 v8::V8::ContextDisposedNotification();
18324 for (gc_count = 1; gc_count < 10; gc_count++) {
18325 other_context->Enter();
18326 CompileRun(source_exception);
18327 other_context->Exit();
18328 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18329 if (GetGlobalObjectsCount() == 1) break;
18331 CHECK_GE(2, gc_count);
18332 CHECK_EQ(1, GetGlobalObjectsCount());
18334 v8::V8::ContextDisposedNotification();
18338 THREADED_TEST(ScriptOrigin) {
18340 v8::HandleScope scope(env->GetIsolate());
18341 v8::ScriptOrigin origin =
18342 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18343 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18344 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18345 v8::Script::Compile(script, &origin)->Run();
18346 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18347 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18348 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18349 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18351 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18352 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18353 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18355 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18356 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18357 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18361 THREADED_TEST(FunctionGetInferredName) {
18363 v8::HandleScope scope(env->GetIsolate());
18364 v8::ScriptOrigin origin =
18365 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18366 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18368 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18369 v8::Script::Compile(script, &origin)->Run();
18370 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18371 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18372 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18376 THREADED_TEST(FunctionGetDisplayName) {
18378 v8::HandleScope scope(env->GetIsolate());
18379 const char* code = "var error = false;"
18380 "function a() { this.x = 1; };"
18381 "a.displayName = 'display_a';"
18382 "var b = (function() {"
18383 " var f = function() { this.x = 2; };"
18384 " f.displayName = 'display_b';"
18387 "var c = function() {};"
18388 "c.__defineGetter__('displayName', function() {"
18390 " throw new Error();"
18393 "d.__defineGetter__('displayName', function() {"
18395 " return 'wrong_display_name';"
18398 "e.displayName = 'wrong_display_name';"
18399 "e.__defineSetter__('displayName', function() {"
18401 " throw new Error();"
18404 "f.displayName = { 'foo': 6, toString: function() {"
18406 " return 'wrong_display_name';"
18408 "var g = function() {"
18409 " arguments.callee.displayName = 'set_in_runtime';"
18412 v8::ScriptOrigin origin =
18413 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18414 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18416 v8::Local<v8::Value> error =
18417 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18418 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18419 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18420 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18421 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18422 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18423 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18424 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18425 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18426 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18427 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18428 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18429 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18430 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18431 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18432 CHECK_EQ(false, error->BooleanValue());
18433 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18434 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18435 CHECK(c->GetDisplayName()->IsUndefined());
18436 CHECK(d->GetDisplayName()->IsUndefined());
18437 CHECK(e->GetDisplayName()->IsUndefined());
18438 CHECK(f->GetDisplayName()->IsUndefined());
18439 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18443 THREADED_TEST(ScriptLineNumber) {
18445 v8::HandleScope scope(env->GetIsolate());
18446 v8::ScriptOrigin origin =
18447 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18448 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18449 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18450 v8::Script::Compile(script, &origin)->Run();
18451 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18452 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18453 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18454 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18455 CHECK_EQ(0, f->GetScriptLineNumber());
18456 CHECK_EQ(2, g->GetScriptLineNumber());
18460 THREADED_TEST(ScriptColumnNumber) {
18462 v8::Isolate* isolate = env->GetIsolate();
18463 v8::HandleScope scope(isolate);
18464 v8::ScriptOrigin origin =
18465 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18466 v8::Integer::New(isolate, 3),
18467 v8::Integer::New(isolate, 2));
18468 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18469 isolate, "function foo() {}\n\n function bar() {}");
18470 v8::Script::Compile(script, &origin)->Run();
18471 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18472 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18473 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18474 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18475 CHECK_EQ(14, foo->GetScriptColumnNumber());
18476 CHECK_EQ(17, bar->GetScriptColumnNumber());
18480 THREADED_TEST(FunctionIsBuiltin) {
18482 v8::Isolate* isolate = env->GetIsolate();
18483 v8::HandleScope scope(isolate);
18484 v8::Local<v8::Function> f;
18485 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18486 CHECK(f->IsBuiltin());
18487 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18488 CHECK(f->IsBuiltin());
18489 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18490 CHECK(f->IsBuiltin());
18491 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18492 CHECK(f->IsBuiltin());
18493 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18494 CHECK(!f->IsBuiltin());
18498 THREADED_TEST(FunctionGetScriptId) {
18500 v8::Isolate* isolate = env->GetIsolate();
18501 v8::HandleScope scope(isolate);
18502 v8::ScriptOrigin origin =
18503 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18504 v8::Integer::New(isolate, 3),
18505 v8::Integer::New(isolate, 2));
18506 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18507 isolate, "function foo() {}\n\n function bar() {}");
18508 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18510 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18511 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18512 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18513 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18514 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18515 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18519 THREADED_TEST(FunctionGetBoundFunction) {
18521 v8::HandleScope scope(env->GetIsolate());
18522 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18523 env->GetIsolate(), "test"));
18524 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18526 "var a = new Object();\n"
18528 "function f () { return this.x };\n"
18529 "var g = f.bind(a);\n"
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 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18535 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18536 CHECK(g->GetBoundFunction()->IsFunction());
18537 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18538 g->GetBoundFunction());
18539 CHECK_EQ(f->GetName(), original_function->GetName());
18540 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18541 CHECK_EQ(f->GetScriptColumnNumber(),
18542 original_function->GetScriptColumnNumber());
18546 static void GetterWhichReturns42(
18547 Local<String> name,
18548 const v8::PropertyCallbackInfo<v8::Value>& info) {
18549 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18550 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18551 info.GetReturnValue().Set(v8_num(42));
18555 static void SetterWhichSetsYOnThisTo23(
18556 Local<String> name,
18557 Local<Value> value,
18558 const v8::PropertyCallbackInfo<void>& info) {
18559 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18560 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18561 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18565 void FooGetInterceptor(Local<String> name,
18566 const v8::PropertyCallbackInfo<v8::Value>& info) {
18567 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18568 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18569 if (!name->Equals(v8_str("foo"))) return;
18570 info.GetReturnValue().Set(v8_num(42));
18574 void FooSetInterceptor(Local<String> name,
18575 Local<Value> value,
18576 const v8::PropertyCallbackInfo<v8::Value>& info) {
18577 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18578 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18579 if (!name->Equals(v8_str("foo"))) return;
18580 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18581 info.GetReturnValue().Set(v8_num(23));
18585 TEST(SetterOnConstructorPrototype) {
18586 v8::Isolate* isolate = CcTest::isolate();
18587 v8::HandleScope scope(isolate);
18588 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18589 templ->SetAccessor(v8_str("x"),
18590 GetterWhichReturns42,
18591 SetterWhichSetsYOnThisTo23);
18592 LocalContext context;
18593 context->Global()->Set(v8_str("P"), templ->NewInstance());
18594 CompileRun("function C1() {"
18597 "C1.prototype = P;"
18601 "C2.prototype = { };"
18602 "C2.prototype.__proto__ = P;");
18604 v8::Local<v8::Script> script;
18605 script = v8_compile("new C1();");
18606 for (int i = 0; i < 10; i++) {
18607 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18608 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18609 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18612 script = v8_compile("new C2();");
18613 for (int i = 0; i < 10; i++) {
18614 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18615 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18616 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18621 static void NamedPropertyGetterWhichReturns42(
18622 Local<String> name,
18623 const v8::PropertyCallbackInfo<v8::Value>& info) {
18624 info.GetReturnValue().Set(v8_num(42));
18628 static void NamedPropertySetterWhichSetsYOnThisTo23(
18629 Local<String> name,
18630 Local<Value> value,
18631 const v8::PropertyCallbackInfo<v8::Value>& info) {
18632 if (name->Equals(v8_str("x"))) {
18633 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18638 THREADED_TEST(InterceptorOnConstructorPrototype) {
18639 v8::Isolate* isolate = CcTest::isolate();
18640 v8::HandleScope scope(isolate);
18641 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18642 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18643 NamedPropertySetterWhichSetsYOnThisTo23);
18644 LocalContext context;
18645 context->Global()->Set(v8_str("P"), templ->NewInstance());
18646 CompileRun("function C1() {"
18649 "C1.prototype = P;"
18653 "C2.prototype = { };"
18654 "C2.prototype.__proto__ = P;");
18656 v8::Local<v8::Script> script;
18657 script = v8_compile("new C1();");
18658 for (int i = 0; i < 10; i++) {
18659 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18660 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18661 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18664 script = v8_compile("new C2();");
18665 for (int i = 0; i < 10; i++) {
18666 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18667 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18668 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18674 const char* source = "function C1() {"
18677 "C1.prototype = P;";
18679 LocalContext context;
18680 v8::Isolate* isolate = context->GetIsolate();
18681 v8::HandleScope scope(isolate);
18682 v8::Local<v8::Script> script;
18684 // Use a simple object as prototype.
18685 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18686 prototype->Set(v8_str("y"), v8_num(42));
18687 context->Global()->Set(v8_str("P"), prototype);
18689 // This compile will add the code to the compilation cache.
18690 CompileRun(source);
18692 script = v8_compile("new C1();");
18693 // Allow enough iterations for the inobject slack tracking logic
18694 // to finalize instance size and install the fast construct stub.
18695 for (int i = 0; i < 256; i++) {
18696 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18697 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18698 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18701 // Use an API object with accessors as prototype.
18702 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18703 templ->SetAccessor(v8_str("x"),
18704 GetterWhichReturns42,
18705 SetterWhichSetsYOnThisTo23);
18706 context->Global()->Set(v8_str("P"), templ->NewInstance());
18708 // This compile will get the code from the compilation cache.
18709 CompileRun(source);
18711 script = v8_compile("new C1();");
18712 for (int i = 0; i < 10; i++) {
18713 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18714 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18715 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18719 v8::Isolate* gc_callbacks_isolate = NULL;
18720 int prologue_call_count = 0;
18721 int epilogue_call_count = 0;
18722 int prologue_call_count_second = 0;
18723 int epilogue_call_count_second = 0;
18724 int prologue_call_count_alloc = 0;
18725 int epilogue_call_count_alloc = 0;
18727 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18728 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18729 ++prologue_call_count;
18733 void PrologueCallback(v8::Isolate* isolate,
18735 v8::GCCallbackFlags flags) {
18736 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18737 CHECK_EQ(gc_callbacks_isolate, isolate);
18738 ++prologue_call_count;
18742 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18743 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18744 ++epilogue_call_count;
18748 void EpilogueCallback(v8::Isolate* isolate,
18750 v8::GCCallbackFlags flags) {
18751 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18752 CHECK_EQ(gc_callbacks_isolate, isolate);
18753 ++epilogue_call_count;
18757 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18758 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18759 ++prologue_call_count_second;
18763 void PrologueCallbackSecond(v8::Isolate* isolate,
18765 v8::GCCallbackFlags flags) {
18766 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18767 CHECK_EQ(gc_callbacks_isolate, isolate);
18768 ++prologue_call_count_second;
18772 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18773 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18774 ++epilogue_call_count_second;
18778 void EpilogueCallbackSecond(v8::Isolate* isolate,
18780 v8::GCCallbackFlags flags) {
18781 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18782 CHECK_EQ(gc_callbacks_isolate, isolate);
18783 ++epilogue_call_count_second;
18787 void PrologueCallbackAlloc(v8::Isolate* isolate,
18789 v8::GCCallbackFlags flags) {
18790 v8::HandleScope scope(isolate);
18792 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18793 CHECK_EQ(gc_callbacks_isolate, isolate);
18794 ++prologue_call_count_alloc;
18796 // Simulate full heap to see if we will reenter this callback
18797 SimulateFullSpace(CcTest::heap()->new_space());
18799 Local<Object> obj = Object::New(isolate);
18800 CHECK(!obj.IsEmpty());
18802 CcTest::heap()->CollectAllGarbage(
18803 i::Heap::kAbortIncrementalMarkingMask);
18807 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18809 v8::GCCallbackFlags flags) {
18810 v8::HandleScope scope(isolate);
18812 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18813 CHECK_EQ(gc_callbacks_isolate, isolate);
18814 ++epilogue_call_count_alloc;
18816 // Simulate full heap to see if we will reenter this callback
18817 SimulateFullSpace(CcTest::heap()->new_space());
18819 Local<Object> obj = Object::New(isolate);
18820 CHECK(!obj.IsEmpty());
18822 CcTest::heap()->CollectAllGarbage(
18823 i::Heap::kAbortIncrementalMarkingMask);
18827 TEST(GCCallbacksOld) {
18828 LocalContext context;
18830 v8::V8::AddGCPrologueCallback(PrologueCallback);
18831 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18832 CHECK_EQ(0, prologue_call_count);
18833 CHECK_EQ(0, epilogue_call_count);
18834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18835 CHECK_EQ(1, prologue_call_count);
18836 CHECK_EQ(1, epilogue_call_count);
18837 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18838 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18839 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18840 CHECK_EQ(2, prologue_call_count);
18841 CHECK_EQ(2, epilogue_call_count);
18842 CHECK_EQ(1, prologue_call_count_second);
18843 CHECK_EQ(1, epilogue_call_count_second);
18844 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18845 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18846 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18847 CHECK_EQ(2, prologue_call_count);
18848 CHECK_EQ(2, epilogue_call_count);
18849 CHECK_EQ(2, prologue_call_count_second);
18850 CHECK_EQ(2, epilogue_call_count_second);
18851 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18852 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18853 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18854 CHECK_EQ(2, prologue_call_count);
18855 CHECK_EQ(2, epilogue_call_count);
18856 CHECK_EQ(2, prologue_call_count_second);
18857 CHECK_EQ(2, epilogue_call_count_second);
18861 TEST(GCCallbacks) {
18862 LocalContext context;
18863 v8::Isolate* isolate = context->GetIsolate();
18864 gc_callbacks_isolate = isolate;
18865 isolate->AddGCPrologueCallback(PrologueCallback);
18866 isolate->AddGCEpilogueCallback(EpilogueCallback);
18867 CHECK_EQ(0, prologue_call_count);
18868 CHECK_EQ(0, epilogue_call_count);
18869 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18870 CHECK_EQ(1, prologue_call_count);
18871 CHECK_EQ(1, epilogue_call_count);
18872 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18873 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18874 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18875 CHECK_EQ(2, prologue_call_count);
18876 CHECK_EQ(2, epilogue_call_count);
18877 CHECK_EQ(1, prologue_call_count_second);
18878 CHECK_EQ(1, epilogue_call_count_second);
18879 isolate->RemoveGCPrologueCallback(PrologueCallback);
18880 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18881 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18882 CHECK_EQ(2, prologue_call_count);
18883 CHECK_EQ(2, epilogue_call_count);
18884 CHECK_EQ(2, prologue_call_count_second);
18885 CHECK_EQ(2, epilogue_call_count_second);
18886 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18887 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18888 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18889 CHECK_EQ(2, prologue_call_count);
18890 CHECK_EQ(2, epilogue_call_count);
18891 CHECK_EQ(2, prologue_call_count_second);
18892 CHECK_EQ(2, epilogue_call_count_second);
18894 CHECK_EQ(0, prologue_call_count_alloc);
18895 CHECK_EQ(0, epilogue_call_count_alloc);
18896 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18897 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18898 CcTest::heap()->CollectAllGarbage(
18899 i::Heap::kAbortIncrementalMarkingMask);
18900 CHECK_EQ(1, prologue_call_count_alloc);
18901 CHECK_EQ(1, epilogue_call_count_alloc);
18902 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18903 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18907 THREADED_TEST(AddToJSFunctionResultCache) {
18908 i::FLAG_stress_compaction = false;
18909 i::FLAG_allow_natives_syntax = true;
18910 v8::HandleScope scope(CcTest::isolate());
18912 LocalContext context;
18918 " var r0 = %_GetFromCache(0, key0);"
18919 " var r1 = %_GetFromCache(0, key1);"
18920 " var r0_ = %_GetFromCache(0, key0);"
18922 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18923 " var r1_ = %_GetFromCache(0, key1);"
18925 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18926 " return 'PASSED';"
18928 CcTest::heap()->ClearJSFunctionResultCaches();
18929 ExpectString(code, "PASSED");
18933 THREADED_TEST(FillJSFunctionResultCache) {
18934 i::FLAG_allow_natives_syntax = true;
18935 LocalContext context;
18936 v8::HandleScope scope(context->GetIsolate());
18941 " var r = %_GetFromCache(0, k);"
18942 " for (var i = 0; i < 16; i++) {"
18943 " %_GetFromCache(0, 'a' + i);"
18945 " if (r === %_GetFromCache(0, k))"
18946 " return 'FAILED: k0CacheSize is too small';"
18947 " return 'PASSED';"
18949 CcTest::heap()->ClearJSFunctionResultCaches();
18950 ExpectString(code, "PASSED");
18954 THREADED_TEST(RoundRobinGetFromCache) {
18955 i::FLAG_allow_natives_syntax = true;
18956 LocalContext context;
18957 v8::HandleScope scope(context->GetIsolate());
18962 " for (var i = 0; i < 16; i++) keys.push(i);"
18963 " var values = [];"
18964 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18965 " for (var i = 0; i < 16; i++) {"
18966 " var v = %_GetFromCache(0, keys[i]);"
18967 " if (v.toString() !== values[i].toString())"
18968 " return 'Wrong value for ' + "
18969 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18971 " return 'PASSED';"
18973 CcTest::heap()->ClearJSFunctionResultCaches();
18974 ExpectString(code, "PASSED");
18978 THREADED_TEST(ReverseGetFromCache) {
18979 i::FLAG_allow_natives_syntax = true;
18980 LocalContext context;
18981 v8::HandleScope scope(context->GetIsolate());
18986 " for (var i = 0; i < 16; i++) keys.push(i);"
18987 " var values = [];"
18988 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18989 " for (var i = 15; i >= 16; i--) {"
18990 " var v = %_GetFromCache(0, keys[i]);"
18991 " if (v !== values[i])"
18992 " return 'Wrong value for ' + "
18993 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18995 " return 'PASSED';"
18997 CcTest::heap()->ClearJSFunctionResultCaches();
18998 ExpectString(code, "PASSED");
19002 THREADED_TEST(TestEviction) {
19003 i::FLAG_allow_natives_syntax = true;
19004 LocalContext context;
19005 v8::HandleScope scope(context->GetIsolate());
19009 " for (var i = 0; i < 2*16; i++) {"
19010 " %_GetFromCache(0, 'a' + i);"
19012 " return 'PASSED';"
19014 CcTest::heap()->ClearJSFunctionResultCaches();
19015 ExpectString(code, "PASSED");
19019 THREADED_TEST(TwoByteStringInAsciiCons) {
19020 // See Chromium issue 47824.
19021 LocalContext context;
19022 v8::HandleScope scope(context->GetIsolate());
19024 const char* init_code =
19025 "var str1 = 'abelspendabel';"
19026 "var str2 = str1 + str1 + str1;"
19028 Local<Value> result = CompileRun(init_code);
19030 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19031 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19033 CHECK(result->IsString());
19034 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19035 int length = string->length();
19036 CHECK(string->IsOneByteRepresentation());
19038 i::Handle<i::String> flat_string = i::String::Flatten(string);
19040 CHECK(string->IsOneByteRepresentation());
19041 CHECK(flat_string->IsOneByteRepresentation());
19043 // Create external resource.
19044 uint16_t* uc16_buffer = new uint16_t[length + 1];
19046 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19047 uc16_buffer[length] = 0;
19049 TestResource resource(uc16_buffer);
19051 flat_string->MakeExternal(&resource);
19053 CHECK(flat_string->IsTwoByteRepresentation());
19055 // If the cons string has been short-circuited, skip the following checks.
19056 if (!string.is_identical_to(flat_string)) {
19057 // At this point, we should have a Cons string which is flat and ASCII,
19058 // with a first half that is a two-byte string (although it only contains
19059 // ASCII characters). This is a valid sequence of steps, and it can happen
19061 CHECK(string->IsOneByteRepresentation());
19062 i::ConsString* cons = i::ConsString::cast(*string);
19063 CHECK_EQ(0, cons->second()->length());
19064 CHECK(cons->first()->IsTwoByteRepresentation());
19067 // Check that some string operations work.
19070 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19071 CHECK_EQ(6, reresult->Int32Value());
19074 reresult = CompileRun("str2.match(/abe./g).length;");
19075 CHECK_EQ(6, reresult->Int32Value());
19077 reresult = CompileRun("str2.search(/bel/g);");
19078 CHECK_EQ(1, reresult->Int32Value());
19080 reresult = CompileRun("str2.search(/be./g);");
19081 CHECK_EQ(1, reresult->Int32Value());
19083 ExpectTrue("/bel/g.test(str2);");
19085 ExpectTrue("/be./g.test(str2);");
19087 reresult = CompileRun("/bel/g.exec(str2);");
19088 CHECK(!reresult->IsNull());
19090 reresult = CompileRun("/be./g.exec(str2);");
19091 CHECK(!reresult->IsNull());
19093 ExpectString("str2.substring(2, 10);", "elspenda");
19095 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19097 ExpectString("str2.charAt(2);", "e");
19099 ExpectObject("str2.indexOf('els');", indexof);
19101 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19103 reresult = CompileRun("str2.charCodeAt(2);");
19104 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19108 TEST(ContainsOnlyOneByte) {
19109 v8::V8::Initialize();
19110 v8::Isolate* isolate = CcTest::isolate();
19111 v8::HandleScope scope(isolate);
19112 // Make a buffer long enough that it won't automatically be converted.
19113 const int length = 512;
19114 // Ensure word aligned assignment.
19115 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19116 i::SmartArrayPointer<uintptr_t>
19117 aligned_contents(new uintptr_t[aligned_length]);
19118 uint16_t* string_contents =
19119 reinterpret_cast<uint16_t*>(aligned_contents.get());
19120 // Set to contain only one byte.
19121 for (int i = 0; i < length-1; i++) {
19122 string_contents[i] = 0x41;
19124 string_contents[length-1] = 0;
19126 Handle<String> string =
19127 String::NewExternal(isolate,
19128 new TestResource(string_contents, NULL, false));
19129 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19130 // Counter example.
19131 string = String::NewFromTwoByte(isolate, string_contents);
19132 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19133 // Test left right and balanced cons strings.
19134 Handle<String> base = String::NewFromUtf8(isolate, "a");
19135 Handle<String> left = base;
19136 Handle<String> right = base;
19137 for (int i = 0; i < 1000; i++) {
19138 left = String::Concat(base, left);
19139 right = String::Concat(right, base);
19141 Handle<String> balanced = String::Concat(left, base);
19142 balanced = String::Concat(balanced, right);
19143 Handle<String> cons_strings[] = {left, balanced, right};
19144 Handle<String> two_byte =
19145 String::NewExternal(isolate,
19146 new TestResource(string_contents, NULL, false));
19147 USE(two_byte); USE(cons_strings);
19148 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19149 // Base assumptions.
19150 string = cons_strings[i];
19151 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19152 // Test left and right concatentation.
19153 string = String::Concat(two_byte, cons_strings[i]);
19154 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19155 string = String::Concat(cons_strings[i], two_byte);
19156 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19158 // Set bits in different positions
19159 // for strings of different lengths and alignments.
19160 for (int alignment = 0; alignment < 7; alignment++) {
19161 for (int size = 2; alignment + size < length; size *= 2) {
19162 int zero_offset = size + alignment;
19163 string_contents[zero_offset] = 0;
19164 for (int i = 0; i < size; i++) {
19165 int shift = 8 + (i % 7);
19166 string_contents[alignment + i] = 1 << shift;
19167 string = String::NewExternal(
19169 new TestResource(string_contents + alignment, NULL, false));
19170 CHECK_EQ(size, string->Length());
19171 CHECK(!string->ContainsOnlyOneByte());
19172 string_contents[alignment + i] = 0x41;
19174 string_contents[zero_offset] = 0x41;
19180 // Failed access check callback that performs a GC on each invocation.
19181 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19182 v8::AccessType type,
19183 Local<v8::Value> data) {
19184 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19188 TEST(GCInFailedAccessCheckCallback) {
19189 // Install a failed access check callback that performs a GC on each
19190 // invocation. Then force the callback to be called from va
19192 v8::V8::Initialize();
19193 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19195 v8::Isolate* isolate = CcTest::isolate();
19196 v8::HandleScope scope(isolate);
19198 // Create an ObjectTemplate for global objects and install access
19199 // check callbacks that will block access.
19200 v8::Handle<v8::ObjectTemplate> global_template =
19201 v8::ObjectTemplate::New(isolate);
19202 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19203 IndexedGetAccessBlocker,
19204 v8::Handle<v8::Value>(),
19207 // Create a context and set an x property on it's global object.
19208 LocalContext context0(NULL, global_template);
19209 context0->Global()->Set(v8_str("x"), v8_num(42));
19210 v8::Handle<v8::Object> global0 = context0->Global();
19212 // Create a context with a different security token so that the
19213 // failed access check callback will be called on each access.
19214 LocalContext context1(NULL, global_template);
19215 context1->Global()->Set(v8_str("other"), global0);
19217 // Get property with failed access check.
19218 ExpectUndefined("other.x");
19220 // Get element with failed access check.
19221 ExpectUndefined("other[0]");
19223 // Set property with failed access check.
19224 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19225 CHECK(result->IsObject());
19227 // Set element with failed access check.
19228 result = CompileRun("other[0] = new Object()");
19229 CHECK(result->IsObject());
19231 // Get property attribute with failed access check.
19232 ExpectFalse("\'x\' in other");
19234 // Get property attribute for element with failed access check.
19235 ExpectFalse("0 in other");
19237 // Delete property.
19238 ExpectFalse("delete other.x");
19241 CHECK_EQ(false, global0->Delete(0));
19245 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19247 // Define JavaScript accessor.
19248 ExpectUndefined("Object.prototype.__defineGetter__.call("
19249 " other, \'x\', function() { return 42; })");
19252 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19256 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19258 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19259 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19260 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19262 // Reset the failed access check callback so it does not influence
19263 // the other tests.
19264 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19268 TEST(IsolateNewDispose) {
19269 v8::Isolate* current_isolate = CcTest::isolate();
19270 v8::Isolate* isolate = v8::Isolate::New();
19271 CHECK(isolate != NULL);
19272 CHECK(current_isolate != isolate);
19273 CHECK(current_isolate == CcTest::isolate());
19275 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19276 last_location = last_message = NULL;
19277 isolate->Dispose();
19278 CHECK_EQ(last_location, NULL);
19279 CHECK_EQ(last_message, NULL);
19283 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19284 v8::Isolate* isolate = v8::Isolate::New();
19286 v8::Isolate::Scope i_scope(isolate);
19287 v8::HandleScope scope(isolate);
19288 LocalContext context(isolate);
19289 // Run something in this isolate.
19290 ExpectTrue("true");
19291 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19292 last_location = last_message = NULL;
19293 // Still entered, should fail.
19294 isolate->Dispose();
19295 CHECK_NE(last_location, NULL);
19296 CHECK_NE(last_message, NULL);
19298 isolate->Dispose();
19302 TEST(RunTwoIsolatesOnSingleThread) {
19304 v8::Isolate* isolate1 = v8::Isolate::New();
19306 v8::Persistent<v8::Context> context1;
19308 v8::HandleScope scope(isolate1);
19309 context1.Reset(isolate1, Context::New(isolate1));
19313 v8::HandleScope scope(isolate1);
19314 v8::Local<v8::Context> context =
19315 v8::Local<v8::Context>::New(isolate1, context1);
19316 v8::Context::Scope context_scope(context);
19317 // Run something in new isolate.
19318 CompileRun("var foo = 'isolate 1';");
19319 ExpectString("function f() { return foo; }; f()", "isolate 1");
19323 v8::Isolate* isolate2 = v8::Isolate::New();
19324 v8::Persistent<v8::Context> context2;
19327 v8::Isolate::Scope iscope(isolate2);
19328 v8::HandleScope scope(isolate2);
19329 context2.Reset(isolate2, Context::New(isolate2));
19330 v8::Local<v8::Context> context =
19331 v8::Local<v8::Context>::New(isolate2, context2);
19332 v8::Context::Scope context_scope(context);
19334 // Run something in new isolate.
19335 CompileRun("var foo = 'isolate 2';");
19336 ExpectString("function f() { return foo; }; f()", "isolate 2");
19340 v8::HandleScope scope(isolate1);
19341 v8::Local<v8::Context> context =
19342 v8::Local<v8::Context>::New(isolate1, context1);
19343 v8::Context::Scope context_scope(context);
19344 // Now again in isolate 1
19345 ExpectString("function f() { return foo; }; f()", "isolate 1");
19350 // Run some stuff in default isolate.
19351 v8::Persistent<v8::Context> context_default;
19353 v8::Isolate* isolate = CcTest::isolate();
19354 v8::Isolate::Scope iscope(isolate);
19355 v8::HandleScope scope(isolate);
19356 context_default.Reset(isolate, Context::New(isolate));
19360 v8::HandleScope scope(CcTest::isolate());
19361 v8::Local<v8::Context> context =
19362 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19363 v8::Context::Scope context_scope(context);
19364 // Variables in other isolates should be not available, verify there
19365 // is an exception.
19366 ExpectTrue("function f() {"
19374 "var isDefaultIsolate = true;"
19381 v8::Isolate::Scope iscope(isolate2);
19382 v8::HandleScope scope(isolate2);
19383 v8::Local<v8::Context> context =
19384 v8::Local<v8::Context>::New(isolate2, context2);
19385 v8::Context::Scope context_scope(context);
19386 ExpectString("function f() { return foo; }; f()", "isolate 2");
19390 v8::HandleScope scope(v8::Isolate::GetCurrent());
19391 v8::Local<v8::Context> context =
19392 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19393 v8::Context::Scope context_scope(context);
19394 ExpectString("function f() { return foo; }; f()", "isolate 1");
19398 v8::Isolate::Scope iscope(isolate2);
19405 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19406 last_location = last_message = NULL;
19408 isolate1->Dispose();
19409 CHECK_EQ(last_location, NULL);
19410 CHECK_EQ(last_message, NULL);
19412 isolate2->Dispose();
19413 CHECK_EQ(last_location, NULL);
19414 CHECK_EQ(last_message, NULL);
19416 // Check that default isolate still runs.
19418 v8::HandleScope scope(CcTest::isolate());
19419 v8::Local<v8::Context> context =
19420 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19421 v8::Context::Scope context_scope(context);
19422 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19427 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19428 v8::Isolate::Scope isolate_scope(isolate);
19429 v8::HandleScope scope(isolate);
19430 LocalContext context(isolate);
19431 i::ScopedVector<char> code(1024);
19432 i::SNPrintF(code, "function fib(n) {"
19433 " if (n <= 2) return 1;"
19434 " return fib(n-1) + fib(n-2);"
19437 Local<Value> value = CompileRun(code.start());
19438 CHECK(value->IsNumber());
19439 return static_cast<int>(value->NumberValue());
19442 class IsolateThread : public v8::internal::Thread {
19444 IsolateThread(v8::Isolate* isolate, int fib_limit)
19445 : Thread("IsolateThread"),
19447 fib_limit_(fib_limit),
19451 result_ = CalcFibonacci(isolate_, fib_limit_);
19454 int result() { return result_; }
19457 v8::Isolate* isolate_;
19463 TEST(MultipleIsolatesOnIndividualThreads) {
19464 v8::Isolate* isolate1 = v8::Isolate::New();
19465 v8::Isolate* isolate2 = v8::Isolate::New();
19467 IsolateThread thread1(isolate1, 21);
19468 IsolateThread thread2(isolate2, 12);
19470 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19474 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19475 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19480 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19481 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19482 CHECK_EQ(result1, 10946);
19483 CHECK_EQ(result2, 144);
19484 CHECK_EQ(result1, thread1.result());
19485 CHECK_EQ(result2, thread2.result());
19487 isolate1->Dispose();
19488 isolate2->Dispose();
19492 TEST(IsolateDifferentContexts) {
19493 v8::Isolate* isolate = v8::Isolate::New();
19494 Local<v8::Context> context;
19496 v8::Isolate::Scope isolate_scope(isolate);
19497 v8::HandleScope handle_scope(isolate);
19498 context = v8::Context::New(isolate);
19499 v8::Context::Scope context_scope(context);
19500 Local<Value> v = CompileRun("2");
19501 CHECK(v->IsNumber());
19502 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19505 v8::Isolate::Scope isolate_scope(isolate);
19506 v8::HandleScope handle_scope(isolate);
19507 context = v8::Context::New(isolate);
19508 v8::Context::Scope context_scope(context);
19509 Local<Value> v = CompileRun("22");
19510 CHECK(v->IsNumber());
19511 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19513 isolate->Dispose();
19516 class InitDefaultIsolateThread : public v8::internal::Thread {
19519 SetResourceConstraints,
19521 SetCounterFunction,
19522 SetCreateHistogramFunction,
19523 SetAddHistogramSampleFunction
19526 explicit InitDefaultIsolateThread(TestCase testCase)
19527 : Thread("InitDefaultIsolateThread"),
19528 testCase_(testCase),
19532 v8::Isolate* isolate = v8::Isolate::New();
19534 switch (testCase_) {
19535 case SetResourceConstraints: {
19536 v8::ResourceConstraints constraints;
19537 constraints.set_max_semi_space_size(1);
19538 constraints.set_max_old_space_size(4);
19539 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19543 case SetFatalHandler:
19544 v8::V8::SetFatalErrorHandler(NULL);
19547 case SetCounterFunction:
19548 CcTest::isolate()->SetCounterFunction(NULL);
19551 case SetCreateHistogramFunction:
19552 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19555 case SetAddHistogramSampleFunction:
19556 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19560 isolate->Dispose();
19564 bool result() { return result_; }
19567 TestCase testCase_;
19572 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19573 InitDefaultIsolateThread thread(testCase);
19576 CHECK_EQ(thread.result(), true);
19580 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19581 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19585 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19586 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19590 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19591 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19595 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19596 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19600 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19601 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19605 TEST(StringCheckMultipleContexts) {
19607 "(function() { return \"a\".charAt(0); })()";
19610 // Run the code twice in the first context to initialize the call IC.
19611 LocalContext context1;
19612 v8::HandleScope scope(context1->GetIsolate());
19613 ExpectString(code, "a");
19614 ExpectString(code, "a");
19618 // Change the String.prototype in the second context and check
19619 // that the right function gets called.
19620 LocalContext context2;
19621 v8::HandleScope scope(context2->GetIsolate());
19622 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19623 ExpectString(code, "not a");
19628 TEST(NumberCheckMultipleContexts) {
19630 "(function() { return (42).toString(); })()";
19633 // Run the code twice in the first context to initialize the call IC.
19634 LocalContext context1;
19635 v8::HandleScope scope(context1->GetIsolate());
19636 ExpectString(code, "42");
19637 ExpectString(code, "42");
19641 // Change the Number.prototype in the second context and check
19642 // that the right function gets called.
19643 LocalContext context2;
19644 v8::HandleScope scope(context2->GetIsolate());
19645 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19646 ExpectString(code, "not 42");
19651 TEST(BooleanCheckMultipleContexts) {
19653 "(function() { return true.toString(); })()";
19656 // Run the code twice in the first context to initialize the call IC.
19657 LocalContext context1;
19658 v8::HandleScope scope(context1->GetIsolate());
19659 ExpectString(code, "true");
19660 ExpectString(code, "true");
19664 // Change the Boolean.prototype in the second context and check
19665 // that the right function gets called.
19666 LocalContext context2;
19667 v8::HandleScope scope(context2->GetIsolate());
19668 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19669 ExpectString(code, "");
19674 TEST(DontDeleteCellLoadIC) {
19675 const char* function_code =
19676 "function readCell() { while (true) { return cell; } }";
19679 // Run the code twice in the first context to initialize the load
19680 // IC for a don't delete cell.
19681 LocalContext context1;
19682 v8::HandleScope scope(context1->GetIsolate());
19683 CompileRun("var cell = \"first\";");
19684 ExpectBoolean("delete cell", false);
19685 CompileRun(function_code);
19686 ExpectString("readCell()", "first");
19687 ExpectString("readCell()", "first");
19691 // Use a deletable cell in the second context.
19692 LocalContext context2;
19693 v8::HandleScope scope(context2->GetIsolate());
19694 CompileRun("cell = \"second\";");
19695 CompileRun(function_code);
19696 ExpectString("readCell()", "second");
19697 ExpectBoolean("delete cell", true);
19698 ExpectString("(function() {"
19700 " return readCell();"
19702 " return e.toString();"
19705 "ReferenceError: cell is not defined");
19706 CompileRun("cell = \"new_second\";");
19707 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19708 ExpectString("readCell()", "new_second");
19709 ExpectString("readCell()", "new_second");
19714 TEST(DontDeleteCellLoadICForceDelete) {
19715 const char* function_code =
19716 "function readCell() { while (true) { return cell; } }";
19718 // Run the code twice to initialize the load IC for a don't delete
19720 LocalContext context;
19721 v8::HandleScope scope(context->GetIsolate());
19722 CompileRun("var cell = \"value\";");
19723 ExpectBoolean("delete cell", false);
19724 CompileRun(function_code);
19725 ExpectString("readCell()", "value");
19726 ExpectString("readCell()", "value");
19728 // Delete the cell using the API and check the inlined code works
19730 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19731 ExpectString("(function() {"
19733 " return readCell();"
19735 " return e.toString();"
19738 "ReferenceError: cell is not defined");
19742 TEST(DontDeleteCellLoadICAPI) {
19743 const char* function_code =
19744 "function readCell() { while (true) { return cell; } }";
19746 // Run the code twice to initialize the load IC for a don't delete
19747 // cell created using the API.
19748 LocalContext context;
19749 v8::HandleScope scope(context->GetIsolate());
19750 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19751 ExpectBoolean("delete cell", false);
19752 CompileRun(function_code);
19753 ExpectString("readCell()", "value");
19754 ExpectString("readCell()", "value");
19756 // Delete the cell using the API and check the inlined code works
19758 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19759 ExpectString("(function() {"
19761 " return readCell();"
19763 " return e.toString();"
19766 "ReferenceError: cell is not defined");
19770 class Visitor42 : public v8::PersistentHandleVisitor {
19772 explicit Visitor42(v8::Persistent<v8::Object>* object)
19773 : counter_(0), object_(object) { }
19775 virtual void VisitPersistentHandle(Persistent<Value>* value,
19776 uint16_t class_id) {
19777 if (class_id != 42) return;
19778 CHECK_EQ(42, value->WrapperClassId());
19779 v8::Isolate* isolate = CcTest::isolate();
19780 v8::HandleScope handle_scope(isolate);
19781 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19782 v8::Handle<v8::Value> object =
19783 v8::Local<v8::Object>::New(isolate, *object_);
19784 CHECK(handle->IsObject());
19785 CHECK_EQ(Handle<Object>::Cast(handle), object);
19790 v8::Persistent<v8::Object>* object_;
19794 TEST(PersistentHandleVisitor) {
19795 LocalContext context;
19796 v8::Isolate* isolate = context->GetIsolate();
19797 v8::HandleScope scope(isolate);
19798 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19799 CHECK_EQ(0, object.WrapperClassId());
19800 object.SetWrapperClassId(42);
19801 CHECK_EQ(42, object.WrapperClassId());
19803 Visitor42 visitor(&object);
19804 v8::V8::VisitHandlesWithClassIds(&visitor);
19805 CHECK_EQ(1, visitor.counter_);
19811 TEST(WrapperClassId) {
19812 LocalContext context;
19813 v8::Isolate* isolate = context->GetIsolate();
19814 v8::HandleScope scope(isolate);
19815 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19816 CHECK_EQ(0, object.WrapperClassId());
19817 object.SetWrapperClassId(65535);
19818 CHECK_EQ(65535, object.WrapperClassId());
19823 TEST(PersistentHandleInNewSpaceVisitor) {
19824 LocalContext context;
19825 v8::Isolate* isolate = context->GetIsolate();
19826 v8::HandleScope scope(isolate);
19827 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19828 CHECK_EQ(0, object1.WrapperClassId());
19829 object1.SetWrapperClassId(42);
19830 CHECK_EQ(42, object1.WrapperClassId());
19832 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19834 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19835 CHECK_EQ(0, object2.WrapperClassId());
19836 object2.SetWrapperClassId(42);
19837 CHECK_EQ(42, object2.WrapperClassId());
19839 Visitor42 visitor(&object2);
19840 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19841 CHECK_EQ(1, visitor.counter_);
19849 LocalContext context;
19850 v8::HandleScope scope(context->GetIsolate());
19852 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19853 CHECK(re->IsRegExp());
19854 CHECK(re->GetSource()->Equals(v8_str("foo")));
19855 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19857 re = v8::RegExp::New(v8_str("bar"),
19858 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19859 v8::RegExp::kGlobal));
19860 CHECK(re->IsRegExp());
19861 CHECK(re->GetSource()->Equals(v8_str("bar")));
19862 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19863 static_cast<int>(re->GetFlags()));
19865 re = v8::RegExp::New(v8_str("baz"),
19866 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19867 v8::RegExp::kMultiline));
19868 CHECK(re->IsRegExp());
19869 CHECK(re->GetSource()->Equals(v8_str("baz")));
19870 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19871 static_cast<int>(re->GetFlags()));
19873 re = CompileRun("/quux/").As<v8::RegExp>();
19874 CHECK(re->IsRegExp());
19875 CHECK(re->GetSource()->Equals(v8_str("quux")));
19876 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19878 re = CompileRun("/quux/gm").As<v8::RegExp>();
19879 CHECK(re->IsRegExp());
19880 CHECK(re->GetSource()->Equals(v8_str("quux")));
19881 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19882 static_cast<int>(re->GetFlags()));
19884 // Override the RegExp constructor and check the API constructor
19886 CompileRun("RegExp = function() {}");
19888 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19889 CHECK(re->IsRegExp());
19890 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19891 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19893 re = v8::RegExp::New(v8_str("foobarbaz"),
19894 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19895 v8::RegExp::kMultiline));
19896 CHECK(re->IsRegExp());
19897 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19898 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19899 static_cast<int>(re->GetFlags()));
19901 context->Global()->Set(v8_str("re"), re);
19902 ExpectTrue("re.test('FoobarbaZ')");
19904 // RegExps are objects on which you can set properties.
19905 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19906 v8::Handle<v8::Value> value(CompileRun("re.property"));
19907 CHECK_EQ(32, value->Int32Value());
19909 v8::TryCatch try_catch;
19910 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19911 CHECK(re.IsEmpty());
19912 CHECK(try_catch.HasCaught());
19913 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19914 ExpectTrue("ex instanceof SyntaxError");
19918 THREADED_TEST(Equals) {
19919 LocalContext localContext;
19920 v8::HandleScope handleScope(localContext->GetIsolate());
19922 v8::Handle<v8::Object> globalProxy = localContext->Global();
19923 v8::Handle<Value> global = globalProxy->GetPrototype();
19925 CHECK(global->StrictEquals(global));
19926 CHECK(!global->StrictEquals(globalProxy));
19927 CHECK(!globalProxy->StrictEquals(global));
19928 CHECK(globalProxy->StrictEquals(globalProxy));
19930 CHECK(global->Equals(global));
19931 CHECK(!global->Equals(globalProxy));
19932 CHECK(!globalProxy->Equals(global));
19933 CHECK(globalProxy->Equals(globalProxy));
19937 static void Getter(v8::Local<v8::String> property,
19938 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19939 info.GetReturnValue().Set(v8_str("42!"));
19943 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19944 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19945 result->Set(0, v8_str("universalAnswer"));
19946 info.GetReturnValue().Set(result);
19950 TEST(NamedEnumeratorAndForIn) {
19951 LocalContext context;
19952 v8::Isolate* isolate = context->GetIsolate();
19953 v8::HandleScope handle_scope(isolate);
19954 v8::Context::Scope context_scope(context.local());
19956 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19957 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19958 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19959 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19960 "var result = []; for (var k in o) result.push(k); result"));
19961 CHECK_EQ(1, result->Length());
19962 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19966 TEST(DefinePropertyPostDetach) {
19967 LocalContext context;
19968 v8::HandleScope scope(context->GetIsolate());
19969 v8::Handle<v8::Object> proxy = context->Global();
19970 v8::Handle<v8::Function> define_property =
19971 CompileRun("(function() {"
19972 " Object.defineProperty("
19975 " { configurable: true, enumerable: true, value: 3 });"
19976 "})").As<Function>();
19977 context->DetachGlobal();
19978 define_property->Call(proxy, 0, NULL);
19982 static void InstallContextId(v8::Handle<Context> context, int id) {
19983 Context::Scope scope(context);
19984 CompileRun("Object.prototype").As<Object>()->
19985 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19989 static void CheckContextId(v8::Handle<Object> object, int expected) {
19990 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19994 THREADED_TEST(CreationContext) {
19995 v8::Isolate* isolate = CcTest::isolate();
19996 HandleScope handle_scope(isolate);
19997 Handle<Context> context1 = Context::New(isolate);
19998 InstallContextId(context1, 1);
19999 Handle<Context> context2 = Context::New(isolate);
20000 InstallContextId(context2, 2);
20001 Handle<Context> context3 = Context::New(isolate);
20002 InstallContextId(context3, 3);
20004 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20006 Local<Object> object1;
20007 Local<Function> func1;
20009 Context::Scope scope(context1);
20010 object1 = Object::New(isolate);
20011 func1 = tmpl->GetFunction();
20014 Local<Object> object2;
20015 Local<Function> func2;
20017 Context::Scope scope(context2);
20018 object2 = Object::New(isolate);
20019 func2 = tmpl->GetFunction();
20022 Local<Object> instance1;
20023 Local<Object> instance2;
20026 Context::Scope scope(context3);
20027 instance1 = func1->NewInstance();
20028 instance2 = func2->NewInstance();
20031 CHECK(object1->CreationContext() == context1);
20032 CheckContextId(object1, 1);
20033 CHECK(func1->CreationContext() == context1);
20034 CheckContextId(func1, 1);
20035 CHECK(instance1->CreationContext() == context1);
20036 CheckContextId(instance1, 1);
20037 CHECK(object2->CreationContext() == context2);
20038 CheckContextId(object2, 2);
20039 CHECK(func2->CreationContext() == context2);
20040 CheckContextId(func2, 2);
20041 CHECK(instance2->CreationContext() == context2);
20042 CheckContextId(instance2, 2);
20045 Context::Scope scope(context1);
20046 CHECK(object1->CreationContext() == context1);
20047 CheckContextId(object1, 1);
20048 CHECK(func1->CreationContext() == context1);
20049 CheckContextId(func1, 1);
20050 CHECK(instance1->CreationContext() == context1);
20051 CheckContextId(instance1, 1);
20052 CHECK(object2->CreationContext() == context2);
20053 CheckContextId(object2, 2);
20054 CHECK(func2->CreationContext() == context2);
20055 CheckContextId(func2, 2);
20056 CHECK(instance2->CreationContext() == context2);
20057 CheckContextId(instance2, 2);
20061 Context::Scope scope(context2);
20062 CHECK(object1->CreationContext() == context1);
20063 CheckContextId(object1, 1);
20064 CHECK(func1->CreationContext() == context1);
20065 CheckContextId(func1, 1);
20066 CHECK(instance1->CreationContext() == context1);
20067 CheckContextId(instance1, 1);
20068 CHECK(object2->CreationContext() == context2);
20069 CheckContextId(object2, 2);
20070 CHECK(func2->CreationContext() == context2);
20071 CheckContextId(func2, 2);
20072 CHECK(instance2->CreationContext() == context2);
20073 CheckContextId(instance2, 2);
20078 THREADED_TEST(CreationContextOfJsFunction) {
20079 HandleScope handle_scope(CcTest::isolate());
20080 Handle<Context> context = Context::New(CcTest::isolate());
20081 InstallContextId(context, 1);
20083 Local<Object> function;
20085 Context::Scope scope(context);
20086 function = CompileRun("function foo() {}; foo").As<Object>();
20089 CHECK(function->CreationContext() == context);
20090 CheckContextId(function, 1);
20094 void HasOwnPropertyIndexedPropertyGetter(
20096 const v8::PropertyCallbackInfo<v8::Value>& info) {
20097 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20101 void HasOwnPropertyNamedPropertyGetter(
20102 Local<String> property,
20103 const v8::PropertyCallbackInfo<v8::Value>& info) {
20104 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20108 void HasOwnPropertyIndexedPropertyQuery(
20109 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20110 if (index == 42) info.GetReturnValue().Set(1);
20114 void HasOwnPropertyNamedPropertyQuery(
20115 Local<String> property,
20116 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20117 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20121 void HasOwnPropertyNamedPropertyQuery2(
20122 Local<String> property,
20123 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20124 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20128 void HasOwnPropertyAccessorGetter(
20129 Local<String> property,
20130 const v8::PropertyCallbackInfo<v8::Value>& info) {
20131 info.GetReturnValue().Set(v8_str("yes"));
20135 TEST(HasOwnProperty) {
20137 v8::Isolate* isolate = env->GetIsolate();
20138 v8::HandleScope scope(isolate);
20139 { // Check normal properties and defined getters.
20140 Handle<Value> value = CompileRun(
20143 " this.__defineGetter__('baz', function() { return 1; });"
20145 "function Bar() { "
20147 " this.__defineGetter__('bla', function() { return 2; });"
20149 "Bar.prototype = new Foo();"
20151 CHECK(value->IsObject());
20152 Handle<Object> object = value->ToObject();
20153 CHECK(object->Has(v8_str("foo")));
20154 CHECK(!object->HasOwnProperty(v8_str("foo")));
20155 CHECK(object->HasOwnProperty(v8_str("bar")));
20156 CHECK(object->Has(v8_str("baz")));
20157 CHECK(!object->HasOwnProperty(v8_str("baz")));
20158 CHECK(object->HasOwnProperty(v8_str("bla")));
20160 { // Check named getter interceptors.
20161 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20162 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20163 Handle<Object> instance = templ->NewInstance();
20164 CHECK(!instance->HasOwnProperty(v8_str("42")));
20165 CHECK(instance->HasOwnProperty(v8_str("foo")));
20166 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20168 { // Check indexed getter interceptors.
20169 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20170 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20171 Handle<Object> instance = templ->NewInstance();
20172 CHECK(instance->HasOwnProperty(v8_str("42")));
20173 CHECK(!instance->HasOwnProperty(v8_str("43")));
20174 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20176 { // Check named query interceptors.
20177 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20178 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20179 Handle<Object> instance = templ->NewInstance();
20180 CHECK(instance->HasOwnProperty(v8_str("foo")));
20181 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20183 { // Check indexed query interceptors.
20184 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20185 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20186 Handle<Object> instance = templ->NewInstance();
20187 CHECK(instance->HasOwnProperty(v8_str("42")));
20188 CHECK(!instance->HasOwnProperty(v8_str("41")));
20190 { // Check callbacks.
20191 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20192 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20193 Handle<Object> instance = templ->NewInstance();
20194 CHECK(instance->HasOwnProperty(v8_str("foo")));
20195 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20197 { // Check that query wins on disagreement.
20198 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20199 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20201 HasOwnPropertyNamedPropertyQuery2);
20202 Handle<Object> instance = templ->NewInstance();
20203 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20204 CHECK(instance->HasOwnProperty(v8_str("bar")));
20209 TEST(IndexedInterceptorWithStringProto) {
20210 v8::Isolate* isolate = CcTest::isolate();
20211 v8::HandleScope scope(isolate);
20212 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20213 templ->SetIndexedPropertyHandler(NULL,
20215 HasOwnPropertyIndexedPropertyQuery);
20216 LocalContext context;
20217 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20218 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20219 // These should be intercepted.
20220 CHECK(CompileRun("42 in obj")->BooleanValue());
20221 CHECK(CompileRun("'42' in obj")->BooleanValue());
20222 // These should fall through to the String prototype.
20223 CHECK(CompileRun("0 in obj")->BooleanValue());
20224 CHECK(CompileRun("'0' in obj")->BooleanValue());
20225 // And these should both fail.
20226 CHECK(!CompileRun("32 in obj")->BooleanValue());
20227 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20231 void CheckCodeGenerationAllowed() {
20232 Handle<Value> result = CompileRun("eval('42')");
20233 CHECK_EQ(42, result->Int32Value());
20234 result = CompileRun("(function(e) { return e('42'); })(eval)");
20235 CHECK_EQ(42, result->Int32Value());
20236 result = CompileRun("var f = new Function('return 42'); f()");
20237 CHECK_EQ(42, result->Int32Value());
20241 void CheckCodeGenerationDisallowed() {
20242 TryCatch try_catch;
20244 Handle<Value> result = CompileRun("eval('42')");
20245 CHECK(result.IsEmpty());
20246 CHECK(try_catch.HasCaught());
20249 result = CompileRun("(function(e) { return e('42'); })(eval)");
20250 CHECK(result.IsEmpty());
20251 CHECK(try_catch.HasCaught());
20254 result = CompileRun("var f = new Function('return 42'); f()");
20255 CHECK(result.IsEmpty());
20256 CHECK(try_catch.HasCaught());
20260 bool CodeGenerationAllowed(Local<Context> context) {
20261 ApiTestFuzzer::Fuzz();
20266 bool CodeGenerationDisallowed(Local<Context> context) {
20267 ApiTestFuzzer::Fuzz();
20272 THREADED_TEST(AllowCodeGenFromStrings) {
20273 LocalContext context;
20274 v8::HandleScope scope(context->GetIsolate());
20276 // eval and the Function constructor allowed by default.
20277 CHECK(context->IsCodeGenerationFromStringsAllowed());
20278 CheckCodeGenerationAllowed();
20280 // Disallow eval and the Function constructor.
20281 context->AllowCodeGenerationFromStrings(false);
20282 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20283 CheckCodeGenerationDisallowed();
20286 context->AllowCodeGenerationFromStrings(true);
20287 CheckCodeGenerationAllowed();
20289 // Disallow but setting a global callback that will allow the calls.
20290 context->AllowCodeGenerationFromStrings(false);
20291 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20292 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20293 CheckCodeGenerationAllowed();
20295 // Set a callback that disallows the code generation.
20296 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20297 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20298 CheckCodeGenerationDisallowed();
20302 TEST(SetErrorMessageForCodeGenFromStrings) {
20303 LocalContext context;
20304 v8::HandleScope scope(context->GetIsolate());
20305 TryCatch try_catch;
20307 Handle<String> message = v8_str("Message") ;
20308 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20309 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20310 context->AllowCodeGenerationFromStrings(false);
20311 context->SetErrorMessageForCodeGenerationFromStrings(message);
20312 Handle<Value> result = CompileRun("eval('42')");
20313 CHECK(result.IsEmpty());
20314 CHECK(try_catch.HasCaught());
20315 Handle<String> actual_message = try_catch.Message()->Get();
20316 CHECK(expected_message->Equals(actual_message));
20320 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20324 THREADED_TEST(CallAPIFunctionOnNonObject) {
20325 LocalContext context;
20326 v8::Isolate* isolate = context->GetIsolate();
20327 v8::HandleScope scope(isolate);
20328 Handle<FunctionTemplate> templ =
20329 v8::FunctionTemplate::New(isolate, NonObjectThis);
20330 Handle<Function> function = templ->GetFunction();
20331 context->Global()->Set(v8_str("f"), function);
20332 TryCatch try_catch;
20333 CompileRun("f.call(2)");
20337 // Regression test for issue 1470.
20338 THREADED_TEST(ReadOnlyIndexedProperties) {
20339 v8::Isolate* isolate = CcTest::isolate();
20340 v8::HandleScope scope(isolate);
20341 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20343 LocalContext context;
20344 Local<v8::Object> obj = templ->NewInstance();
20345 context->Global()->Set(v8_str("obj"), obj);
20346 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20347 obj->Set(v8_str("1"), v8_str("foobar"));
20348 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20349 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20350 obj->Set(v8_num(2), v8_str("foobar"));
20351 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20353 // Test non-smi case.
20354 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20355 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20356 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20360 THREADED_TEST(Regress1516) {
20361 LocalContext context;
20362 v8::HandleScope scope(context->GetIsolate());
20364 { v8::HandleScope temp_scope(context->GetIsolate());
20365 CompileRun("({'a': 0})");
20369 { i::MapCache* map_cache =
20370 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20371 elements = map_cache->NumberOfElements();
20372 CHECK_LE(1, elements);
20375 CcTest::heap()->CollectAllGarbage(
20376 i::Heap::kAbortIncrementalMarkingMask);
20377 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20378 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20379 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20380 CHECK_GT(elements, map_cache->NumberOfElements());
20386 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20388 v8::AccessType type,
20389 Local<Value> data) {
20390 // Only block read access to __proto__.
20391 if (type == v8::ACCESS_GET &&
20392 name->IsString() &&
20393 name->ToString()->Length() == 9 &&
20394 name->ToString()->Utf8Length() == 9) {
20396 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20397 return strncmp(buffer, "__proto__", 9) != 0;
20404 THREADED_TEST(Regress93759) {
20405 v8::Isolate* isolate = CcTest::isolate();
20406 HandleScope scope(isolate);
20408 // Template for object with security check.
20409 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20410 // We don't do indexing, so any callback can be used for that.
20411 no_proto_template->SetAccessCheckCallbacks(
20412 BlockProtoNamedSecurityTestCallback,
20413 IndexedSecurityTestCallback);
20415 // Templates for objects with hidden prototypes and possibly security check.
20416 Local<FunctionTemplate> hidden_proto_template =
20417 v8::FunctionTemplate::New(isolate);
20418 hidden_proto_template->SetHiddenPrototype(true);
20420 Local<FunctionTemplate> protected_hidden_proto_template =
20421 v8::FunctionTemplate::New(isolate);
20422 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20423 BlockProtoNamedSecurityTestCallback,
20424 IndexedSecurityTestCallback);
20425 protected_hidden_proto_template->SetHiddenPrototype(true);
20427 // Context for "foreign" objects used in test.
20428 Local<Context> context = v8::Context::New(isolate);
20431 // Plain object, no security check.
20432 Local<Object> simple_object = Object::New(isolate);
20434 // Object with explicit security check.
20435 Local<Object> protected_object =
20436 no_proto_template->NewInstance();
20438 // JSGlobalProxy object, always have security check.
20439 Local<Object> proxy_object =
20442 // Global object, the prototype of proxy_object. No security checks.
20443 Local<Object> global_object =
20444 proxy_object->GetPrototype()->ToObject();
20446 // Hidden prototype without security check.
20447 Local<Object> hidden_prototype =
20448 hidden_proto_template->GetFunction()->NewInstance();
20449 Local<Object> object_with_hidden =
20450 Object::New(isolate);
20451 object_with_hidden->SetPrototype(hidden_prototype);
20453 // Hidden prototype with security check on the hidden prototype.
20454 Local<Object> protected_hidden_prototype =
20455 protected_hidden_proto_template->GetFunction()->NewInstance();
20456 Local<Object> object_with_protected_hidden =
20457 Object::New(isolate);
20458 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20462 // Template for object for second context. Values to test are put on it as
20464 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20465 global_template->Set(v8_str("simple"), simple_object);
20466 global_template->Set(v8_str("protected"), protected_object);
20467 global_template->Set(v8_str("global"), global_object);
20468 global_template->Set(v8_str("proxy"), proxy_object);
20469 global_template->Set(v8_str("hidden"), object_with_hidden);
20470 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20472 LocalContext context2(NULL, global_template);
20474 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20475 CHECK(result1->Equals(simple_object->GetPrototype()));
20477 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20478 CHECK(result2->Equals(Undefined(isolate)));
20480 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20481 CHECK(result3->Equals(global_object->GetPrototype()));
20483 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20484 CHECK(result4->Equals(Undefined(isolate)));
20486 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20487 CHECK(result5->Equals(
20488 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20490 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20491 CHECK(result6->Equals(Undefined(isolate)));
20495 THREADED_TEST(Regress125988) {
20496 v8::HandleScope scope(CcTest::isolate());
20497 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20498 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20500 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20501 CompileRun("var a = new Object();"
20502 "var b = new Intercept();"
20503 "var c = new Object();"
20507 "for (var i = 0; i < 3; i++) c.x;");
20508 ExpectBoolean("c.hasOwnProperty('x')", false);
20509 ExpectInt32("c.x", 23);
20510 CompileRun("a.y = 42;"
20511 "for (var i = 0; i < 3; i++) c.x;");
20512 ExpectBoolean("c.hasOwnProperty('x')", false);
20513 ExpectInt32("c.x", 23);
20514 ExpectBoolean("c.hasOwnProperty('y')", false);
20515 ExpectInt32("c.y", 42);
20519 static void TestReceiver(Local<Value> expected_result,
20520 Local<Value> expected_receiver,
20521 const char* code) {
20522 Local<Value> result = CompileRun(code);
20523 CHECK(result->IsObject());
20524 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20525 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20529 THREADED_TEST(ForeignFunctionReceiver) {
20530 v8::Isolate* isolate = CcTest::isolate();
20531 HandleScope scope(isolate);
20533 // Create two contexts with different "id" properties ('i' and 'o').
20534 // Call a function both from its own context and from a the foreign
20535 // context, and see what "this" is bound to (returning both "this"
20536 // and "this.id" for comparison).
20538 Local<Context> foreign_context = v8::Context::New(isolate);
20539 foreign_context->Enter();
20540 Local<Value> foreign_function =
20541 CompileRun("function func() { return { 0: this.id, "
20543 " toString: function() { "
20550 CHECK(foreign_function->IsFunction());
20551 foreign_context->Exit();
20553 LocalContext context;
20555 Local<String> password = v8_str("Password");
20556 // Don't get hit by security checks when accessing foreign_context's
20557 // global receiver (aka. global proxy).
20558 context->SetSecurityToken(password);
20559 foreign_context->SetSecurityToken(password);
20561 Local<String> i = v8_str("i");
20562 Local<String> o = v8_str("o");
20563 Local<String> id = v8_str("id");
20565 CompileRun("function ownfunc() { return { 0: this.id, "
20567 " toString: function() { "
20574 context->Global()->Set(v8_str("func"), foreign_function);
20576 // Sanity check the contexts.
20577 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20578 CHECK(o->Equals(context->Global()->Get(id)));
20580 // Checking local function's receiver.
20581 // Calling function using its call/apply methods.
20582 TestReceiver(o, context->Global(), "ownfunc.call()");
20583 TestReceiver(o, context->Global(), "ownfunc.apply()");
20584 // Making calls through built-in functions.
20585 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20586 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20587 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20588 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20589 // Calling with environment record as base.
20590 TestReceiver(o, context->Global(), "ownfunc()");
20591 // Calling with no base.
20592 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20594 // Checking foreign function return value.
20595 // Calling function using its call/apply methods.
20596 TestReceiver(i, foreign_context->Global(), "func.call()");
20597 TestReceiver(i, foreign_context->Global(), "func.apply()");
20598 // Calling function using another context's call/apply methods.
20599 TestReceiver(i, foreign_context->Global(),
20600 "Function.prototype.call.call(func)");
20601 TestReceiver(i, foreign_context->Global(),
20602 "Function.prototype.call.apply(func)");
20603 TestReceiver(i, foreign_context->Global(),
20604 "Function.prototype.apply.call(func)");
20605 TestReceiver(i, foreign_context->Global(),
20606 "Function.prototype.apply.apply(func)");
20607 // Making calls through built-in functions.
20608 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20609 // ToString(func()) is func()[0], i.e., the returned this.id.
20610 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20611 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20612 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20614 // Calling with environment record as base.
20615 TestReceiver(i, foreign_context->Global(), "func()");
20616 // Calling with no base.
20617 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20621 uint8_t callback_fired = 0;
20624 void CallCompletedCallback1() {
20625 i::OS::Print("Firing callback 1.\n");
20626 callback_fired ^= 1; // Toggle first bit.
20630 void CallCompletedCallback2() {
20631 i::OS::Print("Firing callback 2.\n");
20632 callback_fired ^= 2; // Toggle second bit.
20636 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20637 int32_t level = args[0]->Int32Value();
20640 i::OS::Print("Entering recursion level %d.\n", level);
20642 i::Vector<char> script_vector(script, sizeof(script));
20643 i::SNPrintF(script_vector, "recursion(%d)", level);
20644 CompileRun(script_vector.start());
20645 i::OS::Print("Leaving recursion level %d.\n", level);
20646 CHECK_EQ(0, callback_fired);
20648 i::OS::Print("Recursion ends.\n");
20649 CHECK_EQ(0, callback_fired);
20654 TEST(CallCompletedCallback) {
20656 v8::HandleScope scope(env->GetIsolate());
20657 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20658 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20659 env->Global()->Set(v8_str("recursion"),
20660 recursive_runtime->GetFunction());
20661 // Adding the same callback a second time has no effect.
20662 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20663 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20664 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20665 i::OS::Print("--- Script (1) ---\n");
20666 Local<Script> script = v8::Script::Compile(
20667 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20669 CHECK_EQ(3, callback_fired);
20671 i::OS::Print("\n--- Script (2) ---\n");
20672 callback_fired = 0;
20673 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20675 CHECK_EQ(2, callback_fired);
20677 i::OS::Print("\n--- Function ---\n");
20678 callback_fired = 0;
20679 Local<Function> recursive_function =
20680 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20681 v8::Handle<Value> args[] = { v8_num(0) };
20682 recursive_function->Call(env->Global(), 1, args);
20683 CHECK_EQ(2, callback_fired);
20687 void CallCompletedCallbackNoException() {
20688 v8::HandleScope scope(CcTest::isolate());
20689 CompileRun("1+1;");
20693 void CallCompletedCallbackException() {
20694 v8::HandleScope scope(CcTest::isolate());
20695 CompileRun("throw 'second exception';");
20699 TEST(CallCompletedCallbackOneException) {
20701 v8::HandleScope scope(env->GetIsolate());
20702 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20703 CompileRun("throw 'exception';");
20707 TEST(CallCompletedCallbackTwoExceptions) {
20709 v8::HandleScope scope(env->GetIsolate());
20710 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20711 CompileRun("throw 'first exception';");
20715 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20716 v8::HandleScope scope(info.GetIsolate());
20717 CompileRun("ext1Calls++;");
20721 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20722 v8::HandleScope scope(info.GetIsolate());
20723 CompileRun("ext2Calls++;");
20727 void* g_passed_to_three = NULL;
20730 static void MicrotaskThree(void* data) {
20731 g_passed_to_three = data;
20735 TEST(EnqueueMicrotask) {
20737 v8::HandleScope scope(env->GetIsolate());
20739 "var ext1Calls = 0;"
20740 "var ext2Calls = 0;");
20741 CompileRun("1+1;");
20742 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20743 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20745 env->GetIsolate()->EnqueueMicrotask(
20746 Function::New(env->GetIsolate(), MicrotaskOne));
20747 CompileRun("1+1;");
20748 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20749 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20751 env->GetIsolate()->EnqueueMicrotask(
20752 Function::New(env->GetIsolate(), MicrotaskOne));
20753 env->GetIsolate()->EnqueueMicrotask(
20754 Function::New(env->GetIsolate(), MicrotaskTwo));
20755 CompileRun("1+1;");
20756 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20757 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20759 env->GetIsolate()->EnqueueMicrotask(
20760 Function::New(env->GetIsolate(), MicrotaskTwo));
20761 CompileRun("1+1;");
20762 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20763 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20765 CompileRun("1+1;");
20766 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20767 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20769 g_passed_to_three = NULL;
20770 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20771 CompileRun("1+1;");
20772 CHECK_EQ(NULL, g_passed_to_three);
20773 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20774 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20777 env->GetIsolate()->EnqueueMicrotask(
20778 Function::New(env->GetIsolate(), MicrotaskOne));
20779 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20780 env->GetIsolate()->EnqueueMicrotask(
20781 Function::New(env->GetIsolate(), MicrotaskTwo));
20782 CompileRun("1+1;");
20783 CHECK_EQ(&dummy, g_passed_to_three);
20784 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20785 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20786 g_passed_to_three = NULL;
20790 static void MicrotaskExceptionOne(
20791 const v8::FunctionCallbackInfo<Value>& info) {
20792 v8::HandleScope scope(info.GetIsolate());
20793 CompileRun("exception1Calls++;");
20794 info.GetIsolate()->ThrowException(
20795 v8::Exception::Error(v8_str("first")));
20799 static void MicrotaskExceptionTwo(
20800 const v8::FunctionCallbackInfo<Value>& info) {
20801 v8::HandleScope scope(info.GetIsolate());
20802 CompileRun("exception2Calls++;");
20803 info.GetIsolate()->ThrowException(
20804 v8::Exception::Error(v8_str("second")));
20808 TEST(RunMicrotasksIgnoresThrownExceptions) {
20810 v8::Isolate* isolate = env->GetIsolate();
20811 v8::HandleScope scope(isolate);
20813 "var exception1Calls = 0;"
20814 "var exception2Calls = 0;");
20815 isolate->EnqueueMicrotask(
20816 Function::New(isolate, MicrotaskExceptionOne));
20817 isolate->EnqueueMicrotask(
20818 Function::New(isolate, MicrotaskExceptionTwo));
20819 TryCatch try_catch;
20820 CompileRun("1+1;");
20821 CHECK(!try_catch.HasCaught());
20822 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20823 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20827 TEST(SetAutorunMicrotasks) {
20829 v8::HandleScope scope(env->GetIsolate());
20831 "var ext1Calls = 0;"
20832 "var ext2Calls = 0;");
20833 CompileRun("1+1;");
20834 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20835 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20837 env->GetIsolate()->EnqueueMicrotask(
20838 Function::New(env->GetIsolate(), MicrotaskOne));
20839 CompileRun("1+1;");
20840 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20841 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20843 env->GetIsolate()->SetAutorunMicrotasks(false);
20844 env->GetIsolate()->EnqueueMicrotask(
20845 Function::New(env->GetIsolate(), MicrotaskOne));
20846 env->GetIsolate()->EnqueueMicrotask(
20847 Function::New(env->GetIsolate(), MicrotaskTwo));
20848 CompileRun("1+1;");
20849 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20850 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20852 env->GetIsolate()->RunMicrotasks();
20853 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20854 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20856 env->GetIsolate()->EnqueueMicrotask(
20857 Function::New(env->GetIsolate(), MicrotaskTwo));
20858 CompileRun("1+1;");
20859 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20860 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20862 env->GetIsolate()->RunMicrotasks();
20863 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20864 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20866 env->GetIsolate()->SetAutorunMicrotasks(true);
20867 env->GetIsolate()->EnqueueMicrotask(
20868 Function::New(env->GetIsolate(), MicrotaskTwo));
20869 CompileRun("1+1;");
20870 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20871 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20873 env->GetIsolate()->EnqueueMicrotask(
20874 Function::New(env->GetIsolate(), MicrotaskTwo));
20876 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20877 CompileRun("1+1;");
20878 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20879 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20882 CompileRun("1+1;");
20883 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20884 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20888 TEST(RunMicrotasksWithoutEnteringContext) {
20889 v8::Isolate* isolate = CcTest::isolate();
20890 HandleScope handle_scope(isolate);
20891 isolate->SetAutorunMicrotasks(false);
20892 Handle<Context> context = Context::New(isolate);
20894 Context::Scope context_scope(context);
20895 CompileRun("var ext1Calls = 0;");
20896 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20898 isolate->RunMicrotasks();
20900 Context::Scope context_scope(context);
20901 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20903 isolate->SetAutorunMicrotasks(true);
20908 static int probes_counter = 0;
20909 static int misses_counter = 0;
20910 static int updates_counter = 0;
20913 static int* LookupCounter(const char* name) {
20914 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20915 return &probes_counter;
20916 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20917 return &misses_counter;
20918 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20919 return &updates_counter;
20925 static const char* kMegamorphicTestProgram =
20926 "function ClassA() { };"
20927 "function ClassB() { };"
20928 "ClassA.prototype.foo = function() { };"
20929 "ClassB.prototype.foo = function() { };"
20930 "function fooify(obj) { obj.foo(); };"
20931 "var a = new ClassA();"
20932 "var b = new ClassB();"
20933 "for (var i = 0; i < 10000; i++) {"
20940 static void StubCacheHelper(bool primary) {
20942 i::FLAG_native_code_counters = true;
20944 i::FLAG_test_primary_stub_cache = true;
20946 i::FLAG_test_secondary_stub_cache = true;
20948 i::FLAG_crankshaft = false;
20950 env->GetIsolate()->SetCounterFunction(LookupCounter);
20951 v8::HandleScope scope(env->GetIsolate());
20952 int initial_probes = probes_counter;
20953 int initial_misses = misses_counter;
20954 int initial_updates = updates_counter;
20955 CompileRun(kMegamorphicTestProgram);
20956 int probes = probes_counter - initial_probes;
20957 int misses = misses_counter - initial_misses;
20958 int updates = updates_counter - initial_updates;
20959 CHECK_LT(updates, 10);
20960 CHECK_LT(misses, 10);
20961 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20962 // before megamorphism. The number of probes will only work once we teach the
20963 // serializer to embed references to counters in the stubs, given that the
20964 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20965 CHECK_GE(probes, 0);
20970 TEST(SecondaryStubCache) {
20971 StubCacheHelper(true);
20975 TEST(PrimaryStubCache) {
20976 StubCacheHelper(false);
20981 static int cow_arrays_created_runtime = 0;
20984 static int* LookupCounterCOWArrays(const char* name) {
20985 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20986 return &cow_arrays_created_runtime;
20993 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20995 i::FLAG_native_code_counters = true;
20997 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
20998 v8::HandleScope scope(env->GetIsolate());
20999 int initial_cow_arrays = cow_arrays_created_runtime;
21000 CompileRun("var o = [1, 2, 3];");
21001 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21002 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21003 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21004 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21005 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21010 TEST(StaticGetters) {
21011 LocalContext context;
21012 i::Factory* factory = CcTest::i_isolate()->factory();
21013 v8::Isolate* isolate = CcTest::isolate();
21014 v8::HandleScope scope(isolate);
21015 i::Handle<i::Object> undefined_value = factory->undefined_value();
21016 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21017 i::Handle<i::Object> null_value = factory->null_value();
21018 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21019 i::Handle<i::Object> true_value = factory->true_value();
21020 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21021 i::Handle<i::Object> false_value = factory->false_value();
21022 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21026 UNINITIALIZED_TEST(IsolateEmbedderData) {
21027 CcTest::DisableAutomaticDispose();
21028 v8::Isolate* isolate = v8::Isolate::New();
21030 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21031 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21032 CHECK_EQ(NULL, isolate->GetData(slot));
21033 CHECK_EQ(NULL, i_isolate->GetData(slot));
21035 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21036 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21037 isolate->SetData(slot, data);
21039 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21040 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21041 CHECK_EQ(data, isolate->GetData(slot));
21042 CHECK_EQ(data, i_isolate->GetData(slot));
21044 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21045 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21046 isolate->SetData(slot, data);
21048 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21049 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21050 CHECK_EQ(data, isolate->GetData(slot));
21051 CHECK_EQ(data, i_isolate->GetData(slot));
21054 isolate->Dispose();
21058 TEST(StringEmpty) {
21059 LocalContext context;
21060 i::Factory* factory = CcTest::i_isolate()->factory();
21061 v8::Isolate* isolate = CcTest::isolate();
21062 v8::HandleScope scope(isolate);
21063 i::Handle<i::Object> empty_string = factory->empty_string();
21064 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21068 static int instance_checked_getter_count = 0;
21069 static void InstanceCheckedGetter(
21070 Local<String> name,
21071 const v8::PropertyCallbackInfo<v8::Value>& info) {
21072 CHECK_EQ(name, v8_str("foo"));
21073 instance_checked_getter_count++;
21074 info.GetReturnValue().Set(v8_num(11));
21078 static int instance_checked_setter_count = 0;
21079 static void InstanceCheckedSetter(Local<String> name,
21080 Local<Value> value,
21081 const v8::PropertyCallbackInfo<void>& info) {
21082 CHECK_EQ(name, v8_str("foo"));
21083 CHECK_EQ(value, v8_num(23));
21084 instance_checked_setter_count++;
21088 static void CheckInstanceCheckedResult(int getters,
21090 bool expects_callbacks,
21091 TryCatch* try_catch) {
21092 if (expects_callbacks) {
21093 CHECK(!try_catch->HasCaught());
21094 CHECK_EQ(getters, instance_checked_getter_count);
21095 CHECK_EQ(setters, instance_checked_setter_count);
21097 CHECK(try_catch->HasCaught());
21098 CHECK_EQ(0, instance_checked_getter_count);
21099 CHECK_EQ(0, instance_checked_setter_count);
21101 try_catch->Reset();
21105 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21106 instance_checked_getter_count = 0;
21107 instance_checked_setter_count = 0;
21108 TryCatch try_catch;
21110 // Test path through generic runtime code.
21111 CompileRun("obj.foo");
21112 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21113 CompileRun("obj.foo = 23");
21114 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21116 // Test path through generated LoadIC and StoredIC.
21117 CompileRun("function test_get(o) { o.foo; }"
21119 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21120 CompileRun("test_get(obj);");
21121 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21122 CompileRun("test_get(obj);");
21123 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21124 CompileRun("function test_set(o) { o.foo = 23; }"
21126 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21127 CompileRun("test_set(obj);");
21128 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21129 CompileRun("test_set(obj);");
21130 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21132 // Test path through optimized code.
21133 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21135 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21136 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21138 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21140 // Cleanup so that closures start out fresh in next check.
21141 CompileRun("%DeoptimizeFunction(test_get);"
21142 "%ClearFunctionTypeFeedback(test_get);"
21143 "%DeoptimizeFunction(test_set);"
21144 "%ClearFunctionTypeFeedback(test_set);");
21148 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21149 v8::internal::FLAG_allow_natives_syntax = true;
21150 LocalContext context;
21151 v8::HandleScope scope(context->GetIsolate());
21153 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21154 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21155 inst->SetAccessor(v8_str("foo"),
21156 InstanceCheckedGetter, InstanceCheckedSetter,
21160 v8::AccessorSignature::New(context->GetIsolate(), templ));
21161 context->Global()->Set(v8_str("f"), templ->GetFunction());
21163 printf("Testing positive ...\n");
21164 CompileRun("var obj = new f();");
21165 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21166 CheckInstanceCheckedAccessors(true);
21168 printf("Testing negative ...\n");
21169 CompileRun("var obj = {};"
21170 "obj.__proto__ = new f();");
21171 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21172 CheckInstanceCheckedAccessors(false);
21176 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21177 v8::internal::FLAG_allow_natives_syntax = true;
21178 LocalContext context;
21179 v8::HandleScope scope(context->GetIsolate());
21181 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21182 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21183 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21184 inst->SetAccessor(v8_str("foo"),
21185 InstanceCheckedGetter, InstanceCheckedSetter,
21189 v8::AccessorSignature::New(context->GetIsolate(), templ));
21190 context->Global()->Set(v8_str("f"), templ->GetFunction());
21192 printf("Testing positive ...\n");
21193 CompileRun("var obj = new f();");
21194 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21195 CheckInstanceCheckedAccessors(true);
21197 printf("Testing negative ...\n");
21198 CompileRun("var obj = {};"
21199 "obj.__proto__ = new f();");
21200 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21201 CheckInstanceCheckedAccessors(false);
21205 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21206 v8::internal::FLAG_allow_natives_syntax = true;
21207 LocalContext context;
21208 v8::HandleScope scope(context->GetIsolate());
21210 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21211 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21212 proto->SetAccessor(v8_str("foo"),
21213 InstanceCheckedGetter, InstanceCheckedSetter,
21217 v8::AccessorSignature::New(context->GetIsolate(), templ));
21218 context->Global()->Set(v8_str("f"), templ->GetFunction());
21220 printf("Testing positive ...\n");
21221 CompileRun("var obj = new f();");
21222 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21223 CheckInstanceCheckedAccessors(true);
21225 printf("Testing negative ...\n");
21226 CompileRun("var obj = {};"
21227 "obj.__proto__ = new f();");
21228 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21229 CheckInstanceCheckedAccessors(false);
21231 printf("Testing positive with modified prototype chain ...\n");
21232 CompileRun("var obj = new f();"
21234 "pro.__proto__ = obj.__proto__;"
21235 "obj.__proto__ = pro;");
21236 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21237 CheckInstanceCheckedAccessors(true);
21241 TEST(TryFinallyMessage) {
21242 LocalContext context;
21243 v8::HandleScope scope(context->GetIsolate());
21245 // Test that the original error message is not lost if there is a
21246 // recursive call into Javascript is done in the finally block, e.g. to
21247 // initialize an IC. (crbug.com/129171)
21248 TryCatch try_catch;
21249 const char* trigger_ic =
21251 " throw new Error('test'); \n"
21254 " x++; \n" // Trigger an IC initialization here.
21256 CompileRun(trigger_ic);
21257 CHECK(try_catch.HasCaught());
21258 Local<Message> message = try_catch.Message();
21259 CHECK(!message.IsEmpty());
21260 CHECK_EQ(2, message->GetLineNumber());
21264 // Test that the original exception message is indeed overwritten if
21265 // a new error is thrown in the finally block.
21266 TryCatch try_catch;
21267 const char* throw_again =
21269 " throw new Error('test'); \n"
21273 " throw new Error('again'); \n" // This is the new uncaught error.
21275 CompileRun(throw_again);
21276 CHECK(try_catch.HasCaught());
21277 Local<Message> message = try_catch.Message();
21278 CHECK(!message.IsEmpty());
21279 CHECK_EQ(6, message->GetLineNumber());
21284 static void Helper137002(bool do_store,
21286 bool remove_accessor,
21287 bool interceptor) {
21288 LocalContext context;
21289 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21291 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21293 templ->SetAccessor(v8_str("foo"),
21294 GetterWhichReturns42,
21295 SetterWhichSetsYOnThisTo23);
21297 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21299 // Turn monomorphic on slow object with native accessor, then turn
21300 // polymorphic, finally optimize to create negative lookup and fail.
21301 CompileRun(do_store ?
21302 "function f(x) { x.foo = void 0; }" :
21303 "function f(x) { return x.foo; }");
21304 CompileRun("obj.y = void 0;");
21305 if (!interceptor) {
21306 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21308 CompileRun("obj.__proto__ = null;"
21309 "f(obj); f(obj); f(obj);");
21311 CompileRun("f({});");
21313 CompileRun("obj.y = void 0;"
21314 "%OptimizeFunctionOnNextCall(f);");
21315 if (remove_accessor) {
21316 CompileRun("delete obj.foo;");
21318 CompileRun("var result = f(obj);");
21320 CompileRun("result = obj.y;");
21322 if (remove_accessor && !interceptor) {
21323 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21325 CHECK_EQ(do_store ? 23 : 42,
21326 context->Global()->Get(v8_str("result"))->Int32Value());
21331 THREADED_TEST(Regress137002a) {
21332 i::FLAG_allow_natives_syntax = true;
21333 i::FLAG_compilation_cache = false;
21334 v8::HandleScope scope(CcTest::isolate());
21335 for (int i = 0; i < 16; i++) {
21336 Helper137002(i & 8, i & 4, i & 2, i & 1);
21341 THREADED_TEST(Regress137002b) {
21342 i::FLAG_allow_natives_syntax = true;
21343 LocalContext context;
21344 v8::Isolate* isolate = context->GetIsolate();
21345 v8::HandleScope scope(isolate);
21346 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21347 templ->SetAccessor(v8_str("foo"),
21348 GetterWhichReturns42,
21349 SetterWhichSetsYOnThisTo23);
21350 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21352 // Turn monomorphic on slow object with native accessor, then just
21353 // delete the property and fail.
21354 CompileRun("function load(x) { return x.foo; }"
21355 "function store(x) { x.foo = void 0; }"
21356 "function keyed_load(x, key) { return x[key]; }"
21357 // Second version of function has a different source (add void 0)
21358 // so that it does not share code with the first version. This
21359 // ensures that the ICs are monomorphic.
21360 "function load2(x) { void 0; return x.foo; }"
21361 "function store2(x) { void 0; x.foo = void 0; }"
21362 "function keyed_load2(x, key) { void 0; return x[key]; }"
21365 "obj.__proto__ = null;"
21367 "subobj.y = void 0;"
21368 "subobj.__proto__ = obj;"
21369 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21371 // Make the ICs monomorphic.
21372 "load(obj); load(obj);"
21373 "load2(subobj); load2(subobj);"
21374 "store(obj); store(obj);"
21375 "store2(subobj); store2(subobj);"
21376 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21377 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21379 // Actually test the shiny new ICs and better not crash. This
21380 // serves as a regression test for issue 142088 as well.
21385 "keyed_load(obj, 'foo');"
21386 "keyed_load2(subobj, 'foo');"
21388 // Delete the accessor. It better not be called any more now.
21391 "subobj.y = void 0;"
21393 "var load_result = load(obj);"
21394 "var load_result2 = load2(subobj);"
21395 "var keyed_load_result = keyed_load(obj, 'foo');"
21396 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21399 "var y_from_obj = obj.y;"
21400 "var y_from_subobj = subobj.y;");
21401 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21402 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21403 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21404 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21405 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21406 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21410 THREADED_TEST(Regress142088) {
21411 i::FLAG_allow_natives_syntax = true;
21412 LocalContext context;
21413 v8::Isolate* isolate = context->GetIsolate();
21414 v8::HandleScope scope(isolate);
21415 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21416 templ->SetAccessor(v8_str("foo"),
21417 GetterWhichReturns42,
21418 SetterWhichSetsYOnThisTo23);
21419 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21421 CompileRun("function load(x) { return x.foo; }"
21422 "var o = Object.create(obj);"
21423 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21424 "load(o); load(o); load(o); load(o);");
21428 THREADED_TEST(Regress3337) {
21429 LocalContext context;
21430 v8::Isolate* isolate = context->GetIsolate();
21431 v8::HandleScope scope(isolate);
21432 Local<v8::Object> o1 = Object::New(isolate);
21433 Local<v8::Object> o2 = Object::New(isolate);
21434 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21435 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21436 CHECK(io1->map() == io2->map());
21437 o1->SetIndexedPropertiesToExternalArrayData(
21438 NULL, v8::kExternalUint32Array, 0);
21439 o2->SetIndexedPropertiesToExternalArrayData(
21440 NULL, v8::kExternalUint32Array, 0);
21441 CHECK(io1->map() == io2->map());
21445 THREADED_TEST(Regress137496) {
21446 i::FLAG_expose_gc = true;
21447 LocalContext context;
21448 v8::HandleScope scope(context->GetIsolate());
21450 // Compile a try-finally clause where the finally block causes a GC
21451 // while there still is a message pending for external reporting.
21452 TryCatch try_catch;
21453 try_catch.SetVerbose(true);
21454 CompileRun("try { throw new Error(); } finally { gc(); }");
21455 CHECK(try_catch.HasCaught());
21459 THREADED_TEST(Regress149912) {
21460 LocalContext context;
21461 v8::HandleScope scope(context->GetIsolate());
21462 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21463 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21464 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21465 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21469 THREADED_TEST(Regress157124) {
21470 LocalContext context;
21471 v8::Isolate* isolate = context->GetIsolate();
21472 v8::HandleScope scope(isolate);
21473 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21474 Local<Object> obj = templ->NewInstance();
21475 obj->GetIdentityHash();
21476 obj->DeleteHiddenValue(v8_str("Bug"));
21480 THREADED_TEST(Regress2535) {
21481 i::FLAG_harmony_collections = true;
21482 i::FLAG_harmony_symbols = true;
21483 LocalContext context;
21484 v8::HandleScope scope(context->GetIsolate());
21485 Local<Value> set_value = CompileRun("new Set();");
21486 Local<Object> set_object(Local<Object>::Cast(set_value));
21487 CHECK_EQ(0, set_object->InternalFieldCount());
21488 Local<Value> map_value = CompileRun("new Map();");
21489 Local<Object> map_object(Local<Object>::Cast(map_value));
21490 CHECK_EQ(0, map_object->InternalFieldCount());
21494 THREADED_TEST(Regress2746) {
21495 LocalContext context;
21496 v8::Isolate* isolate = context->GetIsolate();
21497 v8::HandleScope scope(isolate);
21498 Local<Object> obj = Object::New(isolate);
21499 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21500 obj->SetHiddenValue(key, v8::Undefined(isolate));
21501 Local<Value> value = obj->GetHiddenValue(key);
21502 CHECK(!value.IsEmpty());
21503 CHECK(value->IsUndefined());
21507 THREADED_TEST(Regress260106) {
21508 LocalContext context;
21509 v8::Isolate* isolate = context->GetIsolate();
21510 v8::HandleScope scope(isolate);
21511 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21513 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21514 Local<Function> function = templ->GetFunction();
21515 CHECK(!function.IsEmpty());
21516 CHECK(function->IsFunction());
21520 THREADED_TEST(JSONParseObject) {
21521 LocalContext context;
21522 HandleScope scope(context->GetIsolate());
21523 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21524 Handle<Object> global = context->Global();
21525 global->Set(v8_str("obj"), obj);
21526 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21530 THREADED_TEST(JSONParseNumber) {
21531 LocalContext context;
21532 HandleScope scope(context->GetIsolate());
21533 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21534 Handle<Object> global = context->Global();
21535 global->Set(v8_str("obj"), obj);
21536 ExpectString("JSON.stringify(obj)", "42");
21541 class ThreadInterruptTest {
21543 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21544 ~ThreadInterruptTest() {}
21547 InterruptThread i_thread(this);
21551 CHECK_EQ(kExpectedValue, sem_value_);
21555 static const int kExpectedValue = 1;
21557 class InterruptThread : public i::Thread {
21559 explicit InterruptThread(ThreadInterruptTest* test)
21560 : Thread("InterruptThread"), test_(test) {}
21562 virtual void Run() {
21563 struct sigaction action;
21565 // Ensure that we'll enter waiting condition
21568 // Setup signal handler
21569 memset(&action, 0, sizeof(action));
21570 action.sa_handler = SignalHandler;
21571 sigaction(SIGCHLD, &action, NULL);
21574 kill(getpid(), SIGCHLD);
21576 // Ensure that if wait has returned because of error
21579 // Set value and signal semaphore
21580 test_->sem_value_ = 1;
21581 test_->sem_.Signal();
21584 static void SignalHandler(int signal) {
21588 ThreadInterruptTest* test_;
21592 volatile int sem_value_;
21596 THREADED_TEST(SemaphoreInterruption) {
21597 ThreadInterruptTest().RunTest();
21601 #endif // V8_OS_POSIX
21604 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21606 v8::AccessType type,
21607 Local<Value> data) {
21608 i::PrintF("Named access blocked.\n");
21613 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21615 v8::AccessType type,
21616 Local<Value> data) {
21617 i::PrintF("Indexed access blocked.\n");
21622 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21627 TEST(JSONStringifyAccessCheck) {
21628 v8::V8::Initialize();
21629 v8::Isolate* isolate = CcTest::isolate();
21630 v8::HandleScope scope(isolate);
21632 // Create an ObjectTemplate for global objects and install access
21633 // check callbacks that will block access.
21634 v8::Handle<v8::ObjectTemplate> global_template =
21635 v8::ObjectTemplate::New(isolate);
21636 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21637 IndexAccessAlwaysBlocked);
21639 // Create a context and set an x property on it's global object.
21640 LocalContext context0(NULL, global_template);
21641 v8::Handle<v8::Object> global0 = context0->Global();
21642 global0->Set(v8_str("x"), v8_num(42));
21643 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21645 for (int i = 0; i < 2; i++) {
21647 // Install a toJSON function on the second run.
21648 v8::Handle<v8::FunctionTemplate> toJSON =
21649 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21651 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21653 // Create a context with a different security token so that the
21654 // failed access check callback will be called on each access.
21655 LocalContext context1(NULL, global_template);
21656 context1->Global()->Set(v8_str("other"), global0);
21658 ExpectString("JSON.stringify(other)", "{}");
21659 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21660 "{\"a\":{},\"b\":[\"c\"]}");
21661 ExpectString("JSON.stringify([other, 'b', 'c'])",
21662 "[{},\"b\",\"c\"]");
21664 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21665 array->Set(0, v8_str("a"));
21666 array->Set(1, v8_str("b"));
21667 context1->Global()->Set(v8_str("array"), array);
21668 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21669 array->TurnOnAccessCheck();
21670 ExpectString("JSON.stringify(array)", "[]");
21671 ExpectString("JSON.stringify([array])", "[[]]");
21672 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21677 bool access_check_fail_thrown = false;
21678 bool catch_callback_called = false;
21681 // Failed access check callback that performs a GC on each invocation.
21682 void FailedAccessCheckThrows(Local<v8::Object> target,
21683 v8::AccessType type,
21684 Local<v8::Value> data) {
21685 access_check_fail_thrown = true;
21686 i::PrintF("Access check failed. Error thrown.\n");
21687 CcTest::isolate()->ThrowException(
21688 v8::Exception::Error(v8_str("cross context")));
21692 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21693 for (int i = 0; i < args.Length(); i++) {
21694 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21696 catch_callback_called = true;
21700 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21701 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21705 void CheckCorrectThrow(const char* script) {
21706 // Test that the script, when wrapped into a try-catch, triggers the catch
21707 // clause due to failed access check throwing an exception.
21708 // The subsequent try-catch should run without any exception.
21709 access_check_fail_thrown = false;
21710 catch_callback_called = false;
21711 i::ScopedVector<char> source(1024);
21712 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21713 CompileRun(source.start());
21714 CHECK(access_check_fail_thrown);
21715 CHECK(catch_callback_called);
21717 access_check_fail_thrown = false;
21718 catch_callback_called = false;
21719 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21720 CHECK(!access_check_fail_thrown);
21721 CHECK(!catch_callback_called);
21725 TEST(AccessCheckThrows) {
21726 i::FLAG_allow_natives_syntax = true;
21727 v8::V8::Initialize();
21728 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21729 v8::Isolate* isolate = CcTest::isolate();
21730 v8::HandleScope scope(isolate);
21732 // Create an ObjectTemplate for global objects and install access
21733 // check callbacks that will block access.
21734 v8::Handle<v8::ObjectTemplate> global_template =
21735 v8::ObjectTemplate::New(isolate);
21736 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21737 IndexAccessAlwaysBlocked);
21739 // Create a context and set an x property on it's global object.
21740 LocalContext context0(NULL, global_template);
21741 context0->Global()->Set(v8_str("x"), v8_num(42));
21742 v8::Handle<v8::Object> global0 = context0->Global();
21744 // Create a context with a different security token so that the
21745 // failed access check callback will be called on each access.
21746 LocalContext context1(NULL, global_template);
21747 context1->Global()->Set(v8_str("other"), global0);
21749 v8::Handle<v8::FunctionTemplate> catcher_fun =
21750 v8::FunctionTemplate::New(isolate, CatcherCallback);
21751 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21753 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21754 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21755 context1->Global()->Set(v8_str("has_own_property"),
21756 has_own_property_fun->GetFunction());
21758 { v8::TryCatch try_catch;
21759 access_check_fail_thrown = false;
21760 CompileRun("other.x;");
21761 CHECK(access_check_fail_thrown);
21762 CHECK(try_catch.HasCaught());
21765 CheckCorrectThrow("other.x");
21766 CheckCorrectThrow("other[1]");
21767 CheckCorrectThrow("JSON.stringify(other)");
21768 CheckCorrectThrow("has_own_property(other, 'x')");
21769 CheckCorrectThrow("%GetProperty(other, 'x')");
21770 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21771 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21772 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21773 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21774 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21775 CheckCorrectThrow("%HasProperty(other, 'x')");
21776 CheckCorrectThrow("%HasElement(other, 1)");
21777 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21778 CheckCorrectThrow("%GetPropertyNames(other)");
21779 // PROPERTY_ATTRIBUTES_NONE = 0
21780 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21781 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21782 "other, 'x', null, null, 1)");
21784 // Reset the failed access check callback so it does not influence
21785 // the other tests.
21786 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21790 THREADED_TEST(Regress256330) {
21791 i::FLAG_allow_natives_syntax = true;
21792 LocalContext context;
21793 v8::HandleScope scope(context->GetIsolate());
21794 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21795 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21796 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21797 CompileRun("\"use strict\"; var o = new Bug;"
21798 "function f(o) { o.x = 10; };"
21799 "f(o); f(o); f(o);"
21800 "%OptimizeFunctionOnNextCall(f);"
21802 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21806 THREADED_TEST(CrankshaftInterceptorSetter) {
21807 i::FLAG_allow_natives_syntax = true;
21808 v8::HandleScope scope(CcTest::isolate());
21809 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21810 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21812 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21813 CompileRun("var obj = new Obj;"
21814 // Initialize fields to avoid transitions later.
21816 "obj.accessor_age = 42;"
21817 "function setter(i) { this.accessor_age = i; };"
21818 "function getter() { return this.accessor_age; };"
21819 "function setAge(i) { obj.age = i; };"
21820 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21824 "%OptimizeFunctionOnNextCall(setAge);"
21826 // All stores went through the interceptor.
21827 ExpectInt32("obj.interceptor_age", 4);
21828 ExpectInt32("obj.accessor_age", 42);
21832 THREADED_TEST(CrankshaftInterceptorGetter) {
21833 i::FLAG_allow_natives_syntax = true;
21834 v8::HandleScope scope(CcTest::isolate());
21835 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21836 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21838 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21839 CompileRun("var obj = new Obj;"
21840 // Initialize fields to avoid transitions later.
21842 "obj.accessor_age = 42;"
21843 "function getter() { return this.accessor_age; };"
21844 "function getAge() { return obj.interceptor_age; };"
21845 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21849 "%OptimizeFunctionOnNextCall(getAge);");
21850 // Access through interceptor.
21851 ExpectInt32("getAge()", 1);
21855 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21856 i::FLAG_allow_natives_syntax = true;
21857 v8::HandleScope scope(CcTest::isolate());
21858 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21859 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21861 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21862 CompileRun("var obj = new Obj;"
21863 "obj.__proto__.interceptor_age = 42;"
21865 "function getAge() { return obj.interceptor_age; };");
21866 ExpectInt32("getAge();", 100);
21867 ExpectInt32("getAge();", 100);
21868 ExpectInt32("getAge();", 100);
21869 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21870 // Access through interceptor.
21871 ExpectInt32("getAge();", 100);
21875 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21876 i::FLAG_allow_natives_syntax = true;
21877 v8::HandleScope scope(CcTest::isolate());
21878 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21879 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21881 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21882 CompileRun("var obj = new Obj;"
21883 "obj.age = 100000;"
21884 "function setAge(i) { obj.age = i };"
21888 "%OptimizeFunctionOnNextCall(setAge);"
21890 ExpectInt32("obj.age", 100000);
21891 ExpectInt32("obj.interceptor_age", 103);
21895 class RequestInterruptTestBase {
21897 RequestInterruptTestBase()
21899 isolate_(env_->GetIsolate()),
21902 should_continue_(true) {
21905 virtual ~RequestInterruptTestBase() { }
21907 virtual void StartInterruptThread() = 0;
21909 virtual void TestBody() = 0;
21912 StartInterruptThread();
21914 v8::HandleScope handle_scope(isolate_);
21918 isolate_->ClearInterrupt();
21920 // Verify we arrived here because interruptor was called
21921 // not due to a bug causing us to exit the loop too early.
21922 CHECK(!should_continue());
21925 void WakeUpInterruptor() {
21929 bool should_continue() const { return should_continue_; }
21931 bool ShouldContinue() {
21933 if (--warmup_ == 0) {
21934 WakeUpInterruptor();
21938 return should_continue_;
21941 static void ShouldContinueCallback(
21942 const v8::FunctionCallbackInfo<Value>& info) {
21943 RequestInterruptTestBase* test =
21944 reinterpret_cast<RequestInterruptTestBase*>(
21945 info.Data().As<v8::External>()->Value());
21946 info.GetReturnValue().Set(test->ShouldContinue());
21950 v8::Isolate* isolate_;
21953 bool should_continue_;
21957 class RequestInterruptTestBaseWithSimpleInterrupt
21958 : public RequestInterruptTestBase {
21960 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
21962 virtual void StartInterruptThread() {
21967 class InterruptThread : public i::Thread {
21969 explicit InterruptThread(RequestInterruptTestBase* test)
21970 : Thread("RequestInterruptTest"), test_(test) {}
21972 virtual void Run() {
21973 test_->sem_.Wait();
21974 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21977 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21978 reinterpret_cast<RequestInterruptTestBase*>(data)->
21979 should_continue_ = false;
21983 RequestInterruptTestBase* test_;
21986 InterruptThread i_thread;
21990 class RequestInterruptTestWithFunctionCall
21991 : public RequestInterruptTestBaseWithSimpleInterrupt {
21993 virtual void TestBody() {
21994 Local<Function> func = Function::New(
21995 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21996 env_->Global()->Set(v8_str("ShouldContinue"), func);
21998 CompileRun("while (ShouldContinue()) { }");
22003 class RequestInterruptTestWithMethodCall
22004 : public RequestInterruptTestBaseWithSimpleInterrupt {
22006 virtual void TestBody() {
22007 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22008 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22009 proto->Set(v8_str("shouldContinue"), Function::New(
22010 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22011 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22013 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22018 class RequestInterruptTestWithAccessor
22019 : public RequestInterruptTestBaseWithSimpleInterrupt {
22021 virtual void TestBody() {
22022 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22023 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22024 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22025 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22026 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22028 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22033 class RequestInterruptTestWithNativeAccessor
22034 : public RequestInterruptTestBaseWithSimpleInterrupt {
22036 virtual void TestBody() {
22037 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22038 t->InstanceTemplate()->SetNativeDataProperty(
22039 v8_str("shouldContinue"),
22040 &ShouldContinueNativeGetter,
22042 v8::External::New(isolate_, this));
22043 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22045 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22049 static void ShouldContinueNativeGetter(
22050 Local<String> property,
22051 const v8::PropertyCallbackInfo<v8::Value>& info) {
22052 RequestInterruptTestBase* test =
22053 reinterpret_cast<RequestInterruptTestBase*>(
22054 info.Data().As<v8::External>()->Value());
22055 info.GetReturnValue().Set(test->ShouldContinue());
22060 class RequestInterruptTestWithMethodCallAndInterceptor
22061 : public RequestInterruptTestBaseWithSimpleInterrupt {
22063 virtual void TestBody() {
22064 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22065 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22066 proto->Set(v8_str("shouldContinue"), Function::New(
22067 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22068 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22069 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22071 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22073 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22077 static void EmptyInterceptor(
22078 Local<String> property,
22079 const v8::PropertyCallbackInfo<v8::Value>& info) {
22084 class RequestInterruptTestWithMathAbs
22085 : public RequestInterruptTestBaseWithSimpleInterrupt {
22087 virtual void TestBody() {
22088 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22090 WakeUpInterruptorCallback,
22091 v8::External::New(isolate_, this)));
22093 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22095 ShouldContinueCallback,
22096 v8::External::New(isolate_, this)));
22098 i::FLAG_allow_natives_syntax = true;
22099 CompileRun("function loopish(o) {"
22101 " while (o.abs(1) > 0) {"
22102 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22104 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22109 "var obj = {abs: function () { return i-- }, x: null};"
22112 "%OptimizeFunctionOnNextCall(loopish);"
22115 i::FLAG_allow_natives_syntax = false;
22119 static void WakeUpInterruptorCallback(
22120 const v8::FunctionCallbackInfo<Value>& info) {
22121 if (!info[0]->BooleanValue()) return;
22123 RequestInterruptTestBase* test =
22124 reinterpret_cast<RequestInterruptTestBase*>(
22125 info.Data().As<v8::External>()->Value());
22126 test->WakeUpInterruptor();
22129 static void ShouldContinueCallback(
22130 const v8::FunctionCallbackInfo<Value>& info) {
22131 RequestInterruptTestBase* test =
22132 reinterpret_cast<RequestInterruptTestBase*>(
22133 info.Data().As<v8::External>()->Value());
22134 info.GetReturnValue().Set(test->should_continue());
22139 TEST(RequestInterruptTestWithFunctionCall) {
22140 RequestInterruptTestWithFunctionCall().RunTest();
22144 TEST(RequestInterruptTestWithMethodCall) {
22145 RequestInterruptTestWithMethodCall().RunTest();
22149 TEST(RequestInterruptTestWithAccessor) {
22150 RequestInterruptTestWithAccessor().RunTest();
22154 TEST(RequestInterruptTestWithNativeAccessor) {
22155 RequestInterruptTestWithNativeAccessor().RunTest();
22159 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22160 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22164 TEST(RequestInterruptTestWithMathAbs) {
22165 RequestInterruptTestWithMathAbs().RunTest();
22169 class ClearInterruptFromAnotherThread
22170 : public RequestInterruptTestBase {
22172 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22174 virtual void StartInterruptThread() {
22178 virtual void TestBody() {
22179 Local<Function> func = Function::New(
22180 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22181 env_->Global()->Set(v8_str("ShouldContinue"), func);
22183 CompileRun("while (ShouldContinue()) { }");
22187 class InterruptThread : public i::Thread {
22189 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22190 : Thread("RequestInterruptTest"), test_(test) {}
22192 virtual void Run() {
22193 test_->sem_.Wait();
22194 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22195 test_->sem_.Wait();
22196 test_->isolate_->ClearInterrupt();
22197 test_->sem2_.Signal();
22200 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22201 ClearInterruptFromAnotherThread* test =
22202 reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22203 test->sem_.Signal();
22204 bool success = test->sem2_.WaitFor(i::TimeDelta::FromSeconds(2));
22205 // Crash instead of timeout to make this failure more prominent.
22207 test->should_continue_ = false;
22211 ClearInterruptFromAnotherThread* test_;
22214 InterruptThread i_thread;
22215 i::Semaphore sem2_;
22219 TEST(ClearInterruptFromAnotherThread) {
22220 ClearInterruptFromAnotherThread().RunTest();
22224 static Local<Value> function_new_expected_env;
22225 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22226 CHECK_EQ(function_new_expected_env, info.Data());
22227 info.GetReturnValue().Set(17);
22231 THREADED_TEST(FunctionNew) {
22233 v8::Isolate* isolate = env->GetIsolate();
22234 v8::HandleScope scope(isolate);
22235 Local<Object> data = v8::Object::New(isolate);
22236 function_new_expected_env = data;
22237 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22238 env->Global()->Set(v8_str("func"), func);
22239 Local<Value> result = CompileRun("func();");
22240 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22241 // Verify function not cached
22242 int serial_number =
22243 i::Smi::cast(v8::Utils::OpenHandle(*func)
22244 ->shared()->get_api_func_data()->serial_number())->value();
22245 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22246 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22247 i::Handle<i::Object> elm =
22248 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22249 CHECK(elm->IsUndefined());
22250 // Verify that each Function::New creates a new function instance
22251 Local<Object> data2 = v8::Object::New(isolate);
22252 function_new_expected_env = data2;
22253 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22254 CHECK(!func2->IsNull());
22255 CHECK_NE(func, func2);
22256 env->Global()->Set(v8_str("func2"), func2);
22257 Local<Value> result2 = CompileRun("func2();");
22258 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22262 TEST(EscapeableHandleScope) {
22263 HandleScope outer_scope(CcTest::isolate());
22264 LocalContext context;
22265 const int runs = 10;
22266 Local<String> values[runs];
22267 for (int i = 0; i < runs; i++) {
22268 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22269 Local<String> value;
22270 if (i != 0) value = v8_str("escape value");
22271 values[i] = inner_scope.Escape(value);
22273 for (int i = 0; i < runs; i++) {
22274 Local<String> expected;
22276 CHECK_EQ(v8_str("escape value"), values[i]);
22278 CHECK(values[i].IsEmpty());
22284 static void SetterWhichExpectsThisAndHolderToDiffer(
22285 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22286 CHECK(info.Holder() != info.This());
22290 TEST(Regress239669) {
22291 LocalContext context;
22292 v8::Isolate* isolate = context->GetIsolate();
22293 v8::HandleScope scope(isolate);
22294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22295 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22296 context->Global()->Set(v8_str("P"), templ->NewInstance());
22301 "C1.prototype = P;"
22302 "for (var i = 0; i < 4; i++ ) {"
22308 class ApiCallOptimizationChecker {
22310 static Local<Object> data;
22311 static Local<Object> receiver;
22312 static Local<Object> holder;
22313 static Local<Object> callee;
22316 static void OptimizationCallback(
22317 const v8::FunctionCallbackInfo<v8::Value>& info) {
22318 CHECK(callee == info.Callee());
22319 CHECK(data == info.Data());
22320 CHECK(receiver == info.This());
22321 if (info.Length() == 1) {
22322 CHECK_EQ(v8_num(1), info[0]);
22324 CHECK(holder == info.Holder());
22326 info.GetReturnValue().Set(v8_str("returned"));
22330 enum SignatureType {
22332 kSignatureOnReceiver,
22333 kSignatureOnPrototype
22337 SignatureType signature_types[] =
22338 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22339 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22340 SignatureType signature_type = signature_types[i];
22341 for (int j = 0; j < 2; j++) {
22342 bool global = j == 0;
22343 int key = signature_type +
22344 ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22345 Run(signature_type, global, key);
22350 void Run(SignatureType signature_type, bool global, int key) {
22351 v8::Isolate* isolate = CcTest::isolate();
22352 v8::HandleScope scope(isolate);
22353 // Build a template for signature checks.
22354 Local<v8::ObjectTemplate> signature_template;
22355 Local<v8::Signature> signature;
22357 Local<v8::FunctionTemplate> parent_template =
22358 FunctionTemplate::New(isolate);
22359 parent_template->SetHiddenPrototype(true);
22360 Local<v8::FunctionTemplate> function_template
22361 = FunctionTemplate::New(isolate);
22362 function_template->Inherit(parent_template);
22363 switch (signature_type) {
22366 case kSignatureOnReceiver:
22367 signature = v8::Signature::New(isolate, function_template);
22369 case kSignatureOnPrototype:
22370 signature = v8::Signature::New(isolate, parent_template);
22373 signature_template = function_template->InstanceTemplate();
22375 // Global object must pass checks.
22376 Local<v8::Context> context =
22377 v8::Context::New(isolate, NULL, signature_template);
22378 v8::Context::Scope context_scope(context);
22379 // Install regular object that can pass signature checks.
22380 Local<Object> function_receiver = signature_template->NewInstance();
22381 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22382 // Get the holder objects.
22383 Local<Object> inner_global =
22384 Local<Object>::Cast(context->Global()->GetPrototype());
22385 // Install functions on hidden prototype object if there is one.
22386 data = Object::New(isolate);
22387 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22388 isolate, OptimizationCallback, data, signature);
22389 Local<Function> function = function_template->GetFunction();
22390 Local<Object> global_holder = inner_global;
22391 Local<Object> function_holder = function_receiver;
22392 if (signature_type == kSignatureOnPrototype) {
22393 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22394 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22396 global_holder->Set(v8_str("g_f"), function);
22397 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22398 function_holder->Set(v8_str("f"), function);
22399 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22400 // Initialize expected values.
22404 receiver = context->Global();
22405 holder = inner_global;
22407 holder = function_receiver;
22408 // If not using a signature, add something else to the prototype chain
22409 // to test the case that holder != receiver
22410 if (signature_type == kNoSignature) {
22411 receiver = Local<Object>::Cast(CompileRun(
22412 "var receiver_subclass = {};\n"
22413 "receiver_subclass.__proto__ = function_receiver;\n"
22414 "receiver_subclass"));
22416 receiver = Local<Object>::Cast(CompileRun(
22417 "var receiver_subclass = function_receiver;\n"
22418 "receiver_subclass"));
22421 // With no signature, the holder is not set.
22422 if (signature_type == kNoSignature) holder = receiver;
22423 // build wrap_function
22424 i::ScopedVector<char> wrap_function(200);
22428 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22429 "function wrap_get_%d() { return this.g_acc; }\n"
22430 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22435 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22436 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22437 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22440 // build source string
22441 i::ScopedVector<char> source(1000);
22444 "%s\n" // wrap functions
22445 "function wrap_f() { return wrap_f_%d(); }\n"
22446 "function wrap_get() { return wrap_get_%d(); }\n"
22447 "function wrap_set() { return wrap_set_%d(); }\n"
22448 "check = function(returned) {\n"
22449 " if (returned !== 'returned') { throw returned; }\n"
22452 "check(wrap_f());\n"
22453 "check(wrap_f());\n"
22454 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22455 "check(wrap_f());\n"
22457 "check(wrap_get());\n"
22458 "check(wrap_get());\n"
22459 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22460 "check(wrap_get());\n"
22462 "check = function(returned) {\n"
22463 " if (returned !== 1) { throw returned; }\n"
22465 "check(wrap_set());\n"
22466 "check(wrap_set());\n"
22467 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22468 "check(wrap_set());\n",
22469 wrap_function.start(), key, key, key, key, key, key);
22470 v8::TryCatch try_catch;
22471 CompileRun(source.start());
22472 ASSERT(!try_catch.HasCaught());
22473 CHECK_EQ(9, count);
22478 Local<Object> ApiCallOptimizationChecker::data;
22479 Local<Object> ApiCallOptimizationChecker::receiver;
22480 Local<Object> ApiCallOptimizationChecker::holder;
22481 Local<Object> ApiCallOptimizationChecker::callee;
22482 int ApiCallOptimizationChecker::count = 0;
22485 TEST(TestFunctionCallOptimization) {
22486 i::FLAG_allow_natives_syntax = true;
22487 ApiCallOptimizationChecker checker;
22492 static const char* last_event_message;
22493 static int last_event_status;
22494 void StoringEventLoggerCallback(const char* message, int status) {
22495 last_event_message = message;
22496 last_event_status = status;
22500 TEST(EventLogging) {
22501 v8::Isolate* isolate = CcTest::isolate();
22502 isolate->SetEventLogger(StoringEventLoggerCallback);
22503 v8::internal::HistogramTimer histogramTimer(
22504 "V8.Test", 0, 10000, 50,
22505 reinterpret_cast<v8::internal::Isolate*>(isolate));
22506 histogramTimer.Start();
22507 CHECK_EQ("V8.Test", last_event_message);
22508 CHECK_EQ(0, last_event_status);
22509 histogramTimer.Stop();
22510 CHECK_EQ("V8.Test", last_event_message);
22511 CHECK_EQ(1, last_event_status);
22516 LocalContext context;
22517 v8::Isolate* isolate = context->GetIsolate();
22518 v8::HandleScope scope(isolate);
22519 Handle<Object> global = context->Global();
22522 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22523 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22524 Handle<v8::Promise> p = pr->GetPromise();
22525 Handle<v8::Promise> r = rr->GetPromise();
22527 // IsPromise predicate.
22528 CHECK(p->IsPromise());
22529 CHECK(r->IsPromise());
22530 Handle<Value> o = v8::Object::New(isolate);
22531 CHECK(!o->IsPromise());
22533 // Resolution and rejection.
22534 pr->Resolve(v8::Integer::New(isolate, 1));
22535 CHECK(p->IsPromise());
22536 rr->Reject(v8::Integer::New(isolate, 2));
22537 CHECK(r->IsPromise());
22539 // Chaining non-pending promises.
22543 "function f1(x) { x1 = x; return x+1 };\n"
22544 "function f2(x) { x2 = x; return x+1 };\n");
22545 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22546 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22549 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22550 isolate->RunMicrotasks();
22551 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22554 isolate->RunMicrotasks();
22555 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22558 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22559 isolate->RunMicrotasks();
22560 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22563 isolate->RunMicrotasks();
22564 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22566 // Chaining pending promises.
22567 CompileRun("x1 = x2 = 0;");
22568 pr = v8::Promise::Resolver::New(isolate);
22569 rr = v8::Promise::Resolver::New(isolate);
22571 pr->GetPromise()->Chain(f1);
22572 rr->GetPromise()->Catch(f2);
22573 isolate->RunMicrotasks();
22574 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22575 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22577 pr->Resolve(v8::Integer::New(isolate, 1));
22578 rr->Reject(v8::Integer::New(isolate, 2));
22579 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22580 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22582 isolate->RunMicrotasks();
22583 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22584 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22587 CompileRun("x1 = x2 = 0;");
22588 pr = v8::Promise::Resolver::New(isolate);
22589 pr->GetPromise()->Chain(f1)->Chain(f2);
22590 pr->Resolve(v8::Integer::New(isolate, 3));
22591 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22592 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22593 isolate->RunMicrotasks();
22594 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22595 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22597 CompileRun("x1 = x2 = 0;");
22598 rr = v8::Promise::Resolver::New(isolate);
22599 rr->GetPromise()->Catch(f1)->Chain(f2);
22600 rr->Reject(v8::Integer::New(isolate, 3));
22601 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22602 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22603 isolate->RunMicrotasks();
22604 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22605 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22609 TEST(PromiseThen) {
22610 LocalContext context;
22611 v8::Isolate* isolate = context->GetIsolate();
22612 v8::HandleScope scope(isolate);
22613 Handle<Object> global = context->Global();
22616 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22617 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22618 Handle<v8::Promise> p = pr->GetPromise();
22619 Handle<v8::Promise> q = qr->GetPromise();
22621 CHECK(p->IsPromise());
22622 CHECK(q->IsPromise());
22624 pr->Resolve(v8::Integer::New(isolate, 1));
22627 // Chaining non-pending promises.
22631 "function f1(x) { x1 = x; return x+1 };\n"
22632 "function f2(x) { x2 = x; return x+1 };\n");
22633 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22634 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22638 CHECK(global->Get(v8_str("x1"))->IsNumber());
22639 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22640 isolate->RunMicrotasks();
22641 CHECK(!global->Get(v8_str("x1"))->IsNumber());
22642 CHECK_EQ(p, global->Get(v8_str("x1")));
22645 CompileRun("x1 = x2 = 0;");
22647 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22648 isolate->RunMicrotasks();
22649 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22652 CompileRun("x1 = x2 = 0;");
22653 pr = v8::Promise::Resolver::New(isolate);
22654 qr = v8::Promise::Resolver::New(isolate);
22657 qr->GetPromise()->Then(f1)->Then(f2);
22659 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22660 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22661 isolate->RunMicrotasks();
22662 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22663 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22665 pr->Resolve(v8::Integer::New(isolate, 3));
22667 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22668 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22669 isolate->RunMicrotasks();
22670 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22671 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22675 TEST(DisallowJavascriptExecutionScope) {
22676 LocalContext context;
22677 v8::Isolate* isolate = context->GetIsolate();
22678 v8::HandleScope scope(isolate);
22679 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22680 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22685 TEST(AllowJavascriptExecutionScope) {
22686 LocalContext context;
22687 v8::Isolate* isolate = context->GetIsolate();
22688 v8::HandleScope scope(isolate);
22689 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22690 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22691 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22692 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22693 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22699 TEST(ThrowOnJavascriptExecution) {
22700 LocalContext context;
22701 v8::Isolate* isolate = context->GetIsolate();
22702 v8::HandleScope scope(isolate);
22703 v8::TryCatch try_catch;
22704 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22705 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22707 CHECK(try_catch.HasCaught());
22711 TEST(Regress354123) {
22712 LocalContext current;
22713 v8::Isolate* isolate = current->GetIsolate();
22714 v8::HandleScope scope(isolate);
22716 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22717 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22718 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22720 // Test access using __proto__ from the prototype chain.
22721 named_access_count = 0;
22722 CompileRun("friend.__proto__ = {};");
22723 CHECK_EQ(2, named_access_count);
22724 CompileRun("friend.__proto__;");
22725 CHECK_EQ(4, named_access_count);
22727 // Test access using __proto__ as a hijacked function (A).
22728 named_access_count = 0;
22729 CompileRun("var p = Object.prototype;"
22730 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22731 "f.call(friend, {});");
22732 CHECK_EQ(1, named_access_count);
22733 CompileRun("var p = Object.prototype;"
22734 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22735 "f.call(friend);");
22736 CHECK_EQ(2, named_access_count);
22738 // Test access using __proto__ as a hijacked function (B).
22739 named_access_count = 0;
22740 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22741 "f.call(friend, {});");
22742 CHECK_EQ(1, named_access_count);
22743 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22744 "f.call(friend);");
22745 CHECK_EQ(2, named_access_count);
22747 // Test access using Object.setPrototypeOf reflective method.
22748 named_access_count = 0;
22749 CompileRun("Object.setPrototypeOf(friend, {});");
22750 CHECK_EQ(1, named_access_count);
22751 CompileRun("Object.getPrototypeOf(friend);");
22752 CHECK_EQ(2, named_access_count);
22756 TEST(CaptureStackTraceForStackOverflow) {
22757 v8::internal::FLAG_stack_size = 150;
22758 LocalContext current;
22759 v8::Isolate* isolate = current->GetIsolate();
22760 v8::HandleScope scope(isolate);
22761 V8::SetCaptureStackTraceForUncaughtExceptions(
22762 true, 10, v8::StackTrace::kDetailed);
22763 v8::TryCatch try_catch;
22764 CompileRun("(function f(x) { f(x+1); })(0)");
22765 CHECK(try_catch.HasCaught());
22769 TEST(ScriptNameAndLineNumber) {
22771 v8::Isolate* isolate = env->GetIsolate();
22772 v8::HandleScope scope(isolate);
22773 const char* url = "http://www.foo.com/foo.js";
22774 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22775 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22776 Local<Script> script = v8::ScriptCompiler::Compile(
22777 isolate, &script_source);
22778 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22779 CHECK(!script_name.IsEmpty());
22780 CHECK(script_name->IsString());
22781 String::Utf8Value utf8_name(script_name);
22782 CHECK_EQ(url, *utf8_name);
22783 int line_number = script->GetUnboundScript()->GetLineNumber(0);
22784 CHECK_EQ(13, line_number);
22788 Local<v8::Context> call_eval_context;
22789 Local<v8::Function> call_eval_bound_function;
22790 static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
22791 v8::Context::Scope scope(call_eval_context);
22792 args.GetReturnValue().Set(
22793 call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL));
22797 TEST(CrossActivationEval) {
22799 v8::Isolate* isolate = env->GetIsolate();
22800 v8::HandleScope scope(isolate);
22802 call_eval_context = v8::Context::New(isolate);
22803 v8::Context::Scope scope(call_eval_context);
22804 call_eval_bound_function =
22805 Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
22807 env->Global()->Set(v8_str("CallEval"),
22808 v8::FunctionTemplate::New(isolate, CallEval)->GetFunction());
22809 Local<Value> result = CompileRun("CallEval();");
22810 CHECK_EQ(result, v8::Integer::New(isolate, 1));