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
40 #include "arguments.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
50 #include "unicode-inl.h"
53 #include "../include/v8-util.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 void ExpectString(const char* code, const char* expected) {
103 Local<Value> result = CompileRun(code);
104 CHECK(result->IsString());
105 String::Utf8Value utf8(result);
106 CHECK_EQ(expected, *utf8);
110 static void ExpectInt32(const char* code, int expected) {
111 Local<Value> result = CompileRun(code);
112 CHECK(result->IsInt32());
113 CHECK_EQ(expected, result->Int32Value());
117 static void ExpectBoolean(const char* code, bool expected) {
118 Local<Value> result = CompileRun(code);
119 CHECK(result->IsBoolean());
120 CHECK_EQ(expected, result->BooleanValue());
124 static void ExpectTrue(const char* code) {
125 ExpectBoolean(code, true);
129 static void ExpectFalse(const char* code) {
130 ExpectBoolean(code, false);
134 static void ExpectObject(const char* code, Local<Value> expected) {
135 Local<Value> result = CompileRun(code);
136 CHECK(result->Equals(expected));
140 static void ExpectUndefined(const char* code) {
141 Local<Value> result = CompileRun(code);
142 CHECK(result->IsUndefined());
146 static int signature_callback_count;
147 static Local<Value> signature_expected_receiver;
148 static void IncrementingSignatureCallback(
149 const v8::FunctionCallbackInfo<v8::Value>& args) {
150 ApiTestFuzzer::Fuzz();
151 signature_callback_count++;
152 CHECK_EQ(signature_expected_receiver, args.Holder());
153 CHECK_EQ(signature_expected_receiver, args.This());
154 v8::Handle<v8::Array> result =
155 v8::Array::New(args.GetIsolate(), args.Length());
156 for (int i = 0; i < args.Length(); i++)
157 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
158 args.GetReturnValue().Set(result);
162 static void SignatureCallback(
163 const v8::FunctionCallbackInfo<v8::Value>& args) {
164 ApiTestFuzzer::Fuzz();
165 v8::Handle<v8::Array> result =
166 v8::Array::New(args.GetIsolate(), args.Length());
167 for (int i = 0; i < args.Length(); i++) {
168 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
170 args.GetReturnValue().Set(result);
174 // Tests that call v8::V8::Dispose() cannot be threaded.
175 TEST(InitializeAndDisposeOnce) {
176 CHECK(v8::V8::Initialize());
177 CHECK(v8::V8::Dispose());
181 // Tests that call v8::V8::Dispose() cannot be threaded.
182 TEST(InitializeAndDisposeMultiple) {
183 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
184 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
185 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
186 // TODO(mstarzinger): This should fail gracefully instead of asserting.
187 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
188 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
192 THREADED_TEST(Handles) {
193 v8::HandleScope scope(CcTest::isolate());
194 Local<Context> local_env;
197 local_env = env.local();
200 // Local context should still be live.
201 CHECK(!local_env.IsEmpty());
204 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
205 CHECK(!undef.IsEmpty());
206 CHECK(undef->IsUndefined());
208 const char* source = "1 + 2 + 3";
209 Local<Script> script = v8_compile(source);
210 CHECK_EQ(6, script->Run()->Int32Value());
216 THREADED_TEST(IsolateOfContext) {
217 v8::HandleScope scope(CcTest::isolate());
218 v8::Handle<Context> env = Context::New(CcTest::isolate());
220 CHECK(!env->GetIsolate()->InContext());
221 CHECK(env->GetIsolate() == CcTest::isolate());
223 CHECK(env->GetIsolate()->InContext());
224 CHECK(env->GetIsolate() == CcTest::isolate());
226 CHECK(!env->GetIsolate()->InContext());
227 CHECK(env->GetIsolate() == CcTest::isolate());
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232 i::ScopedVector<char> source(200);
233 i::OS::SNPrintF(source,
234 "for (var i = 0; i < 10; i++) {"
238 signature_callback_count = 0;
239 signature_expected_receiver = receiver;
240 bool expected_to_throw = receiver.IsEmpty();
241 v8::TryCatch try_catch;
242 CompileRun(source.start());
243 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244 if (!expected_to_throw) {
245 CHECK_EQ(10, signature_callback_count);
247 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248 try_catch.Exception()->ToString());
253 THREADED_TEST(ReceiverSignature) {
255 v8::Isolate* isolate = env->GetIsolate();
256 v8::HandleScope scope(isolate);
258 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260 v8::Handle<v8::FunctionTemplate> callback_sig =
261 v8::FunctionTemplate::New(
262 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263 v8::Handle<v8::FunctionTemplate> callback =
264 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266 sub_fun->Inherit(fun);
267 v8::Handle<v8::FunctionTemplate> unrel_fun =
268 v8::FunctionTemplate::New(isolate);
269 // Install properties.
270 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271 fun_proto->Set(v8_str("prop_sig"), callback_sig);
272 fun_proto->Set(v8_str("prop"), callback);
273 fun_proto->SetAccessorProperty(
274 v8_str("accessor_sig"), callback_sig, callback_sig);
275 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276 // Instantiate templates.
277 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279 // Setup global variables.
280 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282 env->Global()->Set(v8_str("fun_instance"), fun_instance);
283 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
285 "var accessor_sig_key = 'accessor_sig';"
286 "var accessor_key = 'accessor';"
287 "var prop_sig_key = 'prop_sig';"
288 "var prop_key = 'prop';"
290 "function copy_props(obj) {"
291 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292 " var source = Fun.prototype;"
293 " for (var i in keys) {"
294 " var key = keys[i];"
295 " var desc = Object.getOwnPropertyDescriptor(source, key);"
296 " Object.defineProperty(obj, key, desc);"
302 "var unrel = new UnrelFun();"
303 "copy_props(unrel);");
304 // Test with and without ICs
305 const char* test_objects[] = {
306 "fun_instance", "sub_fun_instance", "obj", "unrel" };
307 unsigned bad_signature_start_offset = 2;
308 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309 i::ScopedVector<char> source(200);
311 source, "var test_object = %s; test_object", test_objects[i]);
312 Local<Value> test_object = CompileRun(source.start());
313 TestSignature("test_object.prop();", test_object);
314 TestSignature("test_object.accessor;", test_object);
315 TestSignature("test_object[accessor_key];", test_object);
316 TestSignature("test_object.accessor = 1;", test_object);
317 TestSignature("test_object[accessor_key] = 1;", test_object);
318 if (i >= bad_signature_start_offset) test_object = Local<Value>();
319 TestSignature("test_object.prop_sig();", test_object);
320 TestSignature("test_object.accessor_sig;", test_object);
321 TestSignature("test_object[accessor_sig_key];", test_object);
322 TestSignature("test_object.accessor_sig = 1;", test_object);
323 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
328 THREADED_TEST(ArgumentSignature) {
330 v8::Isolate* isolate = env->GetIsolate();
331 v8::HandleScope scope(isolate);
332 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333 cons->SetClassName(v8_str("Cons"));
334 v8::Handle<v8::Signature> sig = v8::Signature::New(
335 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336 v8::Handle<v8::FunctionTemplate> fun =
337 v8::FunctionTemplate::New(isolate,
341 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
344 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345 CHECK(value1->IsTrue());
347 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348 CHECK(value2->IsTrue());
350 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351 CHECK(value3->IsTrue());
353 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354 cons1->SetClassName(v8_str("Cons1"));
355 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356 cons2->SetClassName(v8_str("Cons2"));
357 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358 cons3->SetClassName(v8_str("Cons3"));
360 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361 v8::Handle<v8::Signature> wsig = v8::Signature::New(
362 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363 v8::Handle<v8::FunctionTemplate> fun2 =
364 v8::FunctionTemplate::New(isolate,
369 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373 v8::Handle<Value> value4 = CompileRun(
374 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375 "'[object Cons1],[object Cons2],[object Cons3]'");
376 CHECK(value4->IsTrue());
378 v8::Handle<Value> value5 = CompileRun(
379 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380 CHECK(value5->IsTrue());
382 v8::Handle<Value> value6 = CompileRun(
383 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384 CHECK(value6->IsTrue());
386 v8::Handle<Value> value7 = CompileRun(
387 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388 "'[object Cons1],[object Cons2],[object Cons3],d';");
389 CHECK(value7->IsTrue());
391 v8::Handle<Value> value8 = CompileRun(
392 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393 CHECK(value8->IsTrue());
397 THREADED_TEST(HulIgennem) {
399 v8::Isolate* isolate = env->GetIsolate();
400 v8::HandleScope scope(isolate);
401 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402 Local<String> undef_str = undef->ToString();
403 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404 undef_str->WriteUtf8(value);
405 CHECK_EQ(0, strcmp(value, "undefined"));
406 i::DeleteArray(value);
410 THREADED_TEST(Access) {
412 v8::Isolate* isolate = env->GetIsolate();
413 v8::HandleScope scope(isolate);
414 Local<v8::Object> obj = v8::Object::New(isolate);
415 Local<Value> foo_before = obj->Get(v8_str("foo"));
416 CHECK(foo_before->IsUndefined());
417 Local<String> bar_str = v8_str("bar");
418 obj->Set(v8_str("foo"), bar_str);
419 Local<Value> foo_after = obj->Get(v8_str("foo"));
420 CHECK(!foo_after->IsUndefined());
421 CHECK(foo_after->IsString());
422 CHECK_EQ(bar_str, foo_after);
426 THREADED_TEST(AccessElement) {
428 v8::HandleScope scope(env->GetIsolate());
429 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430 Local<Value> before = obj->Get(1);
431 CHECK(before->IsUndefined());
432 Local<String> bar_str = v8_str("bar");
433 obj->Set(1, bar_str);
434 Local<Value> after = obj->Get(1);
435 CHECK(!after->IsUndefined());
436 CHECK(after->IsString());
437 CHECK_EQ(bar_str, after);
439 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440 CHECK_EQ(v8_str("a"), value->Get(0));
441 CHECK_EQ(v8_str("b"), value->Get(1));
445 THREADED_TEST(Script) {
447 v8::HandleScope scope(env->GetIsolate());
448 const char* source = "1 + 2 + 3";
449 Local<Script> script = v8_compile(source);
450 CHECK_EQ(6, script->Run()->Int32Value());
454 static uint16_t* AsciiToTwoByteString(const char* source) {
455 int array_length = i::StrLength(source) + 1;
456 uint16_t* converted = i::NewArray<uint16_t>(array_length);
457 for (int i = 0; i < array_length; i++) converted[i] = source[i];
462 class TestResource: public String::ExternalStringResource {
464 TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
465 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
466 while (data[length_]) ++length_;
470 if (owning_data_) i::DeleteArray(data_);
471 if (counter_ != NULL) ++*counter_;
474 const uint16_t* data() const {
478 size_t length() const {
490 class TestAsciiResource: public String::ExternalAsciiStringResource {
492 TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
494 data_(data + offset),
495 length_(strlen(data) - offset),
496 counter_(counter) { }
498 ~TestAsciiResource() {
499 i::DeleteArray(orig_data_);
500 if (counter_ != NULL) ++*counter_;
503 const char* data() const {
507 size_t length() const {
512 const char* orig_data_;
519 THREADED_TEST(ScriptUsingStringResource) {
520 int dispose_count = 0;
521 const char* c_source = "1 + 2 * 3";
522 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
525 v8::HandleScope scope(env->GetIsolate());
526 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
527 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
528 Local<Script> script = v8_compile(source);
529 Local<Value> value = script->Run();
530 CHECK(value->IsNumber());
531 CHECK_EQ(7, value->Int32Value());
532 CHECK(source->IsExternal());
534 static_cast<TestResource*>(source->GetExternalStringResource()));
535 String::Encoding encoding = String::UNKNOWN_ENCODING;
536 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
537 source->GetExternalStringResourceBase(&encoding));
538 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
539 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
540 CHECK_EQ(0, dispose_count);
542 CcTest::i_isolate()->compilation_cache()->Clear();
543 CcTest::heap()->CollectAllAvailableGarbage();
544 CHECK_EQ(1, dispose_count);
548 THREADED_TEST(ScriptUsingAsciiStringResource) {
549 int dispose_count = 0;
550 const char* c_source = "1 + 2 * 3";
553 v8::HandleScope scope(env->GetIsolate());
554 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
556 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
557 CHECK(source->IsExternalAscii());
558 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
559 source->GetExternalAsciiStringResource());
560 String::Encoding encoding = String::UNKNOWN_ENCODING;
561 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
562 source->GetExternalStringResourceBase(&encoding));
563 CHECK_EQ(String::ASCII_ENCODING, encoding);
564 Local<Script> script = v8_compile(source);
565 Local<Value> value = script->Run();
566 CHECK(value->IsNumber());
567 CHECK_EQ(7, value->Int32Value());
568 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
569 CHECK_EQ(0, dispose_count);
571 CcTest::i_isolate()->compilation_cache()->Clear();
572 CcTest::heap()->CollectAllAvailableGarbage();
573 CHECK_EQ(1, dispose_count);
577 THREADED_TEST(ScriptMakingExternalString) {
578 int dispose_count = 0;
579 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
582 v8::HandleScope scope(env->GetIsolate());
583 Local<String> source =
584 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
585 // Trigger GCs so that the newly allocated string moves to old gen.
586 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
587 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
588 CHECK_EQ(source->IsExternal(), false);
589 CHECK_EQ(source->IsExternalAscii(), false);
590 String::Encoding encoding = String::UNKNOWN_ENCODING;
591 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
592 CHECK_EQ(String::ASCII_ENCODING, encoding);
593 bool success = source->MakeExternal(new TestResource(two_byte_source,
596 Local<Script> script = v8_compile(source);
597 Local<Value> value = script->Run();
598 CHECK(value->IsNumber());
599 CHECK_EQ(7, value->Int32Value());
600 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
601 CHECK_EQ(0, dispose_count);
603 CcTest::i_isolate()->compilation_cache()->Clear();
604 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
605 CHECK_EQ(1, dispose_count);
609 THREADED_TEST(ScriptMakingExternalAsciiString) {
610 int dispose_count = 0;
611 const char* c_source = "1 + 2 * 3";
614 v8::HandleScope scope(env->GetIsolate());
615 Local<String> source = v8_str(c_source);
616 // Trigger GCs so that the newly allocated string moves to old gen.
617 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
618 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
619 bool success = source->MakeExternal(
620 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
622 Local<Script> script = v8_compile(source);
623 Local<Value> value = script->Run();
624 CHECK(value->IsNumber());
625 CHECK_EQ(7, value->Int32Value());
626 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
627 CHECK_EQ(0, dispose_count);
629 CcTest::i_isolate()->compilation_cache()->Clear();
630 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
631 CHECK_EQ(1, dispose_count);
635 TEST(MakingExternalStringConditions) {
637 v8::HandleScope scope(env->GetIsolate());
639 // Free some space in the new space so that we can check freshness.
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
643 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
644 Local<String> small_string =
645 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
646 i::DeleteArray(two_byte_string);
648 // We should refuse to externalize newly created small string.
649 CHECK(!small_string->CanMakeExternal());
650 // Trigger GCs so that the newly allocated string moves to old gen.
651 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
652 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
653 // Old space strings should be accepted.
654 CHECK(small_string->CanMakeExternal());
656 two_byte_string = AsciiToTwoByteString("small string 2");
657 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
658 i::DeleteArray(two_byte_string);
660 // We should refuse externalizing newly created small string.
661 CHECK(!small_string->CanMakeExternal());
662 for (int i = 0; i < 100; i++) {
663 String::Value value(small_string);
665 // Frequently used strings should be accepted.
666 CHECK(small_string->CanMakeExternal());
668 const int buf_size = 10 * 1024;
669 char* buf = i::NewArray<char>(buf_size);
670 memset(buf, 'a', buf_size);
671 buf[buf_size - 1] = '\0';
673 two_byte_string = AsciiToTwoByteString(buf);
674 Local<String> large_string =
675 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
677 i::DeleteArray(two_byte_string);
678 // Large strings should be immediately accepted.
679 CHECK(large_string->CanMakeExternal());
683 TEST(MakingExternalAsciiStringConditions) {
685 v8::HandleScope scope(env->GetIsolate());
687 // Free some space in the new space so that we can check freshness.
688 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
689 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
691 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
692 // We should refuse to externalize newly created small string.
693 CHECK(!small_string->CanMakeExternal());
694 // Trigger GCs so that the newly allocated string moves to old gen.
695 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
696 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
697 // Old space strings should be accepted.
698 CHECK(small_string->CanMakeExternal());
700 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
701 // We should refuse externalizing newly created small string.
702 CHECK(!small_string->CanMakeExternal());
703 for (int i = 0; i < 100; i++) {
704 String::Value value(small_string);
706 // Frequently used strings should be accepted.
707 CHECK(small_string->CanMakeExternal());
709 const int buf_size = 10 * 1024;
710 char* buf = i::NewArray<char>(buf_size);
711 memset(buf, 'a', buf_size);
712 buf[buf_size - 1] = '\0';
713 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
715 // Large strings should be immediately accepted.
716 CHECK(large_string->CanMakeExternal());
720 TEST(MakingExternalUnalignedAsciiString) {
722 v8::HandleScope scope(env->GetIsolate());
724 CompileRun("function cons(a, b) { return a + b; }"
725 "function slice(a) { return a.substring(1); }");
726 // Create a cons string that will land in old pointer space.
727 Local<String> cons = Local<String>::Cast(CompileRun(
728 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
729 // Create a sliced string that will land in old pointer space.
730 Local<String> slice = Local<String>::Cast(CompileRun(
731 "slice('abcdefghijklmnopqrstuvwxyz');"));
733 // Trigger GCs so that the newly allocated string moves to old gen.
734 SimulateFullSpace(CcTest::heap()->old_pointer_space());
735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
736 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
738 // Turn into external string with unaligned resource data.
739 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
740 bool success = cons->MakeExternal(
741 new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
743 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
744 success = slice->MakeExternal(
745 new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
748 // Trigger GCs and force evacuation.
749 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
754 THREADED_TEST(UsingExternalString) {
755 i::Factory* factory = CcTest::i_isolate()->factory();
757 v8::HandleScope scope(CcTest::isolate());
758 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
759 Local<String> string = String::NewExternal(
760 CcTest::isolate(), new TestResource(two_byte_string));
761 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762 // Trigger GCs so that the newly allocated string moves to old gen.
763 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
764 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
765 i::Handle<i::String> isymbol =
766 factory->InternalizeString(istring);
767 CHECK(isymbol->IsInternalizedString());
769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
774 THREADED_TEST(UsingExternalAsciiString) {
775 i::Factory* factory = CcTest::i_isolate()->factory();
777 v8::HandleScope scope(CcTest::isolate());
778 const char* one_byte_string = "test string";
779 Local<String> string = String::NewExternal(
780 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
781 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
782 // Trigger GCs so that the newly allocated string moves to old gen.
783 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
784 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
785 i::Handle<i::String> isymbol =
786 factory->InternalizeString(istring);
787 CHECK(isymbol->IsInternalizedString());
789 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
790 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
794 THREADED_TEST(ScavengeExternalString) {
795 i::FLAG_stress_compaction = false;
796 i::FLAG_gc_global = false;
797 int dispose_count = 0;
798 bool in_new_space = false;
800 v8::HandleScope scope(CcTest::isolate());
801 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
802 Local<String> string = String::NewExternal(
803 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
804 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
805 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
806 in_new_space = CcTest::heap()->InNewSpace(*istring);
807 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
808 CHECK_EQ(0, dispose_count);
810 CcTest::heap()->CollectGarbage(
811 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
812 CHECK_EQ(1, dispose_count);
816 THREADED_TEST(ScavengeExternalAsciiString) {
817 i::FLAG_stress_compaction = false;
818 i::FLAG_gc_global = false;
819 int dispose_count = 0;
820 bool in_new_space = false;
822 v8::HandleScope scope(CcTest::isolate());
823 const char* one_byte_string = "test string";
824 Local<String> string = String::NewExternal(
826 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
827 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
828 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
829 in_new_space = CcTest::heap()->InNewSpace(*istring);
830 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
831 CHECK_EQ(0, dispose_count);
833 CcTest::heap()->CollectGarbage(
834 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
835 CHECK_EQ(1, dispose_count);
839 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
841 // Only used by non-threaded tests, so it can use static fields.
842 static int dispose_calls;
843 static int dispose_count;
845 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
846 : TestAsciiResource(data, &dispose_count),
847 dispose_(dispose) { }
851 if (dispose_) delete this;
858 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
859 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
862 TEST(ExternalStringWithDisposeHandling) {
863 const char* c_source = "1 + 2 * 3";
865 // Use a stack allocated external string resource allocated object.
866 TestAsciiResourceWithDisposeControl::dispose_count = 0;
867 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
871 v8::HandleScope scope(env->GetIsolate());
872 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
873 Local<Script> script = v8_compile(source);
874 Local<Value> value = script->Run();
875 CHECK(value->IsNumber());
876 CHECK_EQ(7, value->Int32Value());
877 CcTest::heap()->CollectAllAvailableGarbage();
878 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
880 CcTest::i_isolate()->compilation_cache()->Clear();
881 CcTest::heap()->CollectAllAvailableGarbage();
882 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
883 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
885 // Use a heap allocated external string resource allocated object.
886 TestAsciiResourceWithDisposeControl::dispose_count = 0;
887 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
888 TestAsciiResource* res_heap =
889 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
892 v8::HandleScope scope(env->GetIsolate());
893 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
894 Local<Script> script = v8_compile(source);
895 Local<Value> value = script->Run();
896 CHECK(value->IsNumber());
897 CHECK_EQ(7, value->Int32Value());
898 CcTest::heap()->CollectAllAvailableGarbage();
899 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
901 CcTest::i_isolate()->compilation_cache()->Clear();
902 CcTest::heap()->CollectAllAvailableGarbage();
903 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
904 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
908 THREADED_TEST(StringConcat) {
911 v8::HandleScope scope(env->GetIsolate());
912 const char* one_byte_string_1 = "function a_times_t";
913 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
914 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
915 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
916 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
917 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
919 Local<String> left = v8_str(one_byte_string_1);
921 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
922 Local<String> right =
923 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
924 i::DeleteArray(two_byte_source);
926 Local<String> source = String::Concat(left, right);
927 right = String::NewExternal(
928 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
929 source = String::Concat(source, right);
930 right = String::NewExternal(
932 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
933 source = String::Concat(source, right);
934 right = v8_str(one_byte_string_2);
935 source = String::Concat(source, right);
937 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
938 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
939 i::DeleteArray(two_byte_source);
941 source = String::Concat(source, right);
942 right = String::NewExternal(
944 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
945 source = String::Concat(source, right);
946 Local<Script> script = v8_compile(source);
947 Local<Value> value = script->Run();
948 CHECK(value->IsNumber());
949 CHECK_EQ(68, value->Int32Value());
951 CcTest::i_isolate()->compilation_cache()->Clear();
952 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
953 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
957 THREADED_TEST(GlobalProperties) {
959 v8::HandleScope scope(env->GetIsolate());
960 v8::Handle<v8::Object> global = env->Global();
961 global->Set(v8_str("pi"), v8_num(3.1415926));
962 Local<Value> pi = global->Get(v8_str("pi"));
963 CHECK_EQ(3.1415926, pi->NumberValue());
968 static void CheckReturnValue(const T& t, i::Address callback) {
969 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
970 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
971 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
972 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
973 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
975 bool is_runtime = (*o)->IsTheHole();
977 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
978 rv.Set(v8::Handle<v8::Object>());
979 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
980 CHECK_EQ(is_runtime, (*o)->IsTheHole());
982 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
983 // If CPU profiler is active check that when API callback is invoked
984 // VMState is set to EXTERNAL.
985 if (isolate->cpu_profiler()->is_profiling()) {
986 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
987 CHECK(isolate->external_callback_scope());
988 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
993 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
994 i::Address callback) {
995 ApiTestFuzzer::Fuzz();
996 CheckReturnValue(info, callback);
997 info.GetReturnValue().Set(v8_str("bad value"));
998 info.GetReturnValue().Set(v8_num(102));
1002 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1003 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1007 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1008 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1011 static void construct_callback(
1012 const v8::FunctionCallbackInfo<Value>& info) {
1013 ApiTestFuzzer::Fuzz();
1014 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1015 info.This()->Set(v8_str("x"), v8_num(1));
1016 info.This()->Set(v8_str("y"), v8_num(2));
1017 info.GetReturnValue().Set(v8_str("bad value"));
1018 info.GetReturnValue().Set(info.This());
1022 static void Return239Callback(
1023 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1024 ApiTestFuzzer::Fuzz();
1025 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1026 info.GetReturnValue().Set(v8_str("bad value"));
1027 info.GetReturnValue().Set(v8_num(239));
1031 template<typename Handler>
1032 static void TestFunctionTemplateInitializer(Handler handler,
1033 Handler handler_2) {
1034 // Test constructor calls.
1037 v8::Isolate* isolate = env->GetIsolate();
1038 v8::HandleScope scope(isolate);
1040 Local<v8::FunctionTemplate> fun_templ =
1041 v8::FunctionTemplate::New(isolate, handler);
1042 Local<Function> fun = fun_templ->GetFunction();
1043 env->Global()->Set(v8_str("obj"), fun);
1044 Local<Script> script = v8_compile("obj()");
1045 for (int i = 0; i < 30; i++) {
1046 CHECK_EQ(102, script->Run()->Int32Value());
1049 // Use SetCallHandler to initialize a function template, should work like
1050 // the previous one.
1053 v8::Isolate* isolate = env->GetIsolate();
1054 v8::HandleScope scope(isolate);
1056 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1057 fun_templ->SetCallHandler(handler_2);
1058 Local<Function> fun = fun_templ->GetFunction();
1059 env->Global()->Set(v8_str("obj"), fun);
1060 Local<Script> script = v8_compile("obj()");
1061 for (int i = 0; i < 30; i++) {
1062 CHECK_EQ(102, script->Run()->Int32Value());
1068 template<typename Constructor, typename Accessor>
1069 static void TestFunctionTemplateAccessor(Constructor constructor,
1070 Accessor accessor) {
1072 v8::HandleScope scope(env->GetIsolate());
1074 Local<v8::FunctionTemplate> fun_templ =
1075 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1076 fun_templ->SetClassName(v8_str("funky"));
1077 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1078 Local<Function> fun = fun_templ->GetFunction();
1079 env->Global()->Set(v8_str("obj"), fun);
1080 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1081 CHECK_EQ(v8_str("[object funky]"), result);
1082 CompileRun("var obj_instance = new obj();");
1083 Local<Script> script;
1084 script = v8_compile("obj_instance.x");
1085 for (int i = 0; i < 30; i++) {
1086 CHECK_EQ(1, script->Run()->Int32Value());
1088 script = v8_compile("obj_instance.m");
1089 for (int i = 0; i < 30; i++) {
1090 CHECK_EQ(239, script->Run()->Int32Value());
1095 THREADED_PROFILED_TEST(FunctionTemplate) {
1096 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1097 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1101 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1102 ApiTestFuzzer::Fuzz();
1103 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1104 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1108 template<typename Callback>
1109 static void TestSimpleCallback(Callback callback) {
1111 v8::Isolate* isolate = env->GetIsolate();
1112 v8::HandleScope scope(isolate);
1114 v8::Handle<v8::ObjectTemplate> object_template =
1115 v8::ObjectTemplate::New(isolate);
1116 object_template->Set(isolate, "callback",
1117 v8::FunctionTemplate::New(isolate, callback));
1118 v8::Local<v8::Object> object = object_template->NewInstance();
1119 (*env)->Global()->Set(v8_str("callback_object"), object);
1120 v8::Handle<v8::Script> script;
1121 script = v8_compile("callback_object.callback(17)");
1122 for (int i = 0; i < 30; i++) {
1123 CHECK_EQ(51424, script->Run()->Int32Value());
1125 script = v8_compile("callback_object.callback(17, 24)");
1126 for (int i = 0; i < 30; i++) {
1127 CHECK_EQ(51425, script->Run()->Int32Value());
1132 THREADED_PROFILED_TEST(SimpleCallback) {
1133 TestSimpleCallback(SimpleCallback);
1137 template<typename T>
1138 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1140 // constant return values
1141 static int32_t fast_return_value_int32 = 471;
1142 static uint32_t fast_return_value_uint32 = 571;
1143 static const double kFastReturnValueDouble = 2.7;
1144 // variable return values
1145 static bool fast_return_value_bool = false;
1146 enum ReturnValueOddball {
1148 kUndefinedReturnValue,
1149 kEmptyStringReturnValue
1151 static ReturnValueOddball fast_return_value_void;
1152 static bool fast_return_value_object_is_empty = false;
1154 // Helper function to avoid compiler error: insufficient contextual information
1155 // to determine type when applying FUNCTION_ADDR to a template function.
1156 static i::Address address_of(v8::FunctionCallback callback) {
1157 return FUNCTION_ADDR(callback);
1161 void FastReturnValueCallback<int32_t>(
1162 const v8::FunctionCallbackInfo<v8::Value>& info) {
1163 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1164 info.GetReturnValue().Set(fast_return_value_int32);
1168 void FastReturnValueCallback<uint32_t>(
1169 const v8::FunctionCallbackInfo<v8::Value>& info) {
1170 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1171 info.GetReturnValue().Set(fast_return_value_uint32);
1175 void FastReturnValueCallback<double>(
1176 const v8::FunctionCallbackInfo<v8::Value>& info) {
1177 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1178 info.GetReturnValue().Set(kFastReturnValueDouble);
1182 void FastReturnValueCallback<bool>(
1183 const v8::FunctionCallbackInfo<v8::Value>& info) {
1184 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1185 info.GetReturnValue().Set(fast_return_value_bool);
1189 void FastReturnValueCallback<void>(
1190 const v8::FunctionCallbackInfo<v8::Value>& info) {
1191 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1192 switch (fast_return_value_void) {
1193 case kNullReturnValue:
1194 info.GetReturnValue().SetNull();
1196 case kUndefinedReturnValue:
1197 info.GetReturnValue().SetUndefined();
1199 case kEmptyStringReturnValue:
1200 info.GetReturnValue().SetEmptyString();
1206 void FastReturnValueCallback<Object>(
1207 const v8::FunctionCallbackInfo<v8::Value>& info) {
1208 v8::Handle<v8::Object> object;
1209 if (!fast_return_value_object_is_empty) {
1210 object = Object::New(info.GetIsolate());
1212 info.GetReturnValue().Set(object);
1215 template<typename T>
1216 Handle<Value> TestFastReturnValues() {
1218 v8::Isolate* isolate = env->GetIsolate();
1219 v8::EscapableHandleScope scope(isolate);
1220 v8::Handle<v8::ObjectTemplate> object_template =
1221 v8::ObjectTemplate::New(isolate);
1222 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1223 object_template->Set(isolate, "callback",
1224 v8::FunctionTemplate::New(isolate, callback));
1225 v8::Local<v8::Object> object = object_template->NewInstance();
1226 (*env)->Global()->Set(v8_str("callback_object"), object);
1227 return scope.Escape(CompileRun("callback_object.callback()"));
1231 THREADED_PROFILED_TEST(FastReturnValues) {
1233 v8::HandleScope scope(CcTest::isolate());
1234 v8::Handle<v8::Value> value;
1235 // check int32_t and uint32_t
1236 int32_t int_values[] = {
1238 i::Smi::kMinValue, i::Smi::kMaxValue
1240 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1241 for (int modifier = -1; modifier <= 1; modifier++) {
1242 int int_value = int_values[i] + modifier;
1244 fast_return_value_int32 = int_value;
1245 value = TestFastReturnValues<int32_t>();
1246 CHECK(value->IsInt32());
1247 CHECK(fast_return_value_int32 == value->Int32Value());
1249 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1250 value = TestFastReturnValues<uint32_t>();
1251 CHECK(value->IsUint32());
1252 CHECK(fast_return_value_uint32 == value->Uint32Value());
1256 value = TestFastReturnValues<double>();
1257 CHECK(value->IsNumber());
1258 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1259 // check bool values
1260 for (int i = 0; i < 2; i++) {
1261 fast_return_value_bool = i == 0;
1262 value = TestFastReturnValues<bool>();
1263 CHECK(value->IsBoolean());
1264 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1267 ReturnValueOddball oddballs[] = {
1269 kUndefinedReturnValue,
1270 kEmptyStringReturnValue
1272 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1273 fast_return_value_void = oddballs[i];
1274 value = TestFastReturnValues<void>();
1275 switch (fast_return_value_void) {
1276 case kNullReturnValue:
1277 CHECK(value->IsNull());
1279 case kUndefinedReturnValue:
1280 CHECK(value->IsUndefined());
1282 case kEmptyStringReturnValue:
1283 CHECK(value->IsString());
1284 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1289 fast_return_value_object_is_empty = false;
1290 value = TestFastReturnValues<Object>();
1291 CHECK(value->IsObject());
1292 fast_return_value_object_is_empty = true;
1293 value = TestFastReturnValues<Object>();
1294 CHECK(value->IsUndefined());
1298 THREADED_TEST(FunctionTemplateSetLength) {
1300 v8::Isolate* isolate = env->GetIsolate();
1301 v8::HandleScope scope(isolate);
1303 Local<v8::FunctionTemplate> fun_templ =
1304 v8::FunctionTemplate::New(isolate,
1306 Handle<v8::Value>(),
1307 Handle<v8::Signature>(),
1309 Local<Function> fun = fun_templ->GetFunction();
1310 env->Global()->Set(v8_str("obj"), fun);
1311 Local<Script> script = v8_compile("obj.length");
1312 CHECK_EQ(23, script->Run()->Int32Value());
1315 Local<v8::FunctionTemplate> fun_templ =
1316 v8::FunctionTemplate::New(isolate, handle_callback);
1317 fun_templ->SetLength(22);
1318 Local<Function> fun = fun_templ->GetFunction();
1319 env->Global()->Set(v8_str("obj"), fun);
1320 Local<Script> script = v8_compile("obj.length");
1321 CHECK_EQ(22, script->Run()->Int32Value());
1324 // Without setting length it defaults to 0.
1325 Local<v8::FunctionTemplate> fun_templ =
1326 v8::FunctionTemplate::New(isolate, handle_callback);
1327 Local<Function> fun = fun_templ->GetFunction();
1328 env->Global()->Set(v8_str("obj"), fun);
1329 Local<Script> script = v8_compile("obj.length");
1330 CHECK_EQ(0, script->Run()->Int32Value());
1335 static void* expected_ptr;
1336 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1337 void* ptr = v8::External::Cast(*args.Data())->Value();
1338 CHECK_EQ(expected_ptr, ptr);
1339 args.GetReturnValue().Set(true);
1343 static void TestExternalPointerWrapping() {
1345 v8::Isolate* isolate = env->GetIsolate();
1346 v8::HandleScope scope(isolate);
1348 v8::Handle<v8::Value> data =
1349 v8::External::New(isolate, expected_ptr);
1351 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1352 obj->Set(v8_str("func"),
1353 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1354 env->Global()->Set(v8_str("obj"), obj);
1357 "function foo() {\n"
1358 " for (var i = 0; i < 13; i++) obj.func();\n"
1360 "foo(), true")->BooleanValue());
1364 THREADED_TEST(ExternalWrap) {
1365 // Check heap allocated object.
1368 TestExternalPointerWrapping();
1371 // Check stack allocated object.
1373 expected_ptr = &foo;
1374 TestExternalPointerWrapping();
1376 // Check not aligned addresses.
1378 char* s = new char[n];
1379 for (int i = 0; i < n; i++) {
1380 expected_ptr = s + i;
1381 TestExternalPointerWrapping();
1386 // Check several invalid addresses.
1387 expected_ptr = reinterpret_cast<void*>(1);
1388 TestExternalPointerWrapping();
1390 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1391 TestExternalPointerWrapping();
1393 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1394 TestExternalPointerWrapping();
1396 #if defined(V8_HOST_ARCH_X64)
1397 // Check a value with a leading 1 bit in x64 Smi encoding.
1398 expected_ptr = reinterpret_cast<void*>(0x400000000);
1399 TestExternalPointerWrapping();
1401 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1402 TestExternalPointerWrapping();
1404 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1405 TestExternalPointerWrapping();
1410 THREADED_TEST(FindInstanceInPrototypeChain) {
1412 v8::Isolate* isolate = env->GetIsolate();
1413 v8::HandleScope scope(isolate);
1415 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1416 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1417 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1418 derived->Inherit(base);
1420 Local<v8::Function> base_function = base->GetFunction();
1421 Local<v8::Function> derived_function = derived->GetFunction();
1422 Local<v8::Function> other_function = other->GetFunction();
1424 Local<v8::Object> base_instance = base_function->NewInstance();
1425 Local<v8::Object> derived_instance = derived_function->NewInstance();
1426 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1427 Local<v8::Object> other_instance = other_function->NewInstance();
1428 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1429 other_instance->Set(v8_str("__proto__"), derived_instance2);
1431 // base_instance is only an instance of base.
1432 CHECK_EQ(base_instance,
1433 base_instance->FindInstanceInPrototypeChain(base));
1434 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1435 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1437 // derived_instance is an instance of base and derived.
1438 CHECK_EQ(derived_instance,
1439 derived_instance->FindInstanceInPrototypeChain(base));
1440 CHECK_EQ(derived_instance,
1441 derived_instance->FindInstanceInPrototypeChain(derived));
1442 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1444 // other_instance is an instance of other and its immediate
1445 // prototype derived_instance2 is an instance of base and derived.
1446 // Note, derived_instance is an instance of base and derived too,
1447 // but it comes after derived_instance2 in the prototype chain of
1449 CHECK_EQ(derived_instance2,
1450 other_instance->FindInstanceInPrototypeChain(base));
1451 CHECK_EQ(derived_instance2,
1452 other_instance->FindInstanceInPrototypeChain(derived));
1453 CHECK_EQ(other_instance,
1454 other_instance->FindInstanceInPrototypeChain(other));
1458 THREADED_TEST(TinyInteger) {
1460 v8::Isolate* isolate = env->GetIsolate();
1461 v8::HandleScope scope(isolate);
1463 int32_t value = 239;
1464 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1465 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467 value_obj = v8::Integer::New(isolate, value);
1468 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1472 THREADED_TEST(BigSmiInteger) {
1474 v8::HandleScope scope(env->GetIsolate());
1475 v8::Isolate* isolate = CcTest::isolate();
1477 int32_t value = i::Smi::kMaxValue;
1478 // We cannot add one to a Smi::kMaxValue without wrapping.
1479 if (i::SmiValuesAre31Bits()) {
1480 CHECK(i::Smi::IsValid(value));
1481 CHECK(!i::Smi::IsValid(value + 1));
1483 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1484 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1486 value_obj = v8::Integer::New(isolate, value);
1487 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1492 THREADED_TEST(BigInteger) {
1494 v8::HandleScope scope(env->GetIsolate());
1495 v8::Isolate* isolate = CcTest::isolate();
1497 // We cannot add one to a Smi::kMaxValue without wrapping.
1498 if (i::SmiValuesAre31Bits()) {
1499 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1500 // The code will not be run in that case, due to the "if" guard.
1502 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1503 CHECK(value > i::Smi::kMaxValue);
1504 CHECK(!i::Smi::IsValid(value));
1506 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1507 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509 value_obj = v8::Integer::New(isolate, value);
1510 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1515 THREADED_TEST(TinyUnsignedInteger) {
1517 v8::HandleScope scope(env->GetIsolate());
1518 v8::Isolate* isolate = CcTest::isolate();
1520 uint32_t value = 239;
1522 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1523 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1526 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1530 THREADED_TEST(BigUnsignedSmiInteger) {
1532 v8::HandleScope scope(env->GetIsolate());
1533 v8::Isolate* isolate = CcTest::isolate();
1535 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1536 CHECK(i::Smi::IsValid(value));
1537 CHECK(!i::Smi::IsValid(value + 1));
1539 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1540 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1542 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1543 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1547 THREADED_TEST(BigUnsignedInteger) {
1549 v8::HandleScope scope(env->GetIsolate());
1550 v8::Isolate* isolate = CcTest::isolate();
1552 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1553 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1554 CHECK(!i::Smi::IsValid(value));
1556 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1557 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1559 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1560 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1564 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1566 v8::HandleScope scope(env->GetIsolate());
1567 v8::Isolate* isolate = CcTest::isolate();
1569 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1570 uint32_t value = INT32_MAX_AS_UINT + 1;
1571 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1573 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1574 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1577 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1581 THREADED_TEST(IsNativeError) {
1583 v8::HandleScope scope(env->GetIsolate());
1584 v8::Handle<Value> syntax_error = CompileRun(
1585 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1586 CHECK(syntax_error->IsNativeError());
1587 v8::Handle<Value> not_error = CompileRun("{a:42}");
1588 CHECK(!not_error->IsNativeError());
1589 v8::Handle<Value> not_object = CompileRun("42");
1590 CHECK(!not_object->IsNativeError());
1594 THREADED_TEST(StringObject) {
1596 v8::HandleScope scope(env->GetIsolate());
1597 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598 CHECK(boxed_string->IsStringObject());
1599 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600 CHECK(!unboxed_string->IsStringObject());
1601 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602 CHECK(!boxed_not_string->IsStringObject());
1603 v8::Handle<Value> not_object = CompileRun("0");
1604 CHECK(!not_object->IsStringObject());
1605 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606 CHECK(!as_boxed.IsEmpty());
1607 Local<v8::String> the_string = as_boxed->ValueOf();
1608 CHECK(!the_string.IsEmpty());
1609 ExpectObject("\"test\"", the_string);
1610 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611 CHECK(new_boxed_string->IsStringObject());
1612 as_boxed = new_boxed_string.As<v8::StringObject>();
1613 the_string = as_boxed->ValueOf();
1614 CHECK(!the_string.IsEmpty());
1615 ExpectObject("\"test\"", the_string);
1619 THREADED_TEST(NumberObject) {
1621 v8::HandleScope scope(env->GetIsolate());
1622 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623 CHECK(boxed_number->IsNumberObject());
1624 v8::Handle<Value> unboxed_number = CompileRun("42");
1625 CHECK(!unboxed_number->IsNumberObject());
1626 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627 CHECK(!boxed_not_number->IsNumberObject());
1628 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629 CHECK(!as_boxed.IsEmpty());
1630 double the_number = as_boxed->ValueOf();
1631 CHECK_EQ(42.0, the_number);
1632 v8::Handle<v8::Value> new_boxed_number =
1633 v8::NumberObject::New(env->GetIsolate(), 43);
1634 CHECK(new_boxed_number->IsNumberObject());
1635 as_boxed = new_boxed_number.As<v8::NumberObject>();
1636 the_number = as_boxed->ValueOf();
1637 CHECK_EQ(43.0, the_number);
1641 THREADED_TEST(BooleanObject) {
1643 v8::HandleScope scope(env->GetIsolate());
1644 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645 CHECK(boxed_boolean->IsBooleanObject());
1646 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647 CHECK(!unboxed_boolean->IsBooleanObject());
1648 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649 CHECK(!boxed_not_boolean->IsBooleanObject());
1650 v8::Handle<v8::BooleanObject> as_boxed =
1651 boxed_boolean.As<v8::BooleanObject>();
1652 CHECK(!as_boxed.IsEmpty());
1653 bool the_boolean = as_boxed->ValueOf();
1654 CHECK_EQ(true, the_boolean);
1655 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657 CHECK(boxed_true->IsBooleanObject());
1658 CHECK(boxed_false->IsBooleanObject());
1659 as_boxed = boxed_true.As<v8::BooleanObject>();
1660 CHECK_EQ(true, as_boxed->ValueOf());
1661 as_boxed = boxed_false.As<v8::BooleanObject>();
1662 CHECK_EQ(false, as_boxed->ValueOf());
1666 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1668 v8::HandleScope scope(env->GetIsolate());
1670 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671 CHECK(primitive_false->IsBoolean());
1672 CHECK(!primitive_false->IsBooleanObject());
1673 CHECK(!primitive_false->BooleanValue());
1674 CHECK(!primitive_false->IsTrue());
1675 CHECK(primitive_false->IsFalse());
1677 Local<Value> false_value = BooleanObject::New(false);
1678 CHECK(!false_value->IsBoolean());
1679 CHECK(false_value->IsBooleanObject());
1680 CHECK(false_value->BooleanValue());
1681 CHECK(!false_value->IsTrue());
1682 CHECK(!false_value->IsFalse());
1684 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685 CHECK(!false_boolean_object->IsBoolean());
1686 CHECK(false_boolean_object->IsBooleanObject());
1687 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688 // CHECK(false_boolean_object->BooleanValue());
1689 CHECK(!false_boolean_object->ValueOf());
1690 CHECK(!false_boolean_object->IsTrue());
1691 CHECK(!false_boolean_object->IsFalse());
1693 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694 CHECK(primitive_true->IsBoolean());
1695 CHECK(!primitive_true->IsBooleanObject());
1696 CHECK(primitive_true->BooleanValue());
1697 CHECK(primitive_true->IsTrue());
1698 CHECK(!primitive_true->IsFalse());
1700 Local<Value> true_value = BooleanObject::New(true);
1701 CHECK(!true_value->IsBoolean());
1702 CHECK(true_value->IsBooleanObject());
1703 CHECK(true_value->BooleanValue());
1704 CHECK(!true_value->IsTrue());
1705 CHECK(!true_value->IsFalse());
1707 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708 CHECK(!true_boolean_object->IsBoolean());
1709 CHECK(true_boolean_object->IsBooleanObject());
1710 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711 // CHECK(true_boolean_object->BooleanValue());
1712 CHECK(true_boolean_object->ValueOf());
1713 CHECK(!true_boolean_object->IsTrue());
1714 CHECK(!true_boolean_object->IsFalse());
1718 THREADED_TEST(Number) {
1720 v8::HandleScope scope(env->GetIsolate());
1721 double PI = 3.1415926;
1722 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723 CHECK_EQ(PI, pi_obj->NumberValue());
1727 THREADED_TEST(ToNumber) {
1729 v8::Isolate* isolate = CcTest::isolate();
1730 v8::HandleScope scope(isolate);
1731 Local<String> str = v8_str("3.1415926");
1732 CHECK_EQ(3.1415926, str->NumberValue());
1733 v8::Handle<v8::Boolean> t = v8::True(isolate);
1734 CHECK_EQ(1.0, t->NumberValue());
1735 v8::Handle<v8::Boolean> f = v8::False(isolate);
1736 CHECK_EQ(0.0, f->NumberValue());
1740 THREADED_TEST(Date) {
1742 v8::HandleScope scope(env->GetIsolate());
1743 double PI = 3.1415926;
1744 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745 CHECK_EQ(3.0, date->NumberValue());
1746 date.As<v8::Date>()->Set(v8_str("property"),
1747 v8::Integer::New(env->GetIsolate(), 42));
1748 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1752 THREADED_TEST(Boolean) {
1754 v8::Isolate* isolate = env->GetIsolate();
1755 v8::HandleScope scope(isolate);
1756 v8::Handle<v8::Boolean> t = v8::True(isolate);
1758 v8::Handle<v8::Boolean> f = v8::False(isolate);
1760 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761 CHECK(!u->BooleanValue());
1762 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763 CHECK(!n->BooleanValue());
1764 v8::Handle<String> str1 = v8_str("");
1765 CHECK(!str1->BooleanValue());
1766 v8::Handle<String> str2 = v8_str("x");
1767 CHECK(str2->BooleanValue());
1768 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1772 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777 ApiTestFuzzer::Fuzz();
1778 args.GetReturnValue().Set(v8_num(13.4));
1782 static void GetM(Local<String> name,
1783 const v8::PropertyCallbackInfo<v8::Value>& info) {
1784 ApiTestFuzzer::Fuzz();
1785 info.GetReturnValue().Set(v8_num(876));
1789 THREADED_TEST(GlobalPrototype) {
1790 v8::Isolate* isolate = CcTest::isolate();
1791 v8::HandleScope scope(isolate);
1792 v8::Handle<v8::FunctionTemplate> func_templ =
1793 v8::FunctionTemplate::New(isolate);
1794 func_templ->PrototypeTemplate()->Set(
1795 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797 templ->Set(isolate, "x", v8_num(200));
1798 templ->SetAccessor(v8_str("m"), GetM);
1799 LocalContext env(0, templ);
1800 v8::Handle<Script> script(v8_compile("dummy()"));
1801 v8::Handle<Value> result(script->Run());
1802 CHECK_EQ(13.4, result->NumberValue());
1803 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1808 THREADED_TEST(ObjectTemplate) {
1809 v8::Isolate* isolate = CcTest::isolate();
1810 v8::HandleScope scope(isolate);
1811 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812 templ1->Set(isolate, "x", v8_num(10));
1813 templ1->Set(isolate, "y", v8_num(13));
1815 Local<v8::Object> instance1 = templ1->NewInstance();
1816 env->Global()->Set(v8_str("p"), instance1);
1817 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1819 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822 templ2->Set(isolate, "a", v8_num(12));
1823 templ2->Set(isolate, "b", templ1);
1824 Local<v8::Object> instance2 = templ2->NewInstance();
1825 env->Global()->Set(v8_str("q"), instance2);
1826 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834 ApiTestFuzzer::Fuzz();
1835 args.GetReturnValue().Set(v8_num(17.2));
1839 static void GetKnurd(Local<String> property,
1840 const v8::PropertyCallbackInfo<v8::Value>& info) {
1841 ApiTestFuzzer::Fuzz();
1842 info.GetReturnValue().Set(v8_num(15.2));
1846 THREADED_TEST(DescriptorInheritance) {
1847 v8::Isolate* isolate = CcTest::isolate();
1848 v8::HandleScope scope(isolate);
1849 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850 super->PrototypeTemplate()->Set(isolate, "flabby",
1851 v8::FunctionTemplate::New(isolate,
1853 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1855 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1857 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858 base1->Inherit(super);
1859 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1861 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862 base2->Inherit(super);
1863 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1867 env->Global()->Set(v8_str("s"), super->GetFunction());
1868 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1871 // Checks right __proto__ chain.
1872 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1875 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1877 // Instance accessor should not be visible on function object or its prototype
1878 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1882 env->Global()->Set(v8_str("obj"),
1883 base1->GetFunction()->NewInstance());
1884 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1890 env->Global()->Set(v8_str("obj2"),
1891 base2->GetFunction()->NewInstance());
1892 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1898 // base1 and base2 cannot cross reference to each's prototype
1899 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1904 int echo_named_call_count;
1907 static void EchoNamedProperty(Local<String> name,
1908 const v8::PropertyCallbackInfo<v8::Value>& info) {
1909 ApiTestFuzzer::Fuzz();
1910 CHECK_EQ(v8_str("data"), info.Data());
1911 echo_named_call_count++;
1912 info.GetReturnValue().Set(name);
1916 // Helper functions for Interceptor/Accessor interaction tests
1918 void SimpleAccessorGetter(Local<String> name,
1919 const v8::PropertyCallbackInfo<v8::Value>& info) {
1920 Handle<Object> self = Handle<Object>::Cast(info.This());
1921 info.GetReturnValue().Set(
1922 self->Get(String::Concat(v8_str("accessor_"), name)));
1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926 const v8::PropertyCallbackInfo<void>& info) {
1927 Handle<Object> self = Handle<Object>::Cast(info.This());
1928 self->Set(String::Concat(v8_str("accessor_"), name), value);
1931 void EmptyInterceptorGetter(Local<String> name,
1932 const v8::PropertyCallbackInfo<v8::Value>& info) {
1935 void EmptyInterceptorSetter(Local<String> name,
1937 const v8::PropertyCallbackInfo<v8::Value>& info) {
1940 void InterceptorGetter(Local<String> name,
1941 const v8::PropertyCallbackInfo<v8::Value>& info) {
1942 // Intercept names that start with 'interceptor_'.
1943 String::Utf8Value utf8(name);
1944 char* name_str = *utf8;
1945 char prefix[] = "interceptor_";
1947 for (i = 0; name_str[i] && prefix[i]; ++i) {
1948 if (name_str[i] != prefix[i]) return;
1950 Handle<Object> self = Handle<Object>::Cast(info.This());
1951 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1954 void InterceptorSetter(Local<String> name,
1956 const v8::PropertyCallbackInfo<v8::Value>& info) {
1957 // Intercept accesses that set certain integer values, for which the name does
1958 // not start with 'accessor_'.
1959 String::Utf8Value utf8(name);
1960 char* name_str = *utf8;
1961 char prefix[] = "accessor_";
1963 for (i = 0; name_str[i] && prefix[i]; ++i) {
1964 if (name_str[i] != prefix[i]) break;
1966 if (!prefix[i]) return;
1968 if (value->IsInt32() && value->Int32Value() < 10000) {
1969 Handle<Object> self = Handle<Object>::Cast(info.This());
1970 self->SetHiddenValue(name, value);
1971 info.GetReturnValue().Set(value);
1975 void AddAccessor(Handle<FunctionTemplate> templ,
1976 Handle<String> name,
1977 v8::AccessorGetterCallback getter,
1978 v8::AccessorSetterCallback setter) {
1979 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1982 void AddInterceptor(Handle<FunctionTemplate> templ,
1983 v8::NamedPropertyGetterCallback getter,
1984 v8::NamedPropertySetterCallback setter) {
1985 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1989 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1990 v8::HandleScope scope(CcTest::isolate());
1991 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1992 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1993 child->Inherit(parent);
1994 AddAccessor(parent, v8_str("age"),
1995 SimpleAccessorGetter, SimpleAccessorSetter);
1996 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1998 env->Global()->Set(v8_str("Child"), child->GetFunction());
1999 CompileRun("var child = new Child;"
2001 ExpectBoolean("child.hasOwnProperty('age')", false);
2002 ExpectInt32("child.age", 10);
2003 ExpectInt32("child.accessor_age", 10);
2007 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2008 v8::HandleScope scope(CcTest::isolate());
2009 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2010 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2012 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2013 CompileRun("var o1 = new Constructor;"
2014 "o1.a = 1;" // Ensure a and x share the descriptor array.
2015 "Object.defineProperty(o1, 'x', {value: 10});");
2016 CompileRun("var o2 = new Constructor;"
2018 "Object.defineProperty(o2, 'x', {value: 10});");
2022 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2023 v8::Isolate* isolate = CcTest::isolate();
2024 v8::HandleScope scope(isolate);
2025 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2026 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2027 child->Inherit(parent);
2028 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2030 env->Global()->Set(v8_str("Child"), child->GetFunction());
2031 CompileRun("var child = new Child;"
2032 "var parent = child.__proto__;"
2033 "Object.defineProperty(parent, 'age', "
2034 " {get: function(){ return this.accessor_age; }, "
2035 " set: function(v){ this.accessor_age = v; }, "
2036 " enumerable: true, configurable: true});"
2038 ExpectBoolean("child.hasOwnProperty('age')", false);
2039 ExpectInt32("child.age", 10);
2040 ExpectInt32("child.accessor_age", 10);
2044 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2045 v8::Isolate* isolate = CcTest::isolate();
2046 v8::HandleScope scope(isolate);
2047 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2048 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2049 child->Inherit(parent);
2050 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2052 env->Global()->Set(v8_str("Child"), child->GetFunction());
2053 CompileRun("var child = new Child;"
2054 "var parent = child.__proto__;"
2055 "parent.name = 'Alice';");
2056 ExpectBoolean("child.hasOwnProperty('name')", false);
2057 ExpectString("child.name", "Alice");
2058 CompileRun("child.name = 'Bob';");
2059 ExpectString("child.name", "Bob");
2060 ExpectBoolean("child.hasOwnProperty('name')", true);
2061 ExpectString("parent.name", "Alice");
2065 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2066 v8::HandleScope scope(CcTest::isolate());
2067 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2068 AddAccessor(templ, v8_str("age"),
2069 SimpleAccessorGetter, SimpleAccessorSetter);
2070 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2072 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2073 CompileRun("var obj = new Obj;"
2074 "function setAge(i){ obj.age = i; };"
2075 "for(var i = 0; i <= 10000; i++) setAge(i);");
2076 // All i < 10000 go to the interceptor.
2077 ExpectInt32("obj.interceptor_age", 9999);
2078 // The last i goes to the accessor.
2079 ExpectInt32("obj.accessor_age", 10000);
2083 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2084 v8::HandleScope scope(CcTest::isolate());
2085 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2086 AddAccessor(templ, v8_str("age"),
2087 SimpleAccessorGetter, SimpleAccessorSetter);
2088 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2090 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2091 CompileRun("var obj = new Obj;"
2092 "function setAge(i){ obj.age = i; };"
2093 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2094 // All i >= 10000 go to the accessor.
2095 ExpectInt32("obj.accessor_age", 10000);
2096 // The last i goes to the interceptor.
2097 ExpectInt32("obj.interceptor_age", 9999);
2101 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2102 v8::HandleScope scope(CcTest::isolate());
2103 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2104 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2105 child->Inherit(parent);
2106 AddAccessor(parent, v8_str("age"),
2107 SimpleAccessorGetter, SimpleAccessorSetter);
2108 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2110 env->Global()->Set(v8_str("Child"), child->GetFunction());
2111 CompileRun("var child = new Child;"
2112 "function setAge(i){ child.age = i; };"
2113 "for(var i = 0; i <= 10000; i++) setAge(i);");
2114 // All i < 10000 go to the interceptor.
2115 ExpectInt32("child.interceptor_age", 9999);
2116 // The last i goes to the accessor.
2117 ExpectInt32("child.accessor_age", 10000);
2121 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2122 v8::HandleScope scope(CcTest::isolate());
2123 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2124 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2125 child->Inherit(parent);
2126 AddAccessor(parent, v8_str("age"),
2127 SimpleAccessorGetter, SimpleAccessorSetter);
2128 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2130 env->Global()->Set(v8_str("Child"), child->GetFunction());
2131 CompileRun("var child = new Child;"
2132 "function setAge(i){ child.age = i; };"
2133 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2134 // All i >= 10000 go to the accessor.
2135 ExpectInt32("child.accessor_age", 10000);
2136 // The last i goes to the interceptor.
2137 ExpectInt32("child.interceptor_age", 9999);
2141 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2142 v8::HandleScope scope(CcTest::isolate());
2143 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2146 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2147 CompileRun("var obj = new Obj;"
2148 "function setter(i) { this.accessor_age = i; };"
2149 "function getter() { return this.accessor_age; };"
2150 "function setAge(i) { obj.age = i; };"
2151 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2152 "for(var i = 0; i <= 10000; i++) setAge(i);");
2153 // All i < 10000 go to the interceptor.
2154 ExpectInt32("obj.interceptor_age", 9999);
2155 // The last i goes to the JavaScript accessor.
2156 ExpectInt32("obj.accessor_age", 10000);
2157 // The installed JavaScript getter is still intact.
2158 // This last part is a regression test for issue 1651 and relies on the fact
2159 // that both interceptor and accessor are being installed on the same object.
2160 ExpectInt32("obj.age", 10000);
2161 ExpectBoolean("obj.hasOwnProperty('age')", true);
2162 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2166 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2167 v8::HandleScope scope(CcTest::isolate());
2168 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2169 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2171 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2172 CompileRun("var obj = new Obj;"
2173 "function setter(i) { this.accessor_age = i; };"
2174 "function getter() { return this.accessor_age; };"
2175 "function setAge(i) { obj.age = i; };"
2176 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2177 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2178 // All i >= 10000 go to the accessor.
2179 ExpectInt32("obj.accessor_age", 10000);
2180 // The last i goes to the interceptor.
2181 ExpectInt32("obj.interceptor_age", 9999);
2182 // The installed JavaScript getter is still intact.
2183 // This last part is a regression test for issue 1651 and relies on the fact
2184 // that both interceptor and accessor are being installed on the same object.
2185 ExpectInt32("obj.age", 10000);
2186 ExpectBoolean("obj.hasOwnProperty('age')", true);
2187 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2191 THREADED_TEST(SwitchFromInterceptorToProperty) {
2192 v8::HandleScope scope(CcTest::isolate());
2193 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2194 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2195 child->Inherit(parent);
2196 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2198 env->Global()->Set(v8_str("Child"), child->GetFunction());
2199 CompileRun("var child = new Child;"
2200 "function setAge(i){ child.age = i; };"
2201 "for(var i = 0; i <= 10000; i++) setAge(i);");
2202 // All i < 10000 go to the interceptor.
2203 ExpectInt32("child.interceptor_age", 9999);
2204 // The last i goes to child's own property.
2205 ExpectInt32("child.age", 10000);
2209 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2210 v8::HandleScope scope(CcTest::isolate());
2211 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2212 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2213 child->Inherit(parent);
2214 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2216 env->Global()->Set(v8_str("Child"), child->GetFunction());
2217 CompileRun("var child = new Child;"
2218 "function setAge(i){ child.age = i; };"
2219 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2220 // All i >= 10000 go to child's own property.
2221 ExpectInt32("child.age", 10000);
2222 // The last i goes to the interceptor.
2223 ExpectInt32("child.interceptor_age", 9999);
2227 THREADED_TEST(NamedPropertyHandlerGetter) {
2228 echo_named_call_count = 0;
2229 v8::HandleScope scope(CcTest::isolate());
2230 v8::Handle<v8::FunctionTemplate> templ =
2231 v8::FunctionTemplate::New(CcTest::isolate());
2232 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2236 env->Global()->Set(v8_str("obj"),
2237 templ->GetFunction()->NewInstance());
2238 CHECK_EQ(echo_named_call_count, 0);
2239 v8_compile("obj.x")->Run();
2240 CHECK_EQ(echo_named_call_count, 1);
2241 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2242 v8::Handle<Value> str = CompileRun(code);
2243 String::Utf8Value value(str);
2244 CHECK_EQ(*value, "oddlepoddle");
2245 // Check default behavior
2246 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2247 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2248 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2252 int echo_indexed_call_count = 0;
2255 static void EchoIndexedProperty(
2257 const v8::PropertyCallbackInfo<v8::Value>& info) {
2258 ApiTestFuzzer::Fuzz();
2259 CHECK_EQ(v8_num(637), info.Data());
2260 echo_indexed_call_count++;
2261 info.GetReturnValue().Set(v8_num(index));
2265 THREADED_TEST(IndexedPropertyHandlerGetter) {
2266 v8::Isolate* isolate = CcTest::isolate();
2267 v8::HandleScope scope(isolate);
2268 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2269 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2273 env->Global()->Set(v8_str("obj"),
2274 templ->GetFunction()->NewInstance());
2275 Local<Script> script = v8_compile("obj[900]");
2276 CHECK_EQ(script->Run()->Int32Value(), 900);
2280 v8::Handle<v8::Object> bottom;
2282 static void CheckThisIndexedPropertyHandler(
2284 const v8::PropertyCallbackInfo<v8::Value>& info) {
2285 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2286 ApiTestFuzzer::Fuzz();
2287 CHECK(info.This()->Equals(bottom));
2290 static void CheckThisNamedPropertyHandler(
2292 const v8::PropertyCallbackInfo<v8::Value>& info) {
2293 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2294 ApiTestFuzzer::Fuzz();
2295 CHECK(info.This()->Equals(bottom));
2298 void CheckThisIndexedPropertySetter(
2301 const v8::PropertyCallbackInfo<v8::Value>& info) {
2302 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2303 ApiTestFuzzer::Fuzz();
2304 CHECK(info.This()->Equals(bottom));
2308 void CheckThisNamedPropertySetter(
2309 Local<String> property,
2311 const v8::PropertyCallbackInfo<v8::Value>& info) {
2312 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2313 ApiTestFuzzer::Fuzz();
2314 CHECK(info.This()->Equals(bottom));
2317 void CheckThisIndexedPropertyQuery(
2319 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2320 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2321 ApiTestFuzzer::Fuzz();
2322 CHECK(info.This()->Equals(bottom));
2326 void CheckThisNamedPropertyQuery(
2327 Local<String> property,
2328 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2329 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2330 ApiTestFuzzer::Fuzz();
2331 CHECK(info.This()->Equals(bottom));
2335 void CheckThisIndexedPropertyDeleter(
2337 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2338 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2339 ApiTestFuzzer::Fuzz();
2340 CHECK(info.This()->Equals(bottom));
2344 void CheckThisNamedPropertyDeleter(
2345 Local<String> property,
2346 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2347 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2348 ApiTestFuzzer::Fuzz();
2349 CHECK(info.This()->Equals(bottom));
2353 void CheckThisIndexedPropertyEnumerator(
2354 const v8::PropertyCallbackInfo<v8::Array>& info) {
2355 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2356 ApiTestFuzzer::Fuzz();
2357 CHECK(info.This()->Equals(bottom));
2361 void CheckThisNamedPropertyEnumerator(
2362 const v8::PropertyCallbackInfo<v8::Array>& info) {
2363 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2364 ApiTestFuzzer::Fuzz();
2365 CHECK(info.This()->Equals(bottom));
2369 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2371 v8::Isolate* isolate = env->GetIsolate();
2372 v8::HandleScope scope(isolate);
2374 // Set up a prototype chain with three interceptors.
2375 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2376 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2377 CheckThisIndexedPropertyHandler,
2378 CheckThisIndexedPropertySetter,
2379 CheckThisIndexedPropertyQuery,
2380 CheckThisIndexedPropertyDeleter,
2381 CheckThisIndexedPropertyEnumerator);
2383 templ->InstanceTemplate()->SetNamedPropertyHandler(
2384 CheckThisNamedPropertyHandler,
2385 CheckThisNamedPropertySetter,
2386 CheckThisNamedPropertyQuery,
2387 CheckThisNamedPropertyDeleter,
2388 CheckThisNamedPropertyEnumerator);
2390 bottom = templ->GetFunction()->NewInstance();
2391 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2392 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2394 bottom->SetPrototype(middle);
2395 middle->SetPrototype(top);
2396 env->Global()->Set(v8_str("obj"), bottom);
2398 // Indexed and named get.
2399 CompileRun("obj[0]");
2400 CompileRun("obj.x");
2402 // Indexed and named set.
2403 CompileRun("obj[1] = 42");
2404 CompileRun("obj.y = 42");
2406 // Indexed and named query.
2407 CompileRun("0 in obj");
2408 CompileRun("'x' in obj");
2410 // Indexed and named deleter.
2411 CompileRun("delete obj[0]");
2412 CompileRun("delete obj.x");
2415 CompileRun("for (var p in obj) ;");
2419 static void PrePropertyHandlerGet(
2421 const v8::PropertyCallbackInfo<v8::Value>& info) {
2422 ApiTestFuzzer::Fuzz();
2423 if (v8_str("pre")->Equals(key)) {
2424 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2429 static void PrePropertyHandlerQuery(
2431 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2432 if (v8_str("pre")->Equals(key)) {
2433 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2438 THREADED_TEST(PrePropertyHandler) {
2439 v8::Isolate* isolate = CcTest::isolate();
2440 v8::HandleScope scope(isolate);
2441 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2442 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2444 PrePropertyHandlerQuery);
2445 LocalContext env(NULL, desc->InstanceTemplate());
2446 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2447 v8::Handle<Value> result_pre = CompileRun("pre");
2448 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2449 v8::Handle<Value> result_on = CompileRun("on");
2450 CHECK_EQ(v8_str("Object: on"), result_on);
2451 v8::Handle<Value> result_post = CompileRun("post");
2452 CHECK(result_post.IsEmpty());
2456 THREADED_TEST(UndefinedIsNotEnumerable) {
2458 v8::HandleScope scope(env->GetIsolate());
2459 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2460 CHECK(result->IsFalse());
2464 v8::Handle<Script> call_recursively_script;
2465 static const int kTargetRecursionDepth = 200; // near maximum
2468 static void CallScriptRecursivelyCall(
2469 const v8::FunctionCallbackInfo<v8::Value>& args) {
2470 ApiTestFuzzer::Fuzz();
2471 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2472 if (depth == kTargetRecursionDepth) return;
2473 args.This()->Set(v8_str("depth"),
2474 v8::Integer::New(args.GetIsolate(), depth + 1));
2475 args.GetReturnValue().Set(call_recursively_script->Run());
2479 static void CallFunctionRecursivelyCall(
2480 const v8::FunctionCallbackInfo<v8::Value>& args) {
2481 ApiTestFuzzer::Fuzz();
2482 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2483 if (depth == kTargetRecursionDepth) {
2484 printf("[depth = %d]\n", depth);
2487 args.This()->Set(v8_str("depth"),
2488 v8::Integer::New(args.GetIsolate(), depth + 1));
2489 v8::Handle<Value> function =
2490 args.This()->Get(v8_str("callFunctionRecursively"));
2491 args.GetReturnValue().Set(
2492 function.As<Function>()->Call(args.This(), 0, NULL));
2496 THREADED_TEST(DeepCrossLanguageRecursion) {
2497 v8::Isolate* isolate = CcTest::isolate();
2498 v8::HandleScope scope(isolate);
2499 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2500 global->Set(v8_str("callScriptRecursively"),
2501 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2502 global->Set(v8_str("callFunctionRecursively"),
2503 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2504 LocalContext env(NULL, global);
2506 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2507 call_recursively_script = v8_compile("callScriptRecursively()");
2508 call_recursively_script->Run();
2509 call_recursively_script = v8::Handle<Script>();
2511 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2512 CompileRun("callFunctionRecursively()");
2516 static void ThrowingPropertyHandlerGet(
2518 const v8::PropertyCallbackInfo<v8::Value>& info) {
2519 ApiTestFuzzer::Fuzz();
2520 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2524 static void ThrowingPropertyHandlerSet(
2527 const v8::PropertyCallbackInfo<v8::Value>& info) {
2528 info.GetIsolate()->ThrowException(key);
2529 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2533 THREADED_TEST(CallbackExceptionRegression) {
2534 v8::Isolate* isolate = CcTest::isolate();
2535 v8::HandleScope scope(isolate);
2536 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2537 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2538 ThrowingPropertyHandlerSet);
2540 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2541 v8::Handle<Value> otto = CompileRun(
2542 "try { with (obj) { otto; } } catch (e) { e; }");
2543 CHECK_EQ(v8_str("otto"), otto);
2544 v8::Handle<Value> netto = CompileRun(
2545 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2546 CHECK_EQ(v8_str("netto"), netto);
2550 THREADED_TEST(FunctionPrototype) {
2551 v8::Isolate* isolate = CcTest::isolate();
2552 v8::HandleScope scope(isolate);
2553 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2554 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2556 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2557 Local<Script> script = v8_compile("Foo.prototype.plak");
2558 CHECK_EQ(script->Run()->Int32Value(), 321);
2562 THREADED_TEST(InternalFields) {
2564 v8::Isolate* isolate = env->GetIsolate();
2565 v8::HandleScope scope(isolate);
2567 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2568 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2569 instance_templ->SetInternalFieldCount(1);
2570 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2571 CHECK_EQ(1, obj->InternalFieldCount());
2572 CHECK(obj->GetInternalField(0)->IsUndefined());
2573 obj->SetInternalField(0, v8_num(17));
2574 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2578 THREADED_TEST(GlobalObjectInternalFields) {
2579 v8::Isolate* isolate = CcTest::isolate();
2580 v8::HandleScope scope(isolate);
2581 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2582 global_template->SetInternalFieldCount(1);
2583 LocalContext env(NULL, global_template);
2584 v8::Handle<v8::Object> global_proxy = env->Global();
2585 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2586 CHECK_EQ(1, global->InternalFieldCount());
2587 CHECK(global->GetInternalField(0)->IsUndefined());
2588 global->SetInternalField(0, v8_num(17));
2589 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2593 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2595 v8::HandleScope scope(CcTest::isolate());
2597 v8::Local<v8::Object> global = env->Global();
2598 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2599 CHECK(global->HasRealIndexedProperty(0));
2603 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2605 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2606 obj->SetAlignedPointerInInternalField(0, value);
2607 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2608 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2612 THREADED_TEST(InternalFieldsAlignedPointers) {
2614 v8::Isolate* isolate = env->GetIsolate();
2615 v8::HandleScope scope(isolate);
2617 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2618 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2619 instance_templ->SetInternalFieldCount(1);
2620 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2621 CHECK_EQ(1, obj->InternalFieldCount());
2623 CheckAlignedPointerInInternalField(obj, NULL);
2625 int* heap_allocated = new int[100];
2626 CheckAlignedPointerInInternalField(obj, heap_allocated);
2627 delete[] heap_allocated;
2629 int stack_allocated[100];
2630 CheckAlignedPointerInInternalField(obj, stack_allocated);
2632 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2633 CheckAlignedPointerInInternalField(obj, huge);
2635 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2636 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2637 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2641 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2644 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2645 (*env)->SetAlignedPointerInEmbedderData(index, value);
2646 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2647 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2651 static void* AlignedTestPointer(int i) {
2652 return reinterpret_cast<void*>(i * 1234);
2656 THREADED_TEST(EmbedderDataAlignedPointers) {
2658 v8::HandleScope scope(env->GetIsolate());
2660 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2662 int* heap_allocated = new int[100];
2663 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2664 delete[] heap_allocated;
2666 int stack_allocated[100];
2667 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2669 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2670 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2672 // Test growing of the embedder data's backing store.
2673 for (int i = 0; i < 100; i++) {
2674 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2676 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2677 for (int i = 0; i < 100; i++) {
2678 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2683 static void CheckEmbedderData(LocalContext* env,
2685 v8::Handle<Value> data) {
2686 (*env)->SetEmbedderData(index, data);
2687 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2691 THREADED_TEST(EmbedderData) {
2693 v8::Isolate* isolate = env->GetIsolate();
2694 v8::HandleScope scope(isolate);
2698 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2699 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2700 "over the lazy dog."));
2701 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2702 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2706 THREADED_TEST(IdentityHash) {
2708 v8::Isolate* isolate = env->GetIsolate();
2709 v8::HandleScope scope(isolate);
2711 // Ensure that the test starts with an fresh heap to test whether the hash
2712 // code is based on the address.
2713 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2714 Local<v8::Object> obj = v8::Object::New(isolate);
2715 int hash = obj->GetIdentityHash();
2716 int hash1 = obj->GetIdentityHash();
2717 CHECK_EQ(hash, hash1);
2718 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2719 // Since the identity hash is essentially a random number two consecutive
2720 // objects should not be assigned the same hash code. If the test below fails
2721 // the random number generator should be evaluated.
2722 CHECK_NE(hash, hash2);
2723 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2724 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2725 // Make sure that the identity hash is not based on the initial address of
2726 // the object alone. If the test below fails the random number generator
2727 // should be evaluated.
2728 CHECK_NE(hash, hash3);
2729 int hash4 = obj->GetIdentityHash();
2730 CHECK_EQ(hash, hash4);
2732 // Check identity hashes behaviour in the presence of JS accessors.
2733 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2735 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2736 Local<v8::Object> o1 = v8::Object::New(isolate);
2737 Local<v8::Object> o2 = v8::Object::New(isolate);
2738 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2742 "function cnst() { return 42; };\n"
2743 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2744 Local<v8::Object> o1 = v8::Object::New(isolate);
2745 Local<v8::Object> o2 = v8::Object::New(isolate);
2746 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2751 THREADED_TEST(GlobalProxyIdentityHash) {
2753 v8::Isolate* isolate = env->GetIsolate();
2754 v8::HandleScope scope(isolate);
2755 Handle<Object> global_proxy = env->Global();
2756 int hash1 = global_proxy->GetIdentityHash();
2757 // Hash should be retained after being detached.
2758 env->DetachGlobal();
2759 int hash2 = global_proxy->GetIdentityHash();
2760 CHECK_EQ(hash1, hash2);
2762 // Re-attach global proxy to a new context, hash should stay the same.
2763 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2764 int hash3 = global_proxy->GetIdentityHash();
2765 CHECK_EQ(hash1, hash3);
2770 THREADED_TEST(SymbolProperties) {
2771 i::FLAG_harmony_symbols = true;
2774 v8::Isolate* isolate = env->GetIsolate();
2775 v8::HandleScope scope(isolate);
2777 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2778 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2779 v8::Local<v8::Symbol> sym2 =
2780 v8::Symbol::New(isolate, v8_str("my-symbol"));
2782 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2784 // Check basic symbol functionality.
2785 CHECK(sym1->IsSymbol());
2786 CHECK(sym2->IsSymbol());
2787 CHECK(!obj->IsSymbol());
2789 CHECK(sym1->Equals(sym1));
2790 CHECK(sym2->Equals(sym2));
2791 CHECK(!sym1->Equals(sym2));
2792 CHECK(!sym2->Equals(sym1));
2793 CHECK(sym1->StrictEquals(sym1));
2794 CHECK(sym2->StrictEquals(sym2));
2795 CHECK(!sym1->StrictEquals(sym2));
2796 CHECK(!sym2->StrictEquals(sym1));
2798 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2800 v8::Local<v8::Value> sym_val = sym2;
2801 CHECK(sym_val->IsSymbol());
2802 CHECK(sym_val->Equals(sym2));
2803 CHECK(sym_val->StrictEquals(sym2));
2804 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2806 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2807 CHECK(sym_obj->IsSymbolObject());
2808 CHECK(!sym2->IsSymbolObject());
2809 CHECK(!obj->IsSymbolObject());
2810 CHECK(!sym_obj->Equals(sym2));
2811 CHECK(!sym_obj->StrictEquals(sym2));
2812 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2813 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2815 // Make sure delete of a non-existent symbol property works.
2816 CHECK(obj->Delete(sym1));
2817 CHECK(!obj->Has(sym1));
2819 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2820 CHECK(obj->Has(sym1));
2821 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2822 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2823 CHECK(obj->Has(sym1));
2824 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2825 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2827 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2828 int num_props = obj->GetPropertyNames()->Length();
2829 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2830 v8::Integer::New(isolate, 20)));
2831 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2832 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2836 // Add another property and delete it afterwards to force the object in
2838 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2839 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2840 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2841 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2842 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2844 CHECK(obj->Has(sym1));
2845 CHECK(obj->Has(sym2));
2846 CHECK(obj->Delete(sym2));
2847 CHECK(obj->Has(sym1));
2848 CHECK(!obj->Has(sym2));
2849 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2850 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2852 // Symbol properties are inherited.
2853 v8::Local<v8::Object> child = v8::Object::New(isolate);
2854 child->SetPrototype(obj);
2855 CHECK(child->Has(sym1));
2856 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2857 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2861 THREADED_TEST(PrivateProperties) {
2863 v8::Isolate* isolate = env->GetIsolate();
2864 v8::HandleScope scope(isolate);
2866 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2867 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2868 v8::Local<v8::Private> priv2 =
2869 v8::Private::New(isolate, v8_str("my-private"));
2871 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2873 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2875 // Make sure delete of a non-existent private symbol property works.
2876 CHECK(obj->DeletePrivate(priv1));
2877 CHECK(!obj->HasPrivate(priv1));
2879 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2880 CHECK(obj->HasPrivate(priv1));
2881 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2882 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2883 CHECK(obj->HasPrivate(priv1));
2884 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2886 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2887 int num_props = obj->GetPropertyNames()->Length();
2888 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2889 v8::Integer::New(isolate, 20)));
2890 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2891 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2893 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2895 // Add another property and delete it afterwards to force the object in
2897 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2898 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2899 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2900 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2901 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2903 CHECK(obj->HasPrivate(priv1));
2904 CHECK(obj->HasPrivate(priv2));
2905 CHECK(obj->DeletePrivate(priv2));
2906 CHECK(obj->HasPrivate(priv1));
2907 CHECK(!obj->HasPrivate(priv2));
2908 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2909 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2911 // Private properties are inherited (for the time being).
2912 v8::Local<v8::Object> child = v8::Object::New(isolate);
2913 child->SetPrototype(obj);
2914 CHECK(child->HasPrivate(priv1));
2915 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2916 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2920 THREADED_TEST(GlobalSymbols) {
2921 i::FLAG_harmony_symbols = true;
2924 v8::Isolate* isolate = env->GetIsolate();
2925 v8::HandleScope scope(isolate);
2927 v8::Local<String> name = v8_str("my-symbol");
2928 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2929 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2930 CHECK(glob2->SameValue(glob));
2932 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2933 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2934 CHECK(glob_api2->SameValue(glob_api));
2935 CHECK(!glob_api->SameValue(glob));
2937 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2938 CHECK(!sym->SameValue(glob));
2940 CompileRun("var sym2 = Symbol.for('my-symbol')");
2941 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2942 CHECK(sym2->SameValue(glob));
2943 CHECK(!sym2->SameValue(glob_api));
2947 THREADED_TEST(GlobalPrivates) {
2949 v8::Isolate* isolate = env->GetIsolate();
2950 v8::HandleScope scope(isolate);
2952 v8::Local<String> name = v8_str("my-private");
2953 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2954 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2955 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2957 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2958 CHECK(obj->HasPrivate(glob2));
2960 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2961 CHECK(!obj->HasPrivate(priv));
2963 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2964 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2965 CHECK(!obj->Has(intern));
2969 class ScopedArrayBufferContents {
2971 explicit ScopedArrayBufferContents(
2972 const v8::ArrayBuffer::Contents& contents)
2973 : contents_(contents) {}
2974 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2975 void* Data() const { return contents_.Data(); }
2976 size_t ByteLength() const { return contents_.ByteLength(); }
2978 const v8::ArrayBuffer::Contents contents_;
2981 template <typename T>
2982 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2983 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2984 for (int i = 0; i < value->InternalFieldCount(); i++) {
2985 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2990 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2992 v8::Isolate* isolate = env->GetIsolate();
2993 v8::HandleScope handle_scope(isolate);
2995 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2996 CheckInternalFieldsAreZero(ab);
2997 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2998 CHECK(!ab->IsExternal());
2999 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3001 ScopedArrayBufferContents ab_contents(ab->Externalize());
3002 CHECK(ab->IsExternal());
3004 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3005 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3006 ASSERT(data != NULL);
3007 env->Global()->Set(v8_str("ab"), ab);
3009 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3010 CHECK_EQ(1024, result->Int32Value());
3012 result = CompileRun("var u8 = new Uint8Array(ab);"
3016 CHECK_EQ(1024, result->Int32Value());
3017 CHECK_EQ(0xFF, data[0]);
3018 CHECK_EQ(0xAA, data[1]);
3021 result = CompileRun("u8[0] + u8[1]");
3022 CHECK_EQ(0xDD, result->Int32Value());
3026 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3028 v8::Isolate* isolate = env->GetIsolate();
3029 v8::HandleScope handle_scope(isolate);
3032 v8::Local<v8::Value> result =
3033 CompileRun("var ab1 = new ArrayBuffer(2);"
3034 "var u8_a = new Uint8Array(ab1);"
3036 "u8_a[1] = 0xFF; u8_a.buffer");
3037 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3038 CheckInternalFieldsAreZero(ab1);
3039 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3040 CHECK(!ab1->IsExternal());
3041 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3042 CHECK(ab1->IsExternal());
3044 result = CompileRun("ab1.byteLength");
3045 CHECK_EQ(2, result->Int32Value());
3046 result = CompileRun("u8_a[0]");
3047 CHECK_EQ(0xAA, result->Int32Value());
3048 result = CompileRun("u8_a[1]");
3049 CHECK_EQ(0xFF, result->Int32Value());
3050 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3053 CHECK_EQ(0xBB, result->Int32Value());
3054 result = CompileRun("u8_b[1]");
3055 CHECK_EQ(0xFF, result->Int32Value());
3057 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3058 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3059 CHECK_EQ(0xBB, ab1_data[0]);
3060 CHECK_EQ(0xFF, ab1_data[1]);
3063 result = CompileRun("u8_a[0] + u8_a[1]");
3064 CHECK_EQ(0xDD, result->Int32Value());
3068 THREADED_TEST(ArrayBuffer_External) {
3070 v8::Isolate* isolate = env->GetIsolate();
3071 v8::HandleScope handle_scope(isolate);
3073 i::ScopedVector<uint8_t> my_data(100);
3074 memset(my_data.start(), 0, 100);
3075 Local<v8::ArrayBuffer> ab3 =
3076 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3077 CheckInternalFieldsAreZero(ab3);
3078 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3079 CHECK(ab3->IsExternal());
3081 env->Global()->Set(v8_str("ab3"), ab3);
3083 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3084 CHECK_EQ(100, result->Int32Value());
3086 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3090 CHECK_EQ(100, result->Int32Value());
3091 CHECK_EQ(0xBB, my_data[0]);
3092 CHECK_EQ(0xCC, my_data[1]);
3095 result = CompileRun("u8_b[0] + u8_b[1]");
3096 CHECK_EQ(0xDD, result->Int32Value());
3100 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3101 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3102 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3106 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3107 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3108 CHECK_EQ(0, static_cast<int>(ta->Length()));
3109 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3113 static void CheckIsTypedArrayVarNeutered(const char* name) {
3114 i::ScopedVector<char> source(1024);
3115 i::OS::SNPrintF(source,
3116 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3118 CHECK(CompileRun(source.start())->IsTrue());
3119 v8::Handle<v8::TypedArray> ta =
3120 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3121 CheckIsNeutered(ta);
3125 template <typename TypedArray, int kElementSize>
3126 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3129 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3130 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3131 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3132 CHECK_EQ(length, static_cast<int>(ta->Length()));
3133 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3138 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3140 v8::Isolate* isolate = env->GetIsolate();
3141 v8::HandleScope handle_scope(isolate);
3143 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3145 v8::Handle<v8::Uint8Array> u8a =
3146 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3147 v8::Handle<v8::Uint8ClampedArray> u8c =
3148 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3149 v8::Handle<v8::Int8Array> i8a =
3150 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3152 v8::Handle<v8::Uint16Array> u16a =
3153 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3154 v8::Handle<v8::Int16Array> i16a =
3155 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3157 v8::Handle<v8::Uint32Array> u32a =
3158 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3159 v8::Handle<v8::Int32Array> i32a =
3160 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3162 v8::Handle<v8::Float32Array> f32a =
3163 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3164 v8::Handle<v8::Float64Array> f64a =
3165 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3167 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3168 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3169 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3170 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3172 ScopedArrayBufferContents contents(buffer->Externalize());
3174 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3175 CheckIsNeutered(u8a);
3176 CheckIsNeutered(u8c);
3177 CheckIsNeutered(i8a);
3178 CheckIsNeutered(u16a);
3179 CheckIsNeutered(i16a);
3180 CheckIsNeutered(u32a);
3181 CheckIsNeutered(i32a);
3182 CheckIsNeutered(f32a);
3183 CheckIsNeutered(f64a);
3184 CheckDataViewIsNeutered(dv);
3188 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3190 v8::Isolate* isolate = env->GetIsolate();
3191 v8::HandleScope handle_scope(isolate);
3194 "var ab = new ArrayBuffer(1024);"
3195 "var u8a = new Uint8Array(ab, 1, 1023);"
3196 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3197 "var i8a = new Int8Array(ab, 1, 1023);"
3198 "var u16a = new Uint16Array(ab, 2, 511);"
3199 "var i16a = new Int16Array(ab, 2, 511);"
3200 "var u32a = new Uint32Array(ab, 4, 255);"
3201 "var i32a = new Int32Array(ab, 4, 255);"
3202 "var f32a = new Float32Array(ab, 4, 255);"
3203 "var f64a = new Float64Array(ab, 8, 127);"
3204 "var dv = new DataView(ab, 1, 1023);");
3206 v8::Handle<v8::ArrayBuffer> ab =
3207 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3209 v8::Handle<v8::DataView> dv =
3210 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3212 ScopedArrayBufferContents contents(ab->Externalize());
3214 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3215 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3217 CheckIsTypedArrayVarNeutered("u8a");
3218 CheckIsTypedArrayVarNeutered("u8c");
3219 CheckIsTypedArrayVarNeutered("i8a");
3220 CheckIsTypedArrayVarNeutered("u16a");
3221 CheckIsTypedArrayVarNeutered("i16a");
3222 CheckIsTypedArrayVarNeutered("u32a");
3223 CheckIsTypedArrayVarNeutered("i32a");
3224 CheckIsTypedArrayVarNeutered("f32a");
3225 CheckIsTypedArrayVarNeutered("f64a");
3227 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3228 CheckDataViewIsNeutered(dv);
3233 THREADED_TEST(HiddenProperties) {
3235 v8::Isolate* isolate = env->GetIsolate();
3236 v8::HandleScope scope(isolate);
3238 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3239 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3240 v8::Local<v8::String> empty = v8_str("");
3241 v8::Local<v8::String> prop_name = v8_str("prop_name");
3243 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3245 // Make sure delete of a non-existent hidden value works
3246 CHECK(obj->DeleteHiddenValue(key));
3248 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3249 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3250 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3251 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3253 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3255 // Make sure we do not find the hidden property.
3256 CHECK(!obj->Has(empty));
3257 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3258 CHECK(obj->Get(empty)->IsUndefined());
3259 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3260 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3261 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3262 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3264 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3266 // Add another property and delete it afterwards to force the object in
3268 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3269 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3270 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3271 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3272 CHECK(obj->Delete(prop_name));
3273 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3275 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3277 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3278 CHECK(obj->GetHiddenValue(key).IsEmpty());
3280 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3281 CHECK(obj->DeleteHiddenValue(key));
3282 CHECK(obj->GetHiddenValue(key).IsEmpty());
3286 THREADED_TEST(Regress97784) {
3287 // Regression test for crbug.com/97784
3288 // Messing with the Object.prototype should not have effect on
3289 // hidden properties.
3291 v8::HandleScope scope(env->GetIsolate());
3293 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3294 v8::Local<v8::String> key = v8_str("hidden");
3297 "set_called = false;"
3298 "Object.defineProperty("
3299 " Object.prototype,"
3301 " {get: function() { return 45; },"
3302 " set: function() { set_called = true; }})");
3304 CHECK(obj->GetHiddenValue(key).IsEmpty());
3305 // Make sure that the getter and setter from Object.prototype is not invoked.
3306 // If it did we would have full access to the hidden properties in
3308 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3309 ExpectFalse("set_called");
3310 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3314 static bool interceptor_for_hidden_properties_called;
3315 static void InterceptorForHiddenProperties(
3316 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3317 interceptor_for_hidden_properties_called = true;
3321 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3322 LocalContext context;
3323 v8::Isolate* isolate = context->GetIsolate();
3324 v8::HandleScope scope(isolate);
3326 interceptor_for_hidden_properties_called = false;
3328 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3330 // Associate an interceptor with an object and start setting hidden values.
3331 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3332 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3333 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3334 Local<v8::Function> function = fun_templ->GetFunction();
3335 Local<v8::Object> obj = function->NewInstance();
3336 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3337 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3338 CHECK(!interceptor_for_hidden_properties_called);
3342 THREADED_TEST(External) {
3343 v8::HandleScope scope(CcTest::isolate());
3345 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3347 env->Global()->Set(v8_str("ext"), ext);
3348 Local<Value> reext_obj = CompileRun("this.ext");
3349 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3350 int* ptr = static_cast<int*>(reext->Value());
3355 // Make sure unaligned pointers are wrapped properly.
3356 char* data = i::StrDup("0123456789");
3357 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3358 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3359 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3360 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3362 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3363 CHECK_EQ('0', *char_ptr);
3364 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3365 CHECK_EQ('1', *char_ptr);
3366 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3367 CHECK_EQ('2', *char_ptr);
3368 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3369 CHECK_EQ('3', *char_ptr);
3370 i::DeleteArray(data);
3374 THREADED_TEST(GlobalHandle) {
3375 v8::Isolate* isolate = CcTest::isolate();
3376 v8::Persistent<String> global;
3378 v8::HandleScope scope(isolate);
3379 global.Reset(isolate, v8_str("str"));
3382 v8::HandleScope scope(isolate);
3383 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3387 v8::HandleScope scope(isolate);
3388 global.Reset(isolate, v8_str("str"));
3391 v8::HandleScope scope(isolate);
3392 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3398 THREADED_TEST(ResettingGlobalHandle) {
3399 v8::Isolate* isolate = CcTest::isolate();
3400 v8::Persistent<String> global;
3402 v8::HandleScope scope(isolate);
3403 global.Reset(isolate, v8_str("str"));
3405 v8::internal::GlobalHandles* global_handles =
3406 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3407 int initial_handle_count = global_handles->global_handles_count();
3409 v8::HandleScope scope(isolate);
3410 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3413 v8::HandleScope scope(isolate);
3414 global.Reset(isolate, v8_str("longer"));
3416 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3418 v8::HandleScope scope(isolate);
3419 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3422 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3426 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3427 v8::Isolate* isolate = CcTest::isolate();
3428 v8::Persistent<String> global;
3430 v8::HandleScope scope(isolate);
3431 global.Reset(isolate, v8_str("str"));
3433 v8::internal::GlobalHandles* global_handles =
3434 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3435 int initial_handle_count = global_handles->global_handles_count();
3437 v8::HandleScope scope(isolate);
3438 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3441 v8::HandleScope scope(isolate);
3442 Local<String> empty;
3443 global.Reset(isolate, empty);
3445 CHECK(global.IsEmpty());
3446 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3451 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3452 return unique.Pass();
3457 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3458 const v8::Persistent<T> & global) {
3459 v8::UniquePersistent<String> unique(isolate, global);
3460 return unique.Pass();
3464 THREADED_TEST(UniquePersistent) {
3465 v8::Isolate* isolate = CcTest::isolate();
3466 v8::Persistent<String> global;
3468 v8::HandleScope scope(isolate);
3469 global.Reset(isolate, v8_str("str"));
3471 v8::internal::GlobalHandles* global_handles =
3472 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3473 int initial_handle_count = global_handles->global_handles_count();
3475 v8::UniquePersistent<String> unique(isolate, global);
3476 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3477 // Test assignment via Pass
3479 v8::UniquePersistent<String> copy = unique.Pass();
3480 CHECK(unique.IsEmpty());
3481 CHECK(copy == global);
3482 CHECK_EQ(initial_handle_count + 1,
3483 global_handles->global_handles_count());
3484 unique = copy.Pass();
3486 // Test ctor via Pass
3488 v8::UniquePersistent<String> copy(unique.Pass());
3489 CHECK(unique.IsEmpty());
3490 CHECK(copy == global);
3491 CHECK_EQ(initial_handle_count + 1,
3492 global_handles->global_handles_count());
3493 unique = copy.Pass();
3495 // Test pass through function call
3497 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3498 CHECK(unique.IsEmpty());
3499 CHECK(copy == global);
3500 CHECK_EQ(initial_handle_count + 1,
3501 global_handles->global_handles_count());
3502 unique = copy.Pass();
3504 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3506 // Test pass from function call
3508 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3509 CHECK(unique == global);
3510 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3512 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3517 template<typename K, typename V>
3518 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3520 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3522 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3523 struct WeakCallbackDataType {
3527 static WeakCallbackDataType* WeakCallbackParameter(
3528 MapType* map, const K& key, Local<V> value) {
3529 WeakCallbackDataType* data = new WeakCallbackDataType;
3534 static MapType* MapFromWeakCallbackData(
3535 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3536 return data.GetParameter()->map;
3538 static K KeyFromWeakCallbackData(
3539 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3540 return data.GetParameter()->key;
3542 static void DisposeCallbackData(WeakCallbackDataType* data) {
3545 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3550 template<typename Map>
3551 static void TestPersistentValueMap() {
3553 v8::Isolate* isolate = env->GetIsolate();
3555 v8::internal::GlobalHandles* global_handles =
3556 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3557 int initial_handle_count = global_handles->global_handles_count();
3558 CHECK_EQ(0, static_cast<int>(map.Size()));
3560 HandleScope scope(isolate);
3561 Local<v8::Object> obj = map.Get(7);
3562 CHECK(obj.IsEmpty());
3563 Local<v8::Object> expected = v8::Object::New(isolate);
3564 map.Set(7, expected);
3565 CHECK_EQ(1, static_cast<int>(map.Size()));
3567 CHECK_EQ(expected, obj);
3569 typename Map::PersistentValueReference ref = map.GetReference(7);
3570 CHECK_EQ(expected, ref.NewLocal(isolate));
3572 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3573 CHECK_EQ(0, static_cast<int>(map.Size()));
3574 CHECK(expected == removed);
3575 removed = map.Remove(7);
3576 CHECK(removed.IsEmpty());
3577 map.Set(8, expected);
3578 CHECK_EQ(1, static_cast<int>(map.Size()));
3579 map.Set(8, expected);
3580 CHECK_EQ(1, static_cast<int>(map.Size()));
3582 typename Map::PersistentValueReference ref;
3583 Local<v8::Object> expected2 = v8::Object::New(isolate);
3584 removed = map.Set(8,
3585 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3586 CHECK_EQ(1, static_cast<int>(map.Size()));
3587 CHECK(expected == removed);
3588 CHECK_EQ(expected2, ref.NewLocal(isolate));
3591 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3593 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3594 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3598 CHECK_EQ(0, static_cast<int>(map.Size()));
3599 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3603 TEST(PersistentValueMap) {
3604 // Default case, w/o weak callbacks:
3605 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3607 // Custom traits with weak callbacks:
3608 typedef v8::PersistentValueMap<int, v8::Object,
3609 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3610 TestPersistentValueMap<WeakPersistentValueMap>();
3614 TEST(PersistentValueVector) {
3616 v8::Isolate* isolate = env->GetIsolate();
3617 v8::internal::GlobalHandles* global_handles =
3618 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3619 int handle_count = global_handles->global_handles_count();
3620 HandleScope scope(isolate);
3622 v8::PersistentValueVector<v8::Object> vector(isolate);
3624 Local<v8::Object> obj1 = v8::Object::New(isolate);
3625 Local<v8::Object> obj2 = v8::Object::New(isolate);
3626 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3628 CHECK(vector.IsEmpty());
3629 CHECK_EQ(0, static_cast<int>(vector.Size()));
3631 vector.ReserveCapacity(3);
3632 CHECK(vector.IsEmpty());
3634 vector.Append(obj1);
3635 vector.Append(obj2);
3636 vector.Append(obj1);
3637 vector.Append(obj3.Pass());
3638 vector.Append(obj1);
3640 CHECK(!vector.IsEmpty());
3641 CHECK_EQ(5, static_cast<int>(vector.Size()));
3642 CHECK(obj3.IsEmpty());
3643 CHECK_EQ(obj1, vector.Get(0));
3644 CHECK_EQ(obj1, vector.Get(2));
3645 CHECK_EQ(obj1, vector.Get(4));
3646 CHECK_EQ(obj2, vector.Get(1));
3648 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3651 CHECK(vector.IsEmpty());
3652 CHECK_EQ(0, static_cast<int>(vector.Size()));
3653 CHECK_EQ(handle_count, global_handles->global_handles_count());
3657 THREADED_TEST(GlobalHandleUpcast) {
3658 v8::Isolate* isolate = CcTest::isolate();
3659 v8::HandleScope scope(isolate);
3660 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3661 v8::Persistent<String> global_string(isolate, local);
3662 v8::Persistent<Value>& global_value =
3663 v8::Persistent<Value>::Cast(global_string);
3664 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3665 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3666 global_string.Reset();
3670 THREADED_TEST(HandleEquality) {
3671 v8::Isolate* isolate = CcTest::isolate();
3672 v8::Persistent<String> global1;
3673 v8::Persistent<String> global2;
3675 v8::HandleScope scope(isolate);
3676 global1.Reset(isolate, v8_str("str"));
3677 global2.Reset(isolate, v8_str("str2"));
3679 CHECK_EQ(global1 == global1, true);
3680 CHECK_EQ(global1 != global1, false);
3682 v8::HandleScope scope(isolate);
3683 Local<String> local1 = Local<String>::New(isolate, global1);
3684 Local<String> local2 = Local<String>::New(isolate, global2);
3686 CHECK_EQ(global1 == local1, true);
3687 CHECK_EQ(global1 != local1, false);
3688 CHECK_EQ(local1 == global1, true);
3689 CHECK_EQ(local1 != global1, false);
3691 CHECK_EQ(global1 == local2, false);
3692 CHECK_EQ(global1 != local2, true);
3693 CHECK_EQ(local2 == global1, false);
3694 CHECK_EQ(local2 != global1, true);
3696 CHECK_EQ(local1 == local2, false);
3697 CHECK_EQ(local1 != local2, true);
3699 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3700 CHECK_EQ(local1 == anotherLocal1, true);
3701 CHECK_EQ(local1 != anotherLocal1, false);
3708 THREADED_TEST(LocalHandle) {
3709 v8::HandleScope scope(CcTest::isolate());
3710 v8::Local<String> local =
3711 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3712 CHECK_EQ(local->Length(), 3);
3716 class WeakCallCounter {
3718 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3719 int id() { return id_; }
3720 void increment() { number_of_weak_calls_++; }
3721 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3724 int number_of_weak_calls_;
3728 template<typename T>
3729 struct WeakCallCounterAndPersistent {
3730 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3731 : counter(counter) {}
3732 WeakCallCounter* counter;
3733 v8::Persistent<T> handle;
3737 template <typename T>
3738 static void WeakPointerCallback(
3739 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3740 CHECK_EQ(1234, data.GetParameter()->counter->id());
3741 data.GetParameter()->counter->increment();
3742 data.GetParameter()->handle.Reset();
3746 template<typename T>
3747 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3748 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3752 THREADED_TEST(ApiObjectGroups) {
3754 v8::Isolate* iso = env->GetIsolate();
3755 HandleScope scope(iso);
3757 WeakCallCounter counter(1234);
3759 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3760 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3761 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3762 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3763 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3764 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3767 HandleScope scope(iso);
3768 g1s1.handle.Reset(iso, Object::New(iso));
3769 g1s2.handle.Reset(iso, Object::New(iso));
3770 g1c1.handle.Reset(iso, Object::New(iso));
3771 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3772 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3773 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3775 g2s1.handle.Reset(iso, Object::New(iso));
3776 g2s2.handle.Reset(iso, Object::New(iso));
3777 g2c1.handle.Reset(iso, Object::New(iso));
3778 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3779 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3780 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3783 WeakCallCounterAndPersistent<Value> root(&counter);
3784 root.handle.Reset(iso, g1s1.handle); // make a root.
3786 // Connect group 1 and 2, make a cycle.
3788 HandleScope scope(iso);
3789 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3790 Set(0, Local<Value>::New(iso, g2s2.handle)));
3791 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3792 Set(0, Local<Value>::New(iso, g1s1.handle)));
3796 UniqueId id1 = MakeUniqueId(g1s1.handle);
3797 UniqueId id2 = MakeUniqueId(g2s2.handle);
3798 iso->SetObjectGroupId(g1s1.handle, id1);
3799 iso->SetObjectGroupId(g1s2.handle, id1);
3800 iso->SetReferenceFromGroup(id1, g1c1.handle);
3801 iso->SetObjectGroupId(g2s1.handle, id2);
3802 iso->SetObjectGroupId(g2s2.handle, id2);
3803 iso->SetReferenceFromGroup(id2, g2c1.handle);
3805 // Do a single full GC, ensure incremental marking is stopped.
3806 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3808 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3810 // All object should be alive.
3811 CHECK_EQ(0, counter.NumberOfWeakCalls());
3814 root.handle.SetWeak(&root, &WeakPointerCallback);
3815 // But make children strong roots---all the objects (except for children)
3816 // should be collectable now.
3817 g1c1.handle.ClearWeak();
3818 g2c1.handle.ClearWeak();
3820 // Groups are deleted, rebuild groups.
3822 UniqueId id1 = MakeUniqueId(g1s1.handle);
3823 UniqueId id2 = MakeUniqueId(g2s2.handle);
3824 iso->SetObjectGroupId(g1s1.handle, id1);
3825 iso->SetObjectGroupId(g1s2.handle, id1);
3826 iso->SetReferenceFromGroup(id1, g1c1.handle);
3827 iso->SetObjectGroupId(g2s1.handle, id2);
3828 iso->SetObjectGroupId(g2s2.handle, id2);
3829 iso->SetReferenceFromGroup(id2, g2c1.handle);
3832 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3834 // All objects should be gone. 5 global handles in total.
3835 CHECK_EQ(5, counter.NumberOfWeakCalls());
3837 // And now make children weak again and collect them.
3838 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3839 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3841 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3842 CHECK_EQ(7, counter.NumberOfWeakCalls());
3846 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3848 v8::Isolate* iso = env->GetIsolate();
3849 HandleScope scope(iso);
3851 WeakCallCounter counter(1234);
3853 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3854 WeakCallCounterAndPersistent<String> g1s2(&counter);
3855 WeakCallCounterAndPersistent<String> g1c1(&counter);
3856 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3857 WeakCallCounterAndPersistent<String> g2s2(&counter);
3858 WeakCallCounterAndPersistent<String> g2c1(&counter);
3861 HandleScope scope(iso);
3862 g1s1.handle.Reset(iso, Object::New(iso));
3863 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3864 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3865 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3866 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3867 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3869 g2s1.handle.Reset(iso, Object::New(iso));
3870 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3871 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3872 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3873 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3874 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3877 WeakCallCounterAndPersistent<Value> root(&counter);
3878 root.handle.Reset(iso, g1s1.handle); // make a root.
3880 // Connect group 1 and 2, make a cycle.
3882 HandleScope scope(iso);
3883 CHECK(Local<Object>::New(iso, g1s1.handle)
3884 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3885 CHECK(Local<Object>::New(iso, g2s1.handle)
3886 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3890 UniqueId id1 = MakeUniqueId(g1s1.handle);
3891 UniqueId id2 = MakeUniqueId(g2s2.handle);
3892 iso->SetObjectGroupId(g1s1.handle, id1);
3893 iso->SetObjectGroupId(g1s2.handle, id1);
3894 iso->SetReference(g1s1.handle, g1c1.handle);
3895 iso->SetObjectGroupId(g2s1.handle, id2);
3896 iso->SetObjectGroupId(g2s2.handle, id2);
3897 iso->SetReferenceFromGroup(id2, g2c1.handle);
3899 // Do a single full GC, ensure incremental marking is stopped.
3900 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3902 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3904 // All object should be alive.
3905 CHECK_EQ(0, counter.NumberOfWeakCalls());
3908 root.handle.SetWeak(&root, &WeakPointerCallback);
3909 // But make children strong roots---all the objects (except for children)
3910 // should be collectable now.
3911 g1c1.handle.ClearWeak();
3912 g2c1.handle.ClearWeak();
3914 // Groups are deleted, rebuild groups.
3916 UniqueId id1 = MakeUniqueId(g1s1.handle);
3917 UniqueId id2 = MakeUniqueId(g2s2.handle);
3918 iso->SetObjectGroupId(g1s1.handle, id1);
3919 iso->SetObjectGroupId(g1s2.handle, id1);
3920 iso->SetReference(g1s1.handle, g1c1.handle);
3921 iso->SetObjectGroupId(g2s1.handle, id2);
3922 iso->SetObjectGroupId(g2s2.handle, id2);
3923 iso->SetReferenceFromGroup(id2, g2c1.handle);
3926 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3928 // All objects should be gone. 5 global handles in total.
3929 CHECK_EQ(5, counter.NumberOfWeakCalls());
3931 // And now make children weak again and collect them.
3932 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3933 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3935 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3936 CHECK_EQ(7, counter.NumberOfWeakCalls());
3940 THREADED_TEST(ApiObjectGroupsCycle) {
3942 v8::Isolate* iso = env->GetIsolate();
3943 HandleScope scope(iso);
3945 WeakCallCounter counter(1234);
3947 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3948 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3949 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3950 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3951 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3952 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3953 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3954 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3957 HandleScope scope(iso);
3958 g1s1.handle.Reset(iso, Object::New(iso));
3959 g1s2.handle.Reset(iso, Object::New(iso));
3960 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3961 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3962 CHECK(g1s1.handle.IsWeak());
3963 CHECK(g1s2.handle.IsWeak());
3965 g2s1.handle.Reset(iso, Object::New(iso));
3966 g2s2.handle.Reset(iso, Object::New(iso));
3967 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3968 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3969 CHECK(g2s1.handle.IsWeak());
3970 CHECK(g2s2.handle.IsWeak());
3972 g3s1.handle.Reset(iso, Object::New(iso));
3973 g3s2.handle.Reset(iso, Object::New(iso));
3974 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3975 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3976 CHECK(g3s1.handle.IsWeak());
3977 CHECK(g3s2.handle.IsWeak());
3979 g4s1.handle.Reset(iso, Object::New(iso));
3980 g4s2.handle.Reset(iso, Object::New(iso));
3981 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3982 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3983 CHECK(g4s1.handle.IsWeak());
3984 CHECK(g4s2.handle.IsWeak());
3987 WeakCallCounterAndPersistent<Value> root(&counter);
3988 root.handle.Reset(iso, g1s1.handle); // make a root.
3990 // Connect groups. We're building the following cycle:
3991 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3994 UniqueId id1 = MakeUniqueId(g1s1.handle);
3995 UniqueId id2 = MakeUniqueId(g2s1.handle);
3996 UniqueId id3 = MakeUniqueId(g3s1.handle);
3997 UniqueId id4 = MakeUniqueId(g4s1.handle);
3998 iso->SetObjectGroupId(g1s1.handle, id1);
3999 iso->SetObjectGroupId(g1s2.handle, id1);
4000 iso->SetReferenceFromGroup(id1, g2s1.handle);
4001 iso->SetObjectGroupId(g2s1.handle, id2);
4002 iso->SetObjectGroupId(g2s2.handle, id2);
4003 iso->SetReferenceFromGroup(id2, g3s1.handle);
4004 iso->SetObjectGroupId(g3s1.handle, id3);
4005 iso->SetObjectGroupId(g3s2.handle, id3);
4006 iso->SetReferenceFromGroup(id3, g4s1.handle);
4007 iso->SetObjectGroupId(g4s1.handle, id4);
4008 iso->SetObjectGroupId(g4s2.handle, id4);
4009 iso->SetReferenceFromGroup(id4, g1s1.handle);
4011 // Do a single full GC
4012 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4014 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4016 // All object should be alive.
4017 CHECK_EQ(0, counter.NumberOfWeakCalls());
4020 root.handle.SetWeak(&root, &WeakPointerCallback);
4022 // Groups are deleted, rebuild groups.
4024 UniqueId id1 = MakeUniqueId(g1s1.handle);
4025 UniqueId id2 = MakeUniqueId(g2s1.handle);
4026 UniqueId id3 = MakeUniqueId(g3s1.handle);
4027 UniqueId id4 = MakeUniqueId(g4s1.handle);
4028 iso->SetObjectGroupId(g1s1.handle, id1);
4029 iso->SetObjectGroupId(g1s2.handle, id1);
4030 iso->SetReferenceFromGroup(id1, g2s1.handle);
4031 iso->SetObjectGroupId(g2s1.handle, id2);
4032 iso->SetObjectGroupId(g2s2.handle, id2);
4033 iso->SetReferenceFromGroup(id2, g3s1.handle);
4034 iso->SetObjectGroupId(g3s1.handle, id3);
4035 iso->SetObjectGroupId(g3s2.handle, id3);
4036 iso->SetReferenceFromGroup(id3, g4s1.handle);
4037 iso->SetObjectGroupId(g4s1.handle, id4);
4038 iso->SetObjectGroupId(g4s2.handle, id4);
4039 iso->SetReferenceFromGroup(id4, g1s1.handle);
4042 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4044 // All objects should be gone. 9 global handles in total.
4045 CHECK_EQ(9, counter.NumberOfWeakCalls());
4049 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4050 // on the buildbots, so was made non-threaded for the time being.
4051 TEST(ApiObjectGroupsCycleForScavenger) {
4052 i::FLAG_stress_compaction = false;
4053 i::FLAG_gc_global = false;
4055 v8::Isolate* iso = env->GetIsolate();
4056 HandleScope scope(iso);
4058 WeakCallCounter counter(1234);
4060 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4061 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4062 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4063 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4064 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4065 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4068 HandleScope scope(iso);
4069 g1s1.handle.Reset(iso, Object::New(iso));
4070 g1s2.handle.Reset(iso, Object::New(iso));
4071 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4072 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4074 g2s1.handle.Reset(iso, Object::New(iso));
4075 g2s2.handle.Reset(iso, Object::New(iso));
4076 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4077 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4079 g3s1.handle.Reset(iso, Object::New(iso));
4080 g3s2.handle.Reset(iso, Object::New(iso));
4081 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4082 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4086 WeakCallCounterAndPersistent<Value> root(&counter);
4087 root.handle.Reset(iso, g1s1.handle);
4088 root.handle.MarkPartiallyDependent();
4090 // Connect groups. We're building the following cycle:
4091 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4094 HandleScope handle_scope(iso);
4095 g1s1.handle.MarkPartiallyDependent();
4096 g1s2.handle.MarkPartiallyDependent();
4097 g2s1.handle.MarkPartiallyDependent();
4098 g2s2.handle.MarkPartiallyDependent();
4099 g3s1.handle.MarkPartiallyDependent();
4100 g3s2.handle.MarkPartiallyDependent();
4101 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4102 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4103 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4104 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4105 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4106 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4107 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4108 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4109 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4110 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4111 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4112 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4115 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4117 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4119 // All objects should be alive.
4120 CHECK_EQ(0, counter.NumberOfWeakCalls());
4123 root.handle.SetWeak(&root, &WeakPointerCallback);
4124 root.handle.MarkPartiallyDependent();
4126 // Groups are deleted, rebuild groups.
4128 HandleScope handle_scope(iso);
4129 g1s1.handle.MarkPartiallyDependent();
4130 g1s2.handle.MarkPartiallyDependent();
4131 g2s1.handle.MarkPartiallyDependent();
4132 g2s2.handle.MarkPartiallyDependent();
4133 g3s1.handle.MarkPartiallyDependent();
4134 g3s2.handle.MarkPartiallyDependent();
4135 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4136 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4137 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4138 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4139 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4140 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4141 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4142 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4143 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4144 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4145 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4146 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4149 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4151 // All objects should be gone. 7 global handles in total.
4152 CHECK_EQ(7, counter.NumberOfWeakCalls());
4156 THREADED_TEST(ScriptException) {
4158 v8::HandleScope scope(env->GetIsolate());
4159 Local<Script> script = v8_compile("throw 'panama!';");
4160 v8::TryCatch try_catch;
4161 Local<Value> result = script->Run();
4162 CHECK(result.IsEmpty());
4163 CHECK(try_catch.HasCaught());
4164 String::Utf8Value exception_value(try_catch.Exception());
4165 CHECK_EQ(*exception_value, "panama!");
4169 TEST(TryCatchCustomException) {
4171 v8::HandleScope scope(env->GetIsolate());
4172 v8::TryCatch try_catch;
4173 CompileRun("function CustomError() { this.a = 'b'; }"
4174 "(function f() { throw new CustomError(); })();");
4175 CHECK(try_catch.HasCaught());
4176 CHECK(try_catch.Exception()->ToObject()->
4177 Get(v8_str("a"))->Equals(v8_str("b")));
4181 bool message_received;
4184 static void check_message_0(v8::Handle<v8::Message> message,
4185 v8::Handle<Value> data) {
4186 CHECK_EQ(5.76, data->NumberValue());
4187 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4188 CHECK(!message->IsSharedCrossOrigin());
4189 message_received = true;
4193 THREADED_TEST(MessageHandler0) {
4194 message_received = false;
4195 v8::HandleScope scope(CcTest::isolate());
4196 CHECK(!message_received);
4197 LocalContext context;
4198 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4199 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4201 CHECK(message_received);
4202 // clear out the message listener
4203 v8::V8::RemoveMessageListeners(check_message_0);
4207 static void check_message_1(v8::Handle<v8::Message> message,
4208 v8::Handle<Value> data) {
4209 CHECK(data->IsNumber());
4210 CHECK_EQ(1337, data->Int32Value());
4211 CHECK(!message->IsSharedCrossOrigin());
4212 message_received = true;
4216 TEST(MessageHandler1) {
4217 message_received = false;
4218 v8::HandleScope scope(CcTest::isolate());
4219 CHECK(!message_received);
4220 v8::V8::AddMessageListener(check_message_1);
4221 LocalContext context;
4222 CompileRun("throw 1337;");
4223 CHECK(message_received);
4224 // clear out the message listener
4225 v8::V8::RemoveMessageListeners(check_message_1);
4229 static void check_message_2(v8::Handle<v8::Message> message,
4230 v8::Handle<Value> data) {
4231 LocalContext context;
4232 CHECK(data->IsObject());
4233 v8::Local<v8::Value> hidden_property =
4234 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4235 CHECK(v8_str("hidden value")->Equals(hidden_property));
4236 CHECK(!message->IsSharedCrossOrigin());
4237 message_received = true;
4241 TEST(MessageHandler2) {
4242 message_received = false;
4243 v8::HandleScope scope(CcTest::isolate());
4244 CHECK(!message_received);
4245 v8::V8::AddMessageListener(check_message_2);
4246 LocalContext context;
4247 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4248 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4249 v8_str("hidden value"));
4250 context->Global()->Set(v8_str("error"), error);
4251 CompileRun("throw error;");
4252 CHECK(message_received);
4253 // clear out the message listener
4254 v8::V8::RemoveMessageListeners(check_message_2);
4258 static void check_message_3(v8::Handle<v8::Message> message,
4259 v8::Handle<Value> data) {
4260 CHECK(message->IsSharedCrossOrigin());
4261 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4262 message_received = true;
4266 TEST(MessageHandler3) {
4267 message_received = false;
4268 v8::Isolate* isolate = CcTest::isolate();
4269 v8::HandleScope scope(isolate);
4270 CHECK(!message_received);
4271 v8::V8::AddMessageListener(check_message_3);
4272 LocalContext context;
4273 v8::ScriptOrigin origin =
4274 v8::ScriptOrigin(v8_str("6.75"),
4275 v8::Integer::New(isolate, 1),
4276 v8::Integer::New(isolate, 2),
4278 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4281 CHECK(message_received);
4282 // clear out the message listener
4283 v8::V8::RemoveMessageListeners(check_message_3);
4287 static void check_message_4(v8::Handle<v8::Message> message,
4288 v8::Handle<Value> data) {
4289 CHECK(!message->IsSharedCrossOrigin());
4290 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4291 message_received = true;
4295 TEST(MessageHandler4) {
4296 message_received = false;
4297 v8::Isolate* isolate = CcTest::isolate();
4298 v8::HandleScope scope(isolate);
4299 CHECK(!message_received);
4300 v8::V8::AddMessageListener(check_message_4);
4301 LocalContext context;
4302 v8::ScriptOrigin origin =
4303 v8::ScriptOrigin(v8_str("6.75"),
4304 v8::Integer::New(isolate, 1),
4305 v8::Integer::New(isolate, 2),
4306 v8::False(isolate));
4307 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4310 CHECK(message_received);
4311 // clear out the message listener
4312 v8::V8::RemoveMessageListeners(check_message_4);
4316 static void check_message_5a(v8::Handle<v8::Message> message,
4317 v8::Handle<Value> data) {
4318 CHECK(message->IsSharedCrossOrigin());
4319 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4320 message_received = true;
4324 static void check_message_5b(v8::Handle<v8::Message> message,
4325 v8::Handle<Value> data) {
4326 CHECK(!message->IsSharedCrossOrigin());
4327 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4328 message_received = true;
4332 TEST(MessageHandler5) {
4333 message_received = false;
4334 v8::Isolate* isolate = CcTest::isolate();
4335 v8::HandleScope scope(isolate);
4336 CHECK(!message_received);
4337 v8::V8::AddMessageListener(check_message_5a);
4338 LocalContext context;
4339 v8::ScriptOrigin origin =
4340 v8::ScriptOrigin(v8_str("6.75"),
4341 v8::Integer::New(isolate, 1),
4342 v8::Integer::New(isolate, 2),
4344 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4347 CHECK(message_received);
4348 // clear out the message listener
4349 v8::V8::RemoveMessageListeners(check_message_5a);
4351 message_received = false;
4352 v8::V8::AddMessageListener(check_message_5b);
4354 v8::ScriptOrigin(v8_str("6.75"),
4355 v8::Integer::New(isolate, 1),
4356 v8::Integer::New(isolate, 2),
4357 v8::False(isolate));
4358 script = Script::Compile(v8_str("throw 'error'"),
4361 CHECK(message_received);
4362 // clear out the message listener
4363 v8::V8::RemoveMessageListeners(check_message_5b);
4367 THREADED_TEST(GetSetProperty) {
4368 LocalContext context;
4369 v8::Isolate* isolate = context->GetIsolate();
4370 v8::HandleScope scope(isolate);
4371 context->Global()->Set(v8_str("foo"), v8_num(14));
4372 context->Global()->Set(v8_str("12"), v8_num(92));
4373 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4374 context->Global()->Set(v8_num(13), v8_num(56));
4375 Local<Value> foo = CompileRun("this.foo");
4376 CHECK_EQ(14, foo->Int32Value());
4377 Local<Value> twelve = CompileRun("this[12]");
4378 CHECK_EQ(92, twelve->Int32Value());
4379 Local<Value> sixteen = CompileRun("this[16]");
4380 CHECK_EQ(32, sixteen->Int32Value());
4381 Local<Value> thirteen = CompileRun("this[13]");
4382 CHECK_EQ(56, thirteen->Int32Value());
4384 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4385 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4386 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4388 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4389 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4390 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4392 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4393 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4394 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4398 THREADED_TEST(PropertyAttributes) {
4399 LocalContext context;
4400 v8::HandleScope scope(context->GetIsolate());
4402 Local<String> prop = v8_str("none");
4403 context->Global()->Set(prop, v8_num(7));
4404 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4406 prop = v8_str("read_only");
4407 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4408 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4409 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4410 CompileRun("read_only = 9");
4411 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4412 context->Global()->Set(prop, v8_num(10));
4413 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4415 prop = v8_str("dont_delete");
4416 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4417 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4418 CompileRun("delete dont_delete");
4419 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4420 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4422 prop = v8_str("dont_enum");
4423 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4424 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4426 prop = v8_str("absent");
4427 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4428 Local<Value> fake_prop = v8_num(1);
4429 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4432 Local<Value> exception =
4433 CompileRun("({ toString: function() { throw 'exception';} })");
4434 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4435 CHECK(try_catch.HasCaught());
4436 String::Utf8Value exception_value(try_catch.Exception());
4437 CHECK_EQ("exception", *exception_value);
4442 THREADED_TEST(Array) {
4443 LocalContext context;
4444 v8::HandleScope scope(context->GetIsolate());
4445 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4446 CHECK_EQ(0, array->Length());
4447 CHECK(array->Get(0)->IsUndefined());
4448 CHECK(!array->Has(0));
4449 CHECK(array->Get(100)->IsUndefined());
4450 CHECK(!array->Has(100));
4451 array->Set(2, v8_num(7));
4452 CHECK_EQ(3, array->Length());
4453 CHECK(!array->Has(0));
4454 CHECK(!array->Has(1));
4455 CHECK(array->Has(2));
4456 CHECK_EQ(7, array->Get(2)->Int32Value());
4457 Local<Value> obj = CompileRun("[1, 2, 3]");
4458 Local<v8::Array> arr = obj.As<v8::Array>();
4459 CHECK_EQ(3, arr->Length());
4460 CHECK_EQ(1, arr->Get(0)->Int32Value());
4461 CHECK_EQ(2, arr->Get(1)->Int32Value());
4462 CHECK_EQ(3, arr->Get(2)->Int32Value());
4463 array = v8::Array::New(context->GetIsolate(), 27);
4464 CHECK_EQ(27, array->Length());
4465 array = v8::Array::New(context->GetIsolate(), -27);
4466 CHECK_EQ(0, array->Length());
4470 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4471 v8::EscapableHandleScope scope(args.GetIsolate());
4472 ApiTestFuzzer::Fuzz();
4473 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4474 for (int i = 0; i < args.Length(); i++)
4475 result->Set(i, args[i]);
4476 args.GetReturnValue().Set(scope.Escape(result));
4480 THREADED_TEST(Vector) {
4481 v8::Isolate* isolate = CcTest::isolate();
4482 v8::HandleScope scope(isolate);
4483 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4484 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4485 LocalContext context(0, global);
4487 const char* fun = "f()";
4488 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4489 CHECK_EQ(0, a0->Length());
4491 const char* fun2 = "f(11)";
4492 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4493 CHECK_EQ(1, a1->Length());
4494 CHECK_EQ(11, a1->Get(0)->Int32Value());
4496 const char* fun3 = "f(12, 13)";
4497 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4498 CHECK_EQ(2, a2->Length());
4499 CHECK_EQ(12, a2->Get(0)->Int32Value());
4500 CHECK_EQ(13, a2->Get(1)->Int32Value());
4502 const char* fun4 = "f(14, 15, 16)";
4503 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4504 CHECK_EQ(3, a3->Length());
4505 CHECK_EQ(14, a3->Get(0)->Int32Value());
4506 CHECK_EQ(15, a3->Get(1)->Int32Value());
4507 CHECK_EQ(16, a3->Get(2)->Int32Value());
4509 const char* fun5 = "f(17, 18, 19, 20)";
4510 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4511 CHECK_EQ(4, a4->Length());
4512 CHECK_EQ(17, a4->Get(0)->Int32Value());
4513 CHECK_EQ(18, a4->Get(1)->Int32Value());
4514 CHECK_EQ(19, a4->Get(2)->Int32Value());
4515 CHECK_EQ(20, a4->Get(3)->Int32Value());
4519 THREADED_TEST(FunctionCall) {
4520 LocalContext context;
4521 v8::Isolate* isolate = context->GetIsolate();
4522 v8::HandleScope scope(isolate);
4526 " for (var i = 0; i < arguments.length; i++) {"
4527 " result.push(arguments[i]);"
4531 "function ReturnThisSloppy() {"
4534 "function ReturnThisStrict() {"
4538 Local<Function> Foo =
4539 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4540 Local<Function> ReturnThisSloppy =
4541 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4542 Local<Function> ReturnThisStrict =
4543 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4545 v8::Handle<Value>* args0 = NULL;
4546 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4547 CHECK_EQ(0, a0->Length());
4549 v8::Handle<Value> args1[] = { v8_num(1.1) };
4550 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4551 CHECK_EQ(1, a1->Length());
4552 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4554 v8::Handle<Value> args2[] = { v8_num(2.2),
4556 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4557 CHECK_EQ(2, a2->Length());
4558 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4559 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4561 v8::Handle<Value> args3[] = { v8_num(4.4),
4564 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4565 CHECK_EQ(3, a3->Length());
4566 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4567 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4568 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4570 v8::Handle<Value> args4[] = { v8_num(7.7),
4574 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4575 CHECK_EQ(4, a4->Length());
4576 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4577 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4578 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4579 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4581 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4582 CHECK(r1->StrictEquals(context->Global()));
4583 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4584 CHECK(r2->StrictEquals(context->Global()));
4585 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4586 CHECK(r3->IsNumberObject());
4587 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4588 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4589 CHECK(r4->IsStringObject());
4590 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4591 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4592 CHECK(r5->IsBooleanObject());
4593 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4595 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4596 CHECK(r6->IsUndefined());
4597 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4598 CHECK(r7->IsNull());
4599 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4600 CHECK(r8->StrictEquals(v8_num(42)));
4601 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4602 CHECK(r9->StrictEquals(v8_str("hello")));
4603 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4604 CHECK(r10->StrictEquals(v8::True(isolate)));
4608 THREADED_TEST(ConstructCall) {
4609 LocalContext context;
4610 v8::Isolate* isolate = context->GetIsolate();
4611 v8::HandleScope scope(isolate);
4615 " for (var i = 0; i < arguments.length; i++) {"
4616 " result.push(arguments[i]);"
4620 Local<Function> Foo =
4621 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4623 v8::Handle<Value>* args0 = NULL;
4624 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4625 CHECK_EQ(0, a0->Length());
4627 v8::Handle<Value> args1[] = { v8_num(1.1) };
4628 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4629 CHECK_EQ(1, a1->Length());
4630 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4632 v8::Handle<Value> args2[] = { v8_num(2.2),
4634 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4635 CHECK_EQ(2, a2->Length());
4636 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4637 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4639 v8::Handle<Value> args3[] = { v8_num(4.4),
4642 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4643 CHECK_EQ(3, a3->Length());
4644 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4645 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4646 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4648 v8::Handle<Value> args4[] = { v8_num(7.7),
4652 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4653 CHECK_EQ(4, a4->Length());
4654 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4655 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4656 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4657 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4661 static void CheckUncle(v8::TryCatch* try_catch) {
4662 CHECK(try_catch->HasCaught());
4663 String::Utf8Value str_value(try_catch->Exception());
4664 CHECK_EQ(*str_value, "uncle?");
4669 THREADED_TEST(ConversionNumber) {
4671 v8::HandleScope scope(env->GetIsolate());
4672 // Very large number.
4673 CompileRun("var obj = Math.pow(2,32) * 1237;");
4674 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4675 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4676 CHECK_EQ(0, obj->ToInt32()->Value());
4677 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4679 CompileRun("var obj = -1234567890123;");
4680 obj = env->Global()->Get(v8_str("obj"));
4681 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4682 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4683 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4684 // Small positive integer.
4685 CompileRun("var obj = 42;");
4686 obj = env->Global()->Get(v8_str("obj"));
4687 CHECK_EQ(42.0, obj->ToNumber()->Value());
4688 CHECK_EQ(42, obj->ToInt32()->Value());
4689 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4690 // Negative integer.
4691 CompileRun("var obj = -37;");
4692 obj = env->Global()->Get(v8_str("obj"));
4693 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4694 CHECK_EQ(-37, obj->ToInt32()->Value());
4695 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4696 // Positive non-int32 integer.
4697 CompileRun("var obj = 0x81234567;");
4698 obj = env->Global()->Get(v8_str("obj"));
4699 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4700 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4701 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4703 CompileRun("var obj = 42.3;");
4704 obj = env->Global()->Get(v8_str("obj"));
4705 CHECK_EQ(42.3, obj->ToNumber()->Value());
4706 CHECK_EQ(42, obj->ToInt32()->Value());
4707 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4708 // Large negative fraction.
4709 CompileRun("var obj = -5726623061.75;");
4710 obj = env->Global()->Get(v8_str("obj"));
4711 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4712 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4713 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4717 THREADED_TEST(isNumberType) {
4719 v8::HandleScope scope(env->GetIsolate());
4720 // Very large number.
4721 CompileRun("var obj = Math.pow(2,32) * 1237;");
4722 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4723 CHECK(!obj->IsInt32());
4724 CHECK(!obj->IsUint32());
4725 // Large negative number.
4726 CompileRun("var obj = -1234567890123;");
4727 obj = env->Global()->Get(v8_str("obj"));
4728 CHECK(!obj->IsInt32());
4729 CHECK(!obj->IsUint32());
4730 // Small positive integer.
4731 CompileRun("var obj = 42;");
4732 obj = env->Global()->Get(v8_str("obj"));
4733 CHECK(obj->IsInt32());
4734 CHECK(obj->IsUint32());
4735 // Negative integer.
4736 CompileRun("var obj = -37;");
4737 obj = env->Global()->Get(v8_str("obj"));
4738 CHECK(obj->IsInt32());
4739 CHECK(!obj->IsUint32());
4740 // Positive non-int32 integer.
4741 CompileRun("var obj = 0x81234567;");
4742 obj = env->Global()->Get(v8_str("obj"));
4743 CHECK(!obj->IsInt32());
4744 CHECK(obj->IsUint32());
4746 CompileRun("var obj = 42.3;");
4747 obj = env->Global()->Get(v8_str("obj"));
4748 CHECK(!obj->IsInt32());
4749 CHECK(!obj->IsUint32());
4750 // Large negative fraction.
4751 CompileRun("var obj = -5726623061.75;");
4752 obj = env->Global()->Get(v8_str("obj"));
4753 CHECK(!obj->IsInt32());
4754 CHECK(!obj->IsUint32());
4756 CompileRun("var obj = 0.0;");
4757 obj = env->Global()->Get(v8_str("obj"));
4758 CHECK(obj->IsInt32());
4759 CHECK(obj->IsUint32());
4761 CompileRun("var obj = -0.0;");
4762 obj = env->Global()->Get(v8_str("obj"));
4763 CHECK(!obj->IsInt32());
4764 CHECK(!obj->IsUint32());
4768 THREADED_TEST(ConversionException) {
4770 v8::Isolate* isolate = env->GetIsolate();
4771 v8::HandleScope scope(isolate);
4773 "function TestClass() { };"
4774 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4775 "var obj = new TestClass();");
4776 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4778 v8::TryCatch try_catch;
4780 Local<Value> to_string_result = obj->ToString();
4781 CHECK(to_string_result.IsEmpty());
4782 CheckUncle(&try_catch);
4784 Local<Value> to_number_result = obj->ToNumber();
4785 CHECK(to_number_result.IsEmpty());
4786 CheckUncle(&try_catch);
4788 Local<Value> to_integer_result = obj->ToInteger();
4789 CHECK(to_integer_result.IsEmpty());
4790 CheckUncle(&try_catch);
4792 Local<Value> to_uint32_result = obj->ToUint32();
4793 CHECK(to_uint32_result.IsEmpty());
4794 CheckUncle(&try_catch);
4796 Local<Value> to_int32_result = obj->ToInt32();
4797 CHECK(to_int32_result.IsEmpty());
4798 CheckUncle(&try_catch);
4800 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4801 CHECK(to_object_result.IsEmpty());
4802 CHECK(try_catch.HasCaught());
4805 int32_t int32_value = obj->Int32Value();
4806 CHECK_EQ(0, int32_value);
4807 CheckUncle(&try_catch);
4809 uint32_t uint32_value = obj->Uint32Value();
4810 CHECK_EQ(0, uint32_value);
4811 CheckUncle(&try_catch);
4813 double number_value = obj->NumberValue();
4814 CHECK_NE(0, std::isnan(number_value));
4815 CheckUncle(&try_catch);
4817 int64_t integer_value = obj->IntegerValue();
4818 CHECK_EQ(0.0, static_cast<double>(integer_value));
4819 CheckUncle(&try_catch);
4823 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4824 ApiTestFuzzer::Fuzz();
4825 args.GetIsolate()->ThrowException(v8_str("konto"));
4829 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4830 if (args.Length() < 1) {
4831 args.GetReturnValue().Set(false);
4834 v8::HandleScope scope(args.GetIsolate());
4835 v8::TryCatch try_catch;
4836 Local<Value> result = CompileRun(args[0]->ToString());
4837 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4838 args.GetReturnValue().Set(try_catch.HasCaught());
4842 THREADED_TEST(APICatch) {
4843 v8::Isolate* isolate = CcTest::isolate();
4844 v8::HandleScope scope(isolate);
4845 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4846 templ->Set(v8_str("ThrowFromC"),
4847 v8::FunctionTemplate::New(isolate, ThrowFromC));
4848 LocalContext context(0, templ);
4850 "var thrown = false;"
4856 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4857 CHECK(thrown->BooleanValue());
4861 THREADED_TEST(APIThrowTryCatch) {
4862 v8::Isolate* isolate = CcTest::isolate();
4863 v8::HandleScope scope(isolate);
4864 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4865 templ->Set(v8_str("ThrowFromC"),
4866 v8::FunctionTemplate::New(isolate, ThrowFromC));
4867 LocalContext context(0, templ);
4868 v8::TryCatch try_catch;
4869 CompileRun("ThrowFromC();");
4870 CHECK(try_catch.HasCaught());
4874 // Test that a try-finally block doesn't shadow a try-catch block
4875 // when setting up an external handler.
4877 // BUG(271): Some of the exception propagation does not work on the
4878 // ARM simulator because the simulator separates the C++ stack and the
4879 // JS stack. This test therefore fails on the simulator. The test is
4880 // not threaded to allow the threading tests to run on the simulator.
4881 TEST(TryCatchInTryFinally) {
4882 v8::Isolate* isolate = CcTest::isolate();
4883 v8::HandleScope scope(isolate);
4884 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4885 templ->Set(v8_str("CCatcher"),
4886 v8::FunctionTemplate::New(isolate, CCatcher));
4887 LocalContext context(0, templ);
4888 Local<Value> result = CompileRun("try {"
4890 " CCatcher('throw 7;');"
4895 CHECK(result->IsTrue());
4899 static void check_reference_error_message(
4900 v8::Handle<v8::Message> message,
4901 v8::Handle<v8::Value> data) {
4902 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4903 CHECK(message->Get()->Equals(v8_str(reference_error)));
4907 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4908 ApiTestFuzzer::Fuzz();
4913 // Test that overwritten methods are not invoked on uncaught exception
4914 // formatting. However, they are invoked when performing normal error
4915 // string conversions.
4916 TEST(APIThrowMessageOverwrittenToString) {
4917 v8::Isolate* isolate = CcTest::isolate();
4918 v8::HandleScope scope(isolate);
4919 v8::V8::AddMessageListener(check_reference_error_message);
4920 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4921 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4922 LocalContext context(NULL, templ);
4923 CompileRun("asdf;");
4924 CompileRun("var limit = {};"
4925 "limit.valueOf = fail;"
4926 "Error.stackTraceLimit = limit;");
4928 CompileRun("Array.prototype.pop = fail;");
4929 CompileRun("Object.prototype.hasOwnProperty = fail;");
4930 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4931 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4932 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4933 CompileRun("ReferenceError.prototype.toString ="
4934 " function() { return 'Whoops' }");
4935 CompileRun("asdf;");
4936 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4937 CompileRun("asdf;");
4938 CompileRun("ReferenceError.prototype.constructor = void 0;");
4939 CompileRun("asdf;");
4940 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4941 CompileRun("asdf;");
4942 CompileRun("ReferenceError.prototype = new Object();");
4943 CompileRun("asdf;");
4944 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4945 CHECK(string->Equals(v8_str("Whoops")));
4946 CompileRun("ReferenceError.prototype.constructor = new Object();"
4947 "ReferenceError.prototype.constructor.name = 1;"
4948 "Number.prototype.toString = function() { return 'Whoops'; };"
4949 "ReferenceError.prototype.toString = Object.prototype.toString;");
4950 CompileRun("asdf;");
4951 v8::V8::RemoveMessageListeners(check_reference_error_message);
4955 static void check_custom_error_tostring(
4956 v8::Handle<v8::Message> message,
4957 v8::Handle<v8::Value> data) {
4958 const char* uncaught_error = "Uncaught MyError toString";
4959 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4963 TEST(CustomErrorToString) {
4964 LocalContext context;
4965 v8::HandleScope scope(context->GetIsolate());
4966 v8::V8::AddMessageListener(check_custom_error_tostring);
4968 "function MyError(name, message) { "
4969 " this.name = name; "
4970 " this.message = message; "
4972 "MyError.prototype = Object.create(Error.prototype); "
4973 "MyError.prototype.toString = function() { "
4974 " return 'MyError toString'; "
4976 "throw new MyError('my name', 'my message'); ");
4977 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4981 static void check_custom_error_message(
4982 v8::Handle<v8::Message> message,
4983 v8::Handle<v8::Value> data) {
4984 const char* uncaught_error = "Uncaught MyError: my message";
4985 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4986 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4990 TEST(CustomErrorMessage) {
4991 LocalContext context;
4992 v8::HandleScope scope(context->GetIsolate());
4993 v8::V8::AddMessageListener(check_custom_error_message);
4997 "function MyError(msg) { "
4998 " this.name = 'MyError'; "
4999 " this.message = msg; "
5001 "MyError.prototype = new Error(); "
5002 "throw new MyError('my message'); ");
5006 "function MyError(msg) { "
5007 " this.name = 'MyError'; "
5008 " this.message = msg; "
5010 "inherits = function(childCtor, parentCtor) { "
5011 " function tempCtor() {}; "
5012 " tempCtor.prototype = parentCtor.prototype; "
5013 " childCtor.superClass_ = parentCtor.prototype; "
5014 " childCtor.prototype = new tempCtor(); "
5015 " childCtor.prototype.constructor = childCtor; "
5017 "inherits(MyError, Error); "
5018 "throw new MyError('my message'); ");
5022 "function MyError(msg) { "
5023 " this.name = 'MyError'; "
5024 " this.message = msg; "
5026 "MyError.prototype = Object.create(Error.prototype); "
5027 "throw new MyError('my message'); ");
5029 v8::V8::RemoveMessageListeners(check_custom_error_message);
5033 static void receive_message(v8::Handle<v8::Message> message,
5034 v8::Handle<v8::Value> data) {
5036 message_received = true;
5040 TEST(APIThrowMessage) {
5041 message_received = false;
5042 v8::Isolate* isolate = CcTest::isolate();
5043 v8::HandleScope scope(isolate);
5044 v8::V8::AddMessageListener(receive_message);
5045 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5046 templ->Set(v8_str("ThrowFromC"),
5047 v8::FunctionTemplate::New(isolate, ThrowFromC));
5048 LocalContext context(0, templ);
5049 CompileRun("ThrowFromC();");
5050 CHECK(message_received);
5051 v8::V8::RemoveMessageListeners(receive_message);
5055 TEST(APIThrowMessageAndVerboseTryCatch) {
5056 message_received = false;
5057 v8::Isolate* isolate = CcTest::isolate();
5058 v8::HandleScope scope(isolate);
5059 v8::V8::AddMessageListener(receive_message);
5060 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5061 templ->Set(v8_str("ThrowFromC"),
5062 v8::FunctionTemplate::New(isolate, ThrowFromC));
5063 LocalContext context(0, templ);
5064 v8::TryCatch try_catch;
5065 try_catch.SetVerbose(true);
5066 Local<Value> result = CompileRun("ThrowFromC();");
5067 CHECK(try_catch.HasCaught());
5068 CHECK(result.IsEmpty());
5069 CHECK(message_received);
5070 v8::V8::RemoveMessageListeners(receive_message);
5074 TEST(APIStackOverflowAndVerboseTryCatch) {
5075 message_received = false;
5076 LocalContext context;
5077 v8::HandleScope scope(context->GetIsolate());
5078 v8::V8::AddMessageListener(receive_message);
5079 v8::TryCatch try_catch;
5080 try_catch.SetVerbose(true);
5081 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5082 CHECK(try_catch.HasCaught());
5083 CHECK(result.IsEmpty());
5084 CHECK(message_received);
5085 v8::V8::RemoveMessageListeners(receive_message);
5089 THREADED_TEST(ExternalScriptException) {
5090 v8::Isolate* isolate = CcTest::isolate();
5091 v8::HandleScope scope(isolate);
5092 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5093 templ->Set(v8_str("ThrowFromC"),
5094 v8::FunctionTemplate::New(isolate, ThrowFromC));
5095 LocalContext context(0, templ);
5097 v8::TryCatch try_catch;
5098 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5099 CHECK(result.IsEmpty());
5100 CHECK(try_catch.HasCaught());
5101 String::Utf8Value exception_value(try_catch.Exception());
5102 CHECK_EQ("konto", *exception_value);
5107 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5108 ApiTestFuzzer::Fuzz();
5109 CHECK_EQ(4, args.Length());
5110 int count = args[0]->Int32Value();
5111 int cInterval = args[2]->Int32Value();
5113 args.GetIsolate()->ThrowException(v8_str("FromC"));
5116 Local<v8::Object> global =
5117 args.GetIsolate()->GetCurrentContext()->Global();
5118 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5119 v8::Handle<Value> argv[] = { v8_num(count - 1),
5123 if (count % cInterval == 0) {
5124 v8::TryCatch try_catch;
5125 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5126 int expected = args[3]->Int32Value();
5127 if (try_catch.HasCaught()) {
5128 CHECK_EQ(expected, count);
5129 CHECK(result.IsEmpty());
5130 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5132 CHECK_NE(expected, count);
5134 args.GetReturnValue().Set(result);
5137 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5144 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5145 ApiTestFuzzer::Fuzz();
5146 CHECK_EQ(3, args.Length());
5147 bool equality = args[0]->BooleanValue();
5148 int count = args[1]->Int32Value();
5149 int expected = args[2]->Int32Value();
5151 CHECK_EQ(count, expected);
5153 CHECK_NE(count, expected);
5158 THREADED_TEST(EvalInTryFinally) {
5159 LocalContext context;
5160 v8::HandleScope scope(context->GetIsolate());
5161 v8::TryCatch try_catch;
5162 CompileRun("(function() {"
5164 " eval('asldkf (*&^&*^');"
5169 CHECK(!try_catch.HasCaught());
5173 // This test works by making a stack of alternating JavaScript and C
5174 // activations. These activations set up exception handlers with regular
5175 // intervals, one interval for C activations and another for JavaScript
5176 // activations. When enough activations have been created an exception is
5177 // thrown and we check that the right activation catches the exception and that
5178 // no other activations do. The right activation is always the topmost one with
5179 // a handler, regardless of whether it is in JavaScript or C.
5181 // The notation used to describe a test case looks like this:
5183 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5185 // Each entry is an activation, either JS or C. The index is the count at that
5186 // level. Stars identify activations with exception handlers, the @ identifies
5187 // the exception handler that should catch the exception.
5189 // BUG(271): Some of the exception propagation does not work on the
5190 // ARM simulator because the simulator separates the C++ stack and the
5191 // JS stack. This test therefore fails on the simulator. The test is
5192 // not threaded to allow the threading tests to run on the simulator.
5193 TEST(ExceptionOrder) {
5194 v8::Isolate* isolate = CcTest::isolate();
5195 v8::HandleScope scope(isolate);
5196 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5197 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5198 templ->Set(v8_str("CThrowCountDown"),
5199 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5200 LocalContext context(0, templ);
5202 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5203 " if (count == 0) throw 'FromJS';"
5204 " if (count % jsInterval == 0) {"
5206 " var value = CThrowCountDown(count - 1,"
5210 " check(false, count, expected);"
5213 " check(true, count, expected);"
5216 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5219 Local<Function> fun =
5220 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5223 // count jsInterval cInterval expected
5225 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5226 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5227 fun->Call(fun, argc, a0);
5229 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5230 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5231 fun->Call(fun, argc, a1);
5233 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5234 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5235 fun->Call(fun, argc, a2);
5237 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5238 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5239 fun->Call(fun, argc, a3);
5241 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5242 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5243 fun->Call(fun, argc, a4);
5245 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5246 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5247 fun->Call(fun, argc, a5);
5251 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5252 ApiTestFuzzer::Fuzz();
5253 CHECK_EQ(1, args.Length());
5254 args.GetIsolate()->ThrowException(args[0]);
5258 THREADED_TEST(ThrowValues) {
5259 v8::Isolate* isolate = CcTest::isolate();
5260 v8::HandleScope scope(isolate);
5261 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5262 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5263 LocalContext context(0, templ);
5264 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5265 "function Run(obj) {"
5271 " return 'no exception';"
5273 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5274 CHECK_EQ(5, result->Length());
5275 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5276 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5277 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5278 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5279 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5280 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5281 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5285 THREADED_TEST(CatchZero) {
5286 LocalContext context;
5287 v8::HandleScope scope(context->GetIsolate());
5288 v8::TryCatch try_catch;
5289 CHECK(!try_catch.HasCaught());
5290 CompileRun("throw 10");
5291 CHECK(try_catch.HasCaught());
5292 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5294 CHECK(!try_catch.HasCaught());
5295 CompileRun("throw 0");
5296 CHECK(try_catch.HasCaught());
5297 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5301 THREADED_TEST(CatchExceptionFromWith) {
5302 LocalContext context;
5303 v8::HandleScope scope(context->GetIsolate());
5304 v8::TryCatch try_catch;
5305 CHECK(!try_catch.HasCaught());
5306 CompileRun("var o = {}; with (o) { throw 42; }");
5307 CHECK(try_catch.HasCaught());
5311 THREADED_TEST(TryCatchAndFinallyHidingException) {
5312 LocalContext context;
5313 v8::HandleScope scope(context->GetIsolate());
5314 v8::TryCatch try_catch;
5315 CHECK(!try_catch.HasCaught());
5316 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5317 CompileRun("f({toString: function() { throw 42; }});");
5318 CHECK(!try_catch.HasCaught());
5322 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5323 v8::TryCatch try_catch;
5327 THREADED_TEST(TryCatchAndFinally) {
5328 LocalContext context;
5329 v8::Isolate* isolate = context->GetIsolate();
5330 v8::HandleScope scope(isolate);
5331 context->Global()->Set(
5332 v8_str("native_with_try_catch"),
5333 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5334 v8::TryCatch try_catch;
5335 CHECK(!try_catch.HasCaught());
5338 " throw new Error('a');\n"
5340 " native_with_try_catch();\n"
5342 CHECK(try_catch.HasCaught());
5346 static void TryCatchNestedHelper(int depth) {
5348 v8::TryCatch try_catch;
5349 try_catch.SetVerbose(true);
5350 TryCatchNestedHelper(depth - 1);
5351 CHECK(try_catch.HasCaught());
5352 try_catch.ReThrow();
5354 CcTest::isolate()->ThrowException(v8_str("back"));
5359 TEST(TryCatchNested) {
5360 v8::V8::Initialize();
5361 LocalContext context;
5362 v8::HandleScope scope(context->GetIsolate());
5363 v8::TryCatch try_catch;
5364 TryCatchNestedHelper(5);
5365 CHECK(try_catch.HasCaught());
5366 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5370 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5371 CHECK(try_catch->HasCaught());
5372 Handle<Message> message = try_catch->Message();
5373 Handle<Value> resource = message->GetScriptResourceName();
5374 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5375 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5376 "Uncaught Error: a"));
5377 CHECK_EQ(1, message->GetLineNumber());
5378 CHECK_EQ(6, message->GetStartColumn());
5382 void TryCatchMixedNestingHelper(
5383 const v8::FunctionCallbackInfo<v8::Value>& args) {
5384 ApiTestFuzzer::Fuzz();
5385 v8::TryCatch try_catch;
5386 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5387 CHECK(try_catch.HasCaught());
5388 TryCatchMixedNestingCheck(&try_catch);
5389 try_catch.ReThrow();
5393 // This test ensures that an outer TryCatch in the following situation:
5394 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5395 // does not clobber the Message object generated for the inner TryCatch.
5396 // This exercises the ability of TryCatch.ReThrow() to restore the
5397 // inner pending Message before throwing the exception again.
5398 TEST(TryCatchMixedNesting) {
5399 v8::Isolate* isolate = CcTest::isolate();
5400 v8::HandleScope scope(isolate);
5401 v8::V8::Initialize();
5402 v8::TryCatch try_catch;
5403 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5404 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5405 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5406 LocalContext context(0, templ);
5407 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5408 TryCatchMixedNestingCheck(&try_catch);
5412 THREADED_TEST(Equality) {
5413 LocalContext context;
5414 v8::Isolate* isolate = context->GetIsolate();
5415 v8::HandleScope scope(context->GetIsolate());
5416 // Check that equality works at all before relying on CHECK_EQ
5417 CHECK(v8_str("a")->Equals(v8_str("a")));
5418 CHECK(!v8_str("a")->Equals(v8_str("b")));
5420 CHECK_EQ(v8_str("a"), v8_str("a"));
5421 CHECK_NE(v8_str("a"), v8_str("b"));
5422 CHECK_EQ(v8_num(1), v8_num(1));
5423 CHECK_EQ(v8_num(1.00), v8_num(1));
5424 CHECK_NE(v8_num(1), v8_num(2));
5426 // Assume String is not internalized.
5427 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5428 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5429 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5430 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5431 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5432 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5433 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5434 CHECK(!not_a_number->StrictEquals(not_a_number));
5435 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5436 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5438 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5439 v8::Persistent<v8::Object> alias(isolate, obj);
5440 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5443 CHECK(v8_str("a")->SameValue(v8_str("a")));
5444 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5445 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5446 CHECK(v8_num(1)->SameValue(v8_num(1)));
5447 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5448 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5449 CHECK(not_a_number->SameValue(not_a_number));
5450 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5451 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5455 THREADED_TEST(MultiRun) {
5456 LocalContext context;
5457 v8::HandleScope scope(context->GetIsolate());
5458 Local<Script> script = v8_compile("x");
5459 for (int i = 0; i < 10; i++)
5464 static void GetXValue(Local<String> name,
5465 const v8::PropertyCallbackInfo<v8::Value>& info) {
5466 ApiTestFuzzer::Fuzz();
5467 CHECK_EQ(info.Data(), v8_str("donut"));
5468 CHECK_EQ(name, v8_str("x"));
5469 info.GetReturnValue().Set(name);
5473 THREADED_TEST(SimplePropertyRead) {
5474 LocalContext context;
5475 v8::Isolate* isolate = context->GetIsolate();
5476 v8::HandleScope scope(isolate);
5477 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5478 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5479 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5480 Local<Script> script = v8_compile("obj.x");
5481 for (int i = 0; i < 10; i++) {
5482 Local<Value> result = script->Run();
5483 CHECK_EQ(result, v8_str("x"));
5488 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5489 LocalContext context;
5490 v8::Isolate* isolate = context->GetIsolate();
5491 v8::HandleScope scope(isolate);
5492 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5493 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5494 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5496 // Uses getOwnPropertyDescriptor to check the configurable status
5497 Local<Script> script_desc = v8_compile(
5498 "var prop = Object.getOwnPropertyDescriptor( "
5500 "prop.configurable;");
5501 Local<Value> result = script_desc->Run();
5502 CHECK_EQ(result->BooleanValue(), true);
5504 // Redefine get - but still configurable
5505 Local<Script> script_define = v8_compile(
5506 "var desc = { get: function(){return 42; },"
5507 " configurable: true };"
5508 "Object.defineProperty(obj, 'x', desc);"
5510 result = script_define->Run();
5511 CHECK_EQ(result, v8_num(42));
5513 // Check that the accessor is still configurable
5514 result = script_desc->Run();
5515 CHECK_EQ(result->BooleanValue(), true);
5517 // Redefine to a non-configurable
5518 script_define = v8_compile(
5519 "var desc = { get: function(){return 43; },"
5520 " configurable: false };"
5521 "Object.defineProperty(obj, 'x', desc);"
5523 result = script_define->Run();
5524 CHECK_EQ(result, v8_num(43));
5525 result = script_desc->Run();
5526 CHECK_EQ(result->BooleanValue(), false);
5528 // Make sure that it is not possible to redefine again
5529 v8::TryCatch try_catch;
5530 result = script_define->Run();
5531 CHECK(try_catch.HasCaught());
5532 String::Utf8Value exception_value(try_catch.Exception());
5533 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5537 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5538 v8::Isolate* isolate = CcTest::isolate();
5539 v8::HandleScope scope(isolate);
5540 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5541 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5542 LocalContext context;
5543 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5545 Local<Script> script_desc = v8_compile(
5547 "Object.getOwnPropertyDescriptor( "
5549 "prop.configurable;");
5550 Local<Value> result = script_desc->Run();
5551 CHECK_EQ(result->BooleanValue(), true);
5553 Local<Script> script_define = v8_compile(
5554 "var desc = {get: function(){return 42; },"
5555 " configurable: true };"
5556 "Object.defineProperty(obj, 'x', desc);"
5558 result = script_define->Run();
5559 CHECK_EQ(result, v8_num(42));
5562 result = script_desc->Run();
5563 CHECK_EQ(result->BooleanValue(), true);
5566 script_define = v8_compile(
5567 "var desc = {get: function(){return 43; },"
5568 " configurable: false };"
5569 "Object.defineProperty(obj, 'x', desc);"
5571 result = script_define->Run();
5572 CHECK_EQ(result, v8_num(43));
5573 result = script_desc->Run();
5575 CHECK_EQ(result->BooleanValue(), false);
5577 v8::TryCatch try_catch;
5578 result = script_define->Run();
5579 CHECK(try_catch.HasCaught());
5580 String::Utf8Value exception_value(try_catch.Exception());
5581 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5585 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5587 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5591 THREADED_TEST(DefineAPIAccessorOnObject) {
5592 v8::Isolate* isolate = CcTest::isolate();
5593 v8::HandleScope scope(isolate);
5594 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5595 LocalContext context;
5597 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5598 CompileRun("var obj2 = {};");
5600 CHECK(CompileRun("obj1.x")->IsUndefined());
5601 CHECK(CompileRun("obj2.x")->IsUndefined());
5603 CHECK(GetGlobalProperty(&context, "obj1")->
5604 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5606 ExpectString("obj1.x", "x");
5607 CHECK(CompileRun("obj2.x")->IsUndefined());
5609 CHECK(GetGlobalProperty(&context, "obj2")->
5610 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5612 ExpectString("obj1.x", "x");
5613 ExpectString("obj2.x", "x");
5615 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5616 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5618 CompileRun("Object.defineProperty(obj1, 'x',"
5619 "{ get: function() { return 'y'; }, configurable: true })");
5621 ExpectString("obj1.x", "y");
5622 ExpectString("obj2.x", "x");
5624 CompileRun("Object.defineProperty(obj2, 'x',"
5625 "{ get: function() { return 'y'; }, configurable: true })");
5627 ExpectString("obj1.x", "y");
5628 ExpectString("obj2.x", "y");
5630 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5631 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5633 CHECK(GetGlobalProperty(&context, "obj1")->
5634 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5635 CHECK(GetGlobalProperty(&context, "obj2")->
5636 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5638 ExpectString("obj1.x", "x");
5639 ExpectString("obj2.x", "x");
5641 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5644 // Define getters/setters, but now make them not configurable.
5645 CompileRun("Object.defineProperty(obj1, 'x',"
5646 "{ get: function() { return 'z'; }, configurable: false })");
5647 CompileRun("Object.defineProperty(obj2, 'x',"
5648 "{ get: function() { return 'z'; }, configurable: false })");
5650 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5651 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5653 ExpectString("obj1.x", "z");
5654 ExpectString("obj2.x", "z");
5656 CHECK(!GetGlobalProperty(&context, "obj1")->
5657 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5658 CHECK(!GetGlobalProperty(&context, "obj2")->
5659 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5661 ExpectString("obj1.x", "z");
5662 ExpectString("obj2.x", "z");
5666 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5667 v8::Isolate* isolate = CcTest::isolate();
5668 v8::HandleScope scope(isolate);
5669 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5670 LocalContext context;
5672 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5673 CompileRun("var obj2 = {};");
5675 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5678 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5679 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5682 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5684 ExpectString("obj1.x", "x");
5685 ExpectString("obj2.x", "x");
5687 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5688 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5690 CHECK(!GetGlobalProperty(&context, "obj1")->
5691 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5692 CHECK(!GetGlobalProperty(&context, "obj2")->
5693 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5696 v8::TryCatch try_catch;
5697 CompileRun("Object.defineProperty(obj1, 'x',"
5698 "{get: function() { return 'func'; }})");
5699 CHECK(try_catch.HasCaught());
5700 String::Utf8Value exception_value(try_catch.Exception());
5701 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5704 v8::TryCatch try_catch;
5705 CompileRun("Object.defineProperty(obj2, 'x',"
5706 "{get: function() { return 'func'; }})");
5707 CHECK(try_catch.HasCaught());
5708 String::Utf8Value exception_value(try_catch.Exception());
5709 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5714 static void Get239Value(Local<String> name,
5715 const v8::PropertyCallbackInfo<v8::Value>& info) {
5716 ApiTestFuzzer::Fuzz();
5717 CHECK_EQ(info.Data(), v8_str("donut"));
5718 CHECK_EQ(name, v8_str("239"));
5719 info.GetReturnValue().Set(name);
5723 THREADED_TEST(ElementAPIAccessor) {
5724 v8::Isolate* isolate = CcTest::isolate();
5725 v8::HandleScope scope(isolate);
5726 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5727 LocalContext context;
5729 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5730 CompileRun("var obj2 = {};");
5732 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5736 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5741 ExpectString("obj1[239]", "239");
5742 ExpectString("obj2[239]", "239");
5743 ExpectString("obj1['239']", "239");
5744 ExpectString("obj2['239']", "239");
5748 v8::Persistent<Value> xValue;
5751 static void SetXValue(Local<String> name,
5753 const v8::PropertyCallbackInfo<void>& info) {
5754 CHECK_EQ(value, v8_num(4));
5755 CHECK_EQ(info.Data(), v8_str("donut"));
5756 CHECK_EQ(name, v8_str("x"));
5757 CHECK(xValue.IsEmpty());
5758 xValue.Reset(info.GetIsolate(), value);
5762 THREADED_TEST(SimplePropertyWrite) {
5763 v8::Isolate* isolate = CcTest::isolate();
5764 v8::HandleScope scope(isolate);
5765 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5766 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5767 LocalContext context;
5768 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5769 Local<Script> script = v8_compile("obj.x = 4");
5770 for (int i = 0; i < 10; i++) {
5771 CHECK(xValue.IsEmpty());
5773 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5779 THREADED_TEST(SetterOnly) {
5780 v8::Isolate* isolate = CcTest::isolate();
5781 v8::HandleScope scope(isolate);
5782 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5783 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5784 LocalContext context;
5785 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5786 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5787 for (int i = 0; i < 10; i++) {
5788 CHECK(xValue.IsEmpty());
5790 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5796 THREADED_TEST(NoAccessors) {
5797 v8::Isolate* isolate = CcTest::isolate();
5798 v8::HandleScope scope(isolate);
5799 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5800 templ->SetAccessor(v8_str("x"),
5801 static_cast<v8::AccessorGetterCallback>(NULL),
5804 LocalContext context;
5805 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5806 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5807 for (int i = 0; i < 10; i++) {
5813 static void XPropertyGetter(Local<String> property,
5814 const v8::PropertyCallbackInfo<v8::Value>& info) {
5815 ApiTestFuzzer::Fuzz();
5816 CHECK(info.Data()->IsUndefined());
5817 info.GetReturnValue().Set(property);
5821 THREADED_TEST(NamedInterceptorPropertyRead) {
5822 v8::Isolate* isolate = CcTest::isolate();
5823 v8::HandleScope scope(isolate);
5824 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5825 templ->SetNamedPropertyHandler(XPropertyGetter);
5826 LocalContext context;
5827 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5828 Local<Script> script = v8_compile("obj.x");
5829 for (int i = 0; i < 10; i++) {
5830 Local<Value> result = script->Run();
5831 CHECK_EQ(result, v8_str("x"));
5836 THREADED_TEST(NamedInterceptorDictionaryIC) {
5837 v8::Isolate* isolate = CcTest::isolate();
5838 v8::HandleScope scope(isolate);
5839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840 templ->SetNamedPropertyHandler(XPropertyGetter);
5841 LocalContext context;
5842 // Create an object with a named interceptor.
5843 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5844 Local<Script> script = v8_compile("interceptor_obj.x");
5845 for (int i = 0; i < 10; i++) {
5846 Local<Value> result = script->Run();
5847 CHECK_EQ(result, v8_str("x"));
5849 // Create a slow case object and a function accessing a property in
5850 // that slow case object (with dictionary probing in generated
5851 // code). Then force object with a named interceptor into slow-case,
5852 // pass it to the function, and check that the interceptor is called
5853 // instead of accessing the local property.
5854 Local<Value> result =
5855 CompileRun("function get_x(o) { return o.x; };"
5856 "var obj = { x : 42, y : 0 };"
5858 "for (var i = 0; i < 10; i++) get_x(obj);"
5859 "interceptor_obj.x = 42;"
5860 "interceptor_obj.y = 10;"
5861 "delete interceptor_obj.y;"
5862 "get_x(interceptor_obj)");
5863 CHECK_EQ(result, v8_str("x"));
5867 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5868 v8::Isolate* isolate = CcTest::isolate();
5869 v8::HandleScope scope(isolate);
5870 v8::Local<Context> context1 = Context::New(isolate);
5873 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5874 templ->SetNamedPropertyHandler(XPropertyGetter);
5875 // Create an object with a named interceptor.
5876 v8::Local<v8::Object> object = templ->NewInstance();
5877 context1->Global()->Set(v8_str("interceptor_obj"), object);
5879 // Force the object into the slow case.
5880 CompileRun("interceptor_obj.y = 0;"
5881 "delete interceptor_obj.y;");
5885 // Introduce the object into a different context.
5886 // Repeat named loads to exercise ICs.
5887 LocalContext context2;
5888 context2->Global()->Set(v8_str("interceptor_obj"), object);
5889 Local<Value> result =
5890 CompileRun("function get_x(o) { return o.x; }"
5891 "interceptor_obj.x = 42;"
5892 "for (var i=0; i != 10; i++) {"
5893 " get_x(interceptor_obj);"
5895 "get_x(interceptor_obj)");
5896 // Check that the interceptor was actually invoked.
5897 CHECK_EQ(result, v8_str("x"));
5900 // Return to the original context and force some object to the slow case
5901 // to cause the NormalizedMapCache to verify.
5903 CompileRun("var obj = { x : 0 }; delete obj.x;");
5908 static void SetXOnPrototypeGetter(
5909 Local<String> property,
5910 const v8::PropertyCallbackInfo<v8::Value>& info) {
5911 // Set x on the prototype object and do not handle the get request.
5912 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5913 proto.As<v8::Object>()->Set(v8_str("x"),
5914 v8::Integer::New(info.GetIsolate(), 23));
5918 // This is a regression test for http://crbug.com/20104. Map
5919 // transitions should not interfere with post interceptor lookup.
5920 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5921 v8::Isolate* isolate = CcTest::isolate();
5922 v8::HandleScope scope(isolate);
5923 Local<v8::FunctionTemplate> function_template =
5924 v8::FunctionTemplate::New(isolate);
5925 Local<v8::ObjectTemplate> instance_template
5926 = function_template->InstanceTemplate();
5927 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5928 LocalContext context;
5929 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5930 // Create an instance of F and introduce a map transition for x.
5931 CompileRun("var o = new F(); o.x = 23;");
5932 // Create an instance of F and invoke the getter. The result should be 23.
5933 Local<Value> result = CompileRun("o = new F(); o.x");
5934 CHECK_EQ(result->Int32Value(), 23);
5938 static void IndexedPropertyGetter(
5940 const v8::PropertyCallbackInfo<v8::Value>& info) {
5941 ApiTestFuzzer::Fuzz();
5943 info.GetReturnValue().Set(v8_num(625));
5948 static void IndexedPropertySetter(
5951 const v8::PropertyCallbackInfo<v8::Value>& info) {
5952 ApiTestFuzzer::Fuzz();
5954 info.GetReturnValue().Set(value);
5959 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5960 v8::Isolate* isolate = CcTest::isolate();
5961 v8::HandleScope scope(isolate);
5962 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5963 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5964 IndexedPropertySetter);
5965 LocalContext context;
5966 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5967 Local<Script> getter_script = v8_compile(
5968 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5969 Local<Script> setter_script = v8_compile(
5970 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5973 Local<Script> interceptor_setter_script = v8_compile(
5974 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5976 "obj.foo;"); // This setter should not run, due to the interceptor.
5977 Local<Script> interceptor_getter_script = v8_compile(
5979 Local<Value> result = getter_script->Run();
5980 CHECK_EQ(v8_num(5), result);
5981 result = setter_script->Run();
5982 CHECK_EQ(v8_num(23), result);
5983 result = interceptor_setter_script->Run();
5984 CHECK_EQ(v8_num(23), result);
5985 result = interceptor_getter_script->Run();
5986 CHECK_EQ(v8_num(625), result);
5990 static void UnboxedDoubleIndexedPropertyGetter(
5992 const v8::PropertyCallbackInfo<v8::Value>& info) {
5993 ApiTestFuzzer::Fuzz();
5995 info.GetReturnValue().Set(v8_num(index));
6000 static void UnboxedDoubleIndexedPropertySetter(
6003 const v8::PropertyCallbackInfo<v8::Value>& info) {
6004 ApiTestFuzzer::Fuzz();
6006 info.GetReturnValue().Set(v8_num(index));
6011 void UnboxedDoubleIndexedPropertyEnumerator(
6012 const v8::PropertyCallbackInfo<v8::Array>& info) {
6013 // Force the list of returned keys to be stored in a FastDoubleArray.
6014 Local<Script> indexed_property_names_script = v8_compile(
6015 "keys = new Array(); keys[125000] = 1;"
6016 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6017 "keys.length = 25; keys;");
6018 Local<Value> result = indexed_property_names_script->Run();
6019 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6023 // Make sure that the the interceptor code in the runtime properly handles
6024 // merging property name lists for double-array-backed arrays.
6025 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6026 v8::Isolate* isolate = CcTest::isolate();
6027 v8::HandleScope scope(isolate);
6028 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6029 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6030 UnboxedDoubleIndexedPropertySetter,
6033 UnboxedDoubleIndexedPropertyEnumerator);
6034 LocalContext context;
6035 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6036 // When obj is created, force it to be Stored in a FastDoubleArray.
6037 Local<Script> create_unboxed_double_script = v8_compile(
6038 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6040 "for (x in obj) {key_count++;};"
6042 Local<Value> result = create_unboxed_double_script->Run();
6043 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6044 Local<Script> key_count_check = v8_compile("key_count;");
6045 result = key_count_check->Run();
6046 CHECK_EQ(v8_num(40013), result);
6050 void SloppyArgsIndexedPropertyEnumerator(
6051 const v8::PropertyCallbackInfo<v8::Array>& info) {
6052 // Force the list of returned keys to be stored in a Arguments object.
6053 Local<Script> indexed_property_names_script = v8_compile(
6055 " return arguments;"
6057 "keys = f(0, 1, 2, 3);"
6059 Local<Object> result =
6060 Local<Object>::Cast(indexed_property_names_script->Run());
6061 // Have to populate the handle manually, as it's not Cast-able.
6062 i::Handle<i::JSObject> o =
6063 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6064 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6065 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6069 static void SloppyIndexedPropertyGetter(
6071 const v8::PropertyCallbackInfo<v8::Value>& info) {
6072 ApiTestFuzzer::Fuzz();
6074 info.GetReturnValue().Set(v8_num(index));
6079 // Make sure that the the interceptor code in the runtime properly handles
6080 // merging property name lists for non-string arguments arrays.
6081 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6082 v8::Isolate* isolate = CcTest::isolate();
6083 v8::HandleScope scope(isolate);
6084 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6085 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6089 SloppyArgsIndexedPropertyEnumerator);
6090 LocalContext context;
6091 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6092 Local<Script> create_args_script = v8_compile(
6093 "var key_count = 0;"
6094 "for (x in obj) {key_count++;} key_count;");
6095 Local<Value> result = create_args_script->Run();
6096 CHECK_EQ(v8_num(4), result);
6100 static void IdentityIndexedPropertyGetter(
6102 const v8::PropertyCallbackInfo<v8::Value>& info) {
6103 info.GetReturnValue().Set(index);
6107 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6108 v8::Isolate* isolate = CcTest::isolate();
6109 v8::HandleScope scope(isolate);
6110 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6113 LocalContext context;
6114 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6116 // Check fast object case.
6117 const char* fast_case_code =
6118 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6119 ExpectString(fast_case_code, "0");
6122 const char* slow_case_code =
6123 "obj.x = 1; delete obj.x;"
6124 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6125 ExpectString(slow_case_code, "1");
6129 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6130 v8::Isolate* isolate = CcTest::isolate();
6131 v8::HandleScope scope(isolate);
6132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6133 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6135 LocalContext context;
6136 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6141 " for (var i = 0; i < 100; i++) {"
6143 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6149 ExpectString(code, "PASSED");
6153 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6154 v8::Isolate* isolate = CcTest::isolate();
6155 v8::HandleScope scope(isolate);
6156 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6157 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6159 LocalContext context;
6160 Local<v8::Object> obj = templ->NewInstance();
6161 obj->TurnOnAccessCheck();
6162 context->Global()->Set(v8_str("obj"), obj);
6166 " for (var i = 0; i < 100; i++) {"
6168 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6174 ExpectString(code, "PASSED");
6178 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6179 i::FLAG_allow_natives_syntax = true;
6180 v8::Isolate* isolate = CcTest::isolate();
6181 v8::HandleScope scope(isolate);
6182 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6183 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6185 LocalContext context;
6186 Local<v8::Object> obj = templ->NewInstance();
6187 context->Global()->Set(v8_str("obj"), obj);
6191 " for (var i = 0; i < 100; i++) {"
6192 " var expected = i;"
6194 " %EnableAccessChecks(obj);"
6195 " expected = undefined;"
6198 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6199 " if (i == 5) %DisableAccessChecks(obj);"
6205 ExpectString(code, "PASSED");
6209 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6210 v8::Isolate* isolate = CcTest::isolate();
6211 v8::HandleScope scope(isolate);
6212 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6213 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6215 LocalContext context;
6216 Local<v8::Object> obj = templ->NewInstance();
6217 context->Global()->Set(v8_str("obj"), obj);
6221 " for (var i = 0; i < 100; i++) {"
6223 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6229 ExpectString(code, "PASSED");
6233 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6234 v8::Isolate* isolate = CcTest::isolate();
6235 v8::HandleScope scope(isolate);
6236 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6237 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6239 LocalContext context;
6240 Local<v8::Object> obj = templ->NewInstance();
6241 context->Global()->Set(v8_str("obj"), obj);
6245 " for (var i = 0; i < 100; i++) {"
6246 " var expected = i;"
6250 " expected = undefined;"
6253 " /* probe minimal Smi number on 32-bit platforms */"
6254 " key = -(1 << 30);"
6255 " expected = undefined;"
6258 " /* probe minimal Smi number on 64-bit platforms */"
6260 " expected = undefined;"
6262 " var v = obj[key];"
6263 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6269 ExpectString(code, "PASSED");
6273 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6274 v8::Isolate* isolate = CcTest::isolate();
6275 v8::HandleScope scope(isolate);
6276 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6277 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6279 LocalContext context;
6280 Local<v8::Object> obj = templ->NewInstance();
6281 context->Global()->Set(v8_str("obj"), obj);
6285 " for (var i = 0; i < 100; i++) {"
6286 " var expected = i;"
6290 " expected = undefined;"
6292 " var v = obj[key];"
6293 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6299 ExpectString(code, "PASSED");
6303 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
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;"
6319 " obj = {50: 'foobar'};"
6320 " expected = 'foobar';"
6323 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6324 " if (i == 50) obj = original;"
6330 ExpectString(code, "PASSED");
6334 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
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 original = obj;"
6347 " for (var i = 0; i < 100; i++) {"
6348 " var expected = i;"
6351 " expected = undefined;"
6354 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6355 " if (i == 5) obj = original;"
6361 ExpectString(code, "PASSED");
6365 THREADED_TEST(IndexedInterceptorOnProto) {
6366 v8::Isolate* isolate = CcTest::isolate();
6367 v8::HandleScope scope(isolate);
6368 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6369 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6371 LocalContext context;
6372 Local<v8::Object> obj = templ->NewInstance();
6373 context->Global()->Set(v8_str("obj"), obj);
6376 "var o = {__proto__: obj};"
6378 " for (var i = 0; i < 100; i++) {"
6380 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6386 ExpectString(code, "PASSED");
6390 THREADED_TEST(MultiContexts) {
6391 v8::Isolate* isolate = CcTest::isolate();
6392 v8::HandleScope scope(isolate);
6393 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6394 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6397 Local<String> password = v8_str("Password");
6399 // Create an environment
6400 LocalContext context0(0, templ);
6401 context0->SetSecurityToken(password);
6402 v8::Handle<v8::Object> global0 = context0->Global();
6403 global0->Set(v8_str("custom"), v8_num(1234));
6404 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6406 // Create an independent environment
6407 LocalContext context1(0, templ);
6408 context1->SetSecurityToken(password);
6409 v8::Handle<v8::Object> global1 = context1->Global();
6410 global1->Set(v8_str("custom"), v8_num(1234));
6411 CHECK_NE(global0, global1);
6412 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6413 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6415 // Now create a new context with the old global
6416 LocalContext context2(0, templ, global1);
6417 context2->SetSecurityToken(password);
6418 v8::Handle<v8::Object> global2 = context2->Global();
6419 CHECK_EQ(global1, global2);
6420 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6421 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6425 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6426 // Make sure that functions created by cloning boilerplates cannot
6427 // communicate through their __proto__ field.
6429 v8::HandleScope scope(CcTest::isolate());
6432 v8::Handle<v8::Object> global0 =
6434 v8::Handle<v8::Object> object0 =
6435 global0->Get(v8_str("Object")).As<v8::Object>();
6436 v8::Handle<v8::Object> tostring0 =
6437 object0->Get(v8_str("toString")).As<v8::Object>();
6438 v8::Handle<v8::Object> proto0 =
6439 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6440 proto0->Set(v8_str("custom"), v8_num(1234));
6443 v8::Handle<v8::Object> global1 =
6445 v8::Handle<v8::Object> object1 =
6446 global1->Get(v8_str("Object")).As<v8::Object>();
6447 v8::Handle<v8::Object> tostring1 =
6448 object1->Get(v8_str("toString")).As<v8::Object>();
6449 v8::Handle<v8::Object> proto1 =
6450 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6451 CHECK(!proto1->Has(v8_str("custom")));
6455 THREADED_TEST(Regress892105) {
6456 // Make sure that object and array literals created by cloning
6457 // boilerplates cannot communicate through their __proto__
6458 // field. This is rather difficult to check, but we try to add stuff
6459 // to Object.prototype and Array.prototype and create a new
6460 // environment. This should succeed.
6462 v8::HandleScope scope(CcTest::isolate());
6464 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6465 "Array.prototype.arr = 4567;"
6469 Local<Script> script0 = v8_compile(source);
6470 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6473 Local<Script> script1 = v8_compile(source);
6474 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6478 THREADED_TEST(UndetectableObject) {
6480 v8::HandleScope scope(env->GetIsolate());
6482 Local<v8::FunctionTemplate> desc =
6483 v8::FunctionTemplate::New(env->GetIsolate());
6484 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6486 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6487 env->Global()->Set(v8_str("undetectable"), obj);
6489 ExpectString("undetectable.toString()", "[object Object]");
6490 ExpectString("typeof undetectable", "undefined");
6491 ExpectString("typeof(undetectable)", "undefined");
6492 ExpectBoolean("typeof undetectable == 'undefined'", true);
6493 ExpectBoolean("typeof undetectable == 'object'", false);
6494 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6495 ExpectBoolean("!undetectable", true);
6497 ExpectObject("true&&undetectable", obj);
6498 ExpectBoolean("false&&undetectable", false);
6499 ExpectBoolean("true||undetectable", true);
6500 ExpectObject("false||undetectable", obj);
6502 ExpectObject("undetectable&&true", obj);
6503 ExpectObject("undetectable&&false", obj);
6504 ExpectBoolean("undetectable||true", true);
6505 ExpectBoolean("undetectable||false", false);
6507 ExpectBoolean("undetectable==null", true);
6508 ExpectBoolean("null==undetectable", true);
6509 ExpectBoolean("undetectable==undefined", true);
6510 ExpectBoolean("undefined==undetectable", true);
6511 ExpectBoolean("undetectable==undetectable", true);
6514 ExpectBoolean("undetectable===null", false);
6515 ExpectBoolean("null===undetectable", false);
6516 ExpectBoolean("undetectable===undefined", false);
6517 ExpectBoolean("undefined===undetectable", false);
6518 ExpectBoolean("undetectable===undetectable", true);
6522 THREADED_TEST(VoidLiteral) {
6524 v8::Isolate* isolate = env->GetIsolate();
6525 v8::HandleScope scope(isolate);
6527 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6528 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6530 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6531 env->Global()->Set(v8_str("undetectable"), obj);
6533 ExpectBoolean("undefined == void 0", true);
6534 ExpectBoolean("undetectable == void 0", true);
6535 ExpectBoolean("null == void 0", true);
6536 ExpectBoolean("undefined === void 0", true);
6537 ExpectBoolean("undetectable === void 0", false);
6538 ExpectBoolean("null === void 0", false);
6540 ExpectBoolean("void 0 == undefined", true);
6541 ExpectBoolean("void 0 == undetectable", true);
6542 ExpectBoolean("void 0 == null", true);
6543 ExpectBoolean("void 0 === undefined", true);
6544 ExpectBoolean("void 0 === undetectable", false);
6545 ExpectBoolean("void 0 === null", false);
6547 ExpectString("(function() {"
6549 " return x === void 0;"
6551 " return e.toString();"
6554 "ReferenceError: x is not defined");
6555 ExpectString("(function() {"
6557 " return void 0 === x;"
6559 " return e.toString();"
6562 "ReferenceError: x is not defined");
6566 THREADED_TEST(ExtensibleOnUndetectable) {
6568 v8::Isolate* isolate = env->GetIsolate();
6569 v8::HandleScope scope(isolate);
6571 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6572 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6574 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6575 env->Global()->Set(v8_str("undetectable"), obj);
6577 Local<String> source = v8_str("undetectable.x = 42;"
6580 Local<Script> script = v8_compile(source);
6582 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6584 ExpectBoolean("Object.isExtensible(undetectable)", true);
6586 source = v8_str("Object.preventExtensions(undetectable);");
6587 script = v8_compile(source);
6589 ExpectBoolean("Object.isExtensible(undetectable)", false);
6591 source = v8_str("undetectable.y = 2000;");
6592 script = v8_compile(source);
6594 ExpectBoolean("undetectable.y == undefined", true);
6599 THREADED_TEST(UndetectableString) {
6601 v8::HandleScope scope(env->GetIsolate());
6603 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6604 String::kUndetectableString);
6605 env->Global()->Set(v8_str("undetectable"), obj);
6607 ExpectString("undetectable", "foo");
6608 ExpectString("typeof undetectable", "undefined");
6609 ExpectString("typeof(undetectable)", "undefined");
6610 ExpectBoolean("typeof undetectable == 'undefined'", true);
6611 ExpectBoolean("typeof undetectable == 'string'", false);
6612 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6613 ExpectBoolean("!undetectable", true);
6615 ExpectObject("true&&undetectable", obj);
6616 ExpectBoolean("false&&undetectable", false);
6617 ExpectBoolean("true||undetectable", true);
6618 ExpectObject("false||undetectable", obj);
6620 ExpectObject("undetectable&&true", obj);
6621 ExpectObject("undetectable&&false", obj);
6622 ExpectBoolean("undetectable||true", true);
6623 ExpectBoolean("undetectable||false", false);
6625 ExpectBoolean("undetectable==null", true);
6626 ExpectBoolean("null==undetectable", true);
6627 ExpectBoolean("undetectable==undefined", true);
6628 ExpectBoolean("undefined==undetectable", true);
6629 ExpectBoolean("undetectable==undetectable", true);
6632 ExpectBoolean("undetectable===null", false);
6633 ExpectBoolean("null===undetectable", false);
6634 ExpectBoolean("undetectable===undefined", false);
6635 ExpectBoolean("undefined===undetectable", false);
6636 ExpectBoolean("undetectable===undetectable", true);
6640 TEST(UndetectableOptimized) {
6641 i::FLAG_allow_natives_syntax = true;
6643 v8::HandleScope scope(env->GetIsolate());
6645 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6646 String::kUndetectableString);
6647 env->Global()->Set(v8_str("undetectable"), obj);
6648 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6651 "function testBranch() {"
6652 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6653 " if (%_IsUndetectableObject(detectable)) throw 2;"
6655 "function testBool() {"
6656 " var b1 = !%_IsUndetectableObject(undetectable);"
6657 " var b2 = %_IsUndetectableObject(detectable);"
6662 "%OptimizeFunctionOnNextCall(testBranch);"
6663 "%OptimizeFunctionOnNextCall(testBool);"
6664 "for (var i = 0; i < 10; i++) {"
6673 template <typename T> static void USE(T) { }
6676 // The point of this test is type checking. We run it only so compilers
6677 // don't complain about an unused function.
6678 TEST(PersistentHandles) {
6680 v8::Isolate* isolate = CcTest::isolate();
6681 v8::HandleScope scope(isolate);
6682 Local<String> str = v8_str("foo");
6683 v8::Persistent<String> p_str(isolate, str);
6685 Local<Script> scr = v8_compile("");
6686 v8::Persistent<Script> p_scr(isolate, scr);
6688 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6689 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6694 static void HandleLogDelegator(
6695 const v8::FunctionCallbackInfo<v8::Value>& args) {
6696 ApiTestFuzzer::Fuzz();
6700 THREADED_TEST(GlobalObjectTemplate) {
6701 v8::Isolate* isolate = CcTest::isolate();
6702 v8::HandleScope handle_scope(isolate);
6703 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6704 global_template->Set(v8_str("JSNI_Log"),
6705 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6706 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6707 Context::Scope context_scope(context);
6708 CompileRun("JSNI_Log('LOG')");
6712 static const char* kSimpleExtensionSource =
6718 TEST(SimpleExtensions) {
6719 v8::HandleScope handle_scope(CcTest::isolate());
6720 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6721 const char* extension_names[] = { "simpletest" };
6722 v8::ExtensionConfiguration extensions(1, extension_names);
6723 v8::Handle<Context> context =
6724 Context::New(CcTest::isolate(), &extensions);
6725 Context::Scope lock(context);
6726 v8::Handle<Value> result = CompileRun("Foo()");
6727 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6731 TEST(NullExtensions) {
6732 v8::HandleScope handle_scope(CcTest::isolate());
6733 v8::RegisterExtension(new Extension("nulltest", NULL));
6734 const char* extension_names[] = { "nulltest" };
6735 v8::ExtensionConfiguration extensions(1, extension_names);
6736 v8::Handle<Context> context =
6737 Context::New(CcTest::isolate(), &extensions);
6738 Context::Scope lock(context);
6739 v8::Handle<Value> result = CompileRun("1+3");
6740 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6744 static const char* kEmbeddedExtensionSource =
6745 "function Ret54321(){return 54321;}~~@@$"
6746 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6747 static const int kEmbeddedExtensionSourceValidLen = 34;
6750 TEST(ExtensionMissingSourceLength) {
6751 v8::HandleScope handle_scope(CcTest::isolate());
6752 v8::RegisterExtension(new Extension("srclentest_fail",
6753 kEmbeddedExtensionSource));
6754 const char* extension_names[] = { "srclentest_fail" };
6755 v8::ExtensionConfiguration extensions(1, extension_names);
6756 v8::Handle<Context> context =
6757 Context::New(CcTest::isolate(), &extensions);
6758 CHECK_EQ(0, *context);
6762 TEST(ExtensionWithSourceLength) {
6763 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6764 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6765 v8::HandleScope handle_scope(CcTest::isolate());
6766 i::ScopedVector<char> extension_name(32);
6767 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6768 v8::RegisterExtension(new Extension(extension_name.start(),
6769 kEmbeddedExtensionSource, 0, 0,
6771 const char* extension_names[1] = { extension_name.start() };
6772 v8::ExtensionConfiguration extensions(1, extension_names);
6773 v8::Handle<Context> context =
6774 Context::New(CcTest::isolate(), &extensions);
6775 if (source_len == kEmbeddedExtensionSourceValidLen) {
6776 Context::Scope lock(context);
6777 v8::Handle<Value> result = CompileRun("Ret54321()");
6778 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6780 // Anything but exactly the right length should fail to compile.
6781 CHECK_EQ(0, *context);
6787 static const char* kEvalExtensionSource1 =
6788 "function UseEval1() {"
6790 " return eval('x');"
6794 static const char* kEvalExtensionSource2 =
6798 " return eval('x');"
6800 " this.UseEval2 = e;"
6804 TEST(UseEvalFromExtension) {
6805 v8::HandleScope handle_scope(CcTest::isolate());
6806 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6807 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6808 const char* extension_names[] = { "evaltest1", "evaltest2" };
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("UseEval1()");
6814 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6815 result = CompileRun("UseEval2()");
6816 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6820 static const char* kWithExtensionSource1 =
6821 "function UseWith1() {"
6823 " with({x:87}) { return x; }"
6828 static const char* kWithExtensionSource2 =
6832 " with ({x:87}) { return x; }"
6834 " this.UseWith2 = e;"
6838 TEST(UseWithFromExtension) {
6839 v8::HandleScope handle_scope(CcTest::isolate());
6840 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6841 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6842 const char* extension_names[] = { "withtest1", "withtest2" };
6843 v8::ExtensionConfiguration extensions(2, extension_names);
6844 v8::Handle<Context> context =
6845 Context::New(CcTest::isolate(), &extensions);
6846 Context::Scope lock(context);
6847 v8::Handle<Value> result = CompileRun("UseWith1()");
6848 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6849 result = CompileRun("UseWith2()");
6850 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6854 TEST(AutoExtensions) {
6855 v8::HandleScope handle_scope(CcTest::isolate());
6856 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6857 extension->set_auto_enable(true);
6858 v8::RegisterExtension(extension);
6859 v8::Handle<Context> context =
6860 Context::New(CcTest::isolate());
6861 Context::Scope lock(context);
6862 v8::Handle<Value> result = CompileRun("Foo()");
6863 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6867 static const char* kSyntaxErrorInExtensionSource =
6871 // Test that a syntax error in an extension does not cause a fatal
6872 // error but results in an empty context.
6873 TEST(SyntaxErrorExtensions) {
6874 v8::HandleScope handle_scope(CcTest::isolate());
6875 v8::RegisterExtension(new Extension("syntaxerror",
6876 kSyntaxErrorInExtensionSource));
6877 const char* extension_names[] = { "syntaxerror" };
6878 v8::ExtensionConfiguration extensions(1, extension_names);
6879 v8::Handle<Context> context =
6880 Context::New(CcTest::isolate(), &extensions);
6881 CHECK(context.IsEmpty());
6885 static const char* kExceptionInExtensionSource =
6889 // Test that an exception when installing an extension does not cause
6890 // a fatal error but results in an empty context.
6891 TEST(ExceptionExtensions) {
6892 v8::HandleScope handle_scope(CcTest::isolate());
6893 v8::RegisterExtension(new Extension("exception",
6894 kExceptionInExtensionSource));
6895 const char* extension_names[] = { "exception" };
6896 v8::ExtensionConfiguration extensions(1, extension_names);
6897 v8::Handle<Context> context =
6898 Context::New(CcTest::isolate(), &extensions);
6899 CHECK(context.IsEmpty());
6903 static const char* kNativeCallInExtensionSource =
6904 "function call_runtime_last_index_of(x) {"
6905 " return %StringLastIndexOf(x, 'bob', 10);"
6909 static const char* kNativeCallTest =
6910 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6912 // Test that a native runtime calls are supported in extensions.
6913 TEST(NativeCallInExtensions) {
6914 v8::HandleScope handle_scope(CcTest::isolate());
6915 v8::RegisterExtension(new Extension("nativecall",
6916 kNativeCallInExtensionSource));
6917 const char* extension_names[] = { "nativecall" };
6918 v8::ExtensionConfiguration extensions(1, extension_names);
6919 v8::Handle<Context> context =
6920 Context::New(CcTest::isolate(), &extensions);
6921 Context::Scope lock(context);
6922 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6923 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6927 class NativeFunctionExtension : public Extension {
6929 NativeFunctionExtension(const char* name,
6931 v8::FunctionCallback fun = &Echo)
6932 : Extension(name, source),
6935 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6936 v8::Isolate* isolate,
6937 v8::Handle<v8::String> name) {
6938 return v8::FunctionTemplate::New(isolate, function_);
6941 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6942 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6945 v8::FunctionCallback function_;
6949 TEST(NativeFunctionDeclaration) {
6950 v8::HandleScope handle_scope(CcTest::isolate());
6951 const char* name = "nativedecl";
6952 v8::RegisterExtension(new NativeFunctionExtension(name,
6953 "native function foo();"));
6954 const char* extension_names[] = { name };
6955 v8::ExtensionConfiguration extensions(1, extension_names);
6956 v8::Handle<Context> context =
6957 Context::New(CcTest::isolate(), &extensions);
6958 Context::Scope lock(context);
6959 v8::Handle<Value> result = CompileRun("foo(42);");
6960 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6964 TEST(NativeFunctionDeclarationError) {
6965 v8::HandleScope handle_scope(CcTest::isolate());
6966 const char* name = "nativedeclerr";
6967 // Syntax error in extension code.
6968 v8::RegisterExtension(new NativeFunctionExtension(name,
6969 "native\nfunction foo();"));
6970 const char* extension_names[] = { name };
6971 v8::ExtensionConfiguration extensions(1, extension_names);
6972 v8::Handle<Context> context =
6973 Context::New(CcTest::isolate(), &extensions);
6974 CHECK(context.IsEmpty());
6978 TEST(NativeFunctionDeclarationErrorEscape) {
6979 v8::HandleScope handle_scope(CcTest::isolate());
6980 const char* name = "nativedeclerresc";
6981 // Syntax error in extension code - escape code in "native" means that
6982 // it's not treated as a keyword.
6983 v8::RegisterExtension(new NativeFunctionExtension(
6985 "nativ\\u0065 function foo();"));
6986 const char* extension_names[] = { name };
6987 v8::ExtensionConfiguration extensions(1, extension_names);
6988 v8::Handle<Context> context =
6989 Context::New(CcTest::isolate(), &extensions);
6990 CHECK(context.IsEmpty());
6994 static void CheckDependencies(const char* name, const char* expected) {
6995 v8::HandleScope handle_scope(CcTest::isolate());
6996 v8::ExtensionConfiguration config(1, &name);
6997 LocalContext context(&config);
6998 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6999 context->Global()->Get(v8_str("loaded")));
7010 THREADED_TEST(ExtensionDependency) {
7011 static const char* kEDeps[] = { "D" };
7012 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7013 static const char* kDDeps[] = { "B", "C" };
7014 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7015 static const char* kBCDeps[] = { "A" };
7016 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7017 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7018 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7019 CheckDependencies("A", "undefinedA");
7020 CheckDependencies("B", "undefinedAB");
7021 CheckDependencies("C", "undefinedAC");
7022 CheckDependencies("D", "undefinedABCD");
7023 CheckDependencies("E", "undefinedABCDE");
7024 v8::HandleScope handle_scope(CcTest::isolate());
7025 static const char* exts[2] = { "C", "E" };
7026 v8::ExtensionConfiguration config(2, exts);
7027 LocalContext context(&config);
7028 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7032 static const char* kExtensionTestScript =
7033 "native function A();"
7034 "native function B();"
7035 "native function C();"
7037 " if (i == 0) return A();"
7038 " if (i == 1) return B();"
7039 " if (i == 2) return C();"
7043 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7044 ApiTestFuzzer::Fuzz();
7045 if (args.IsConstructCall()) {
7046 args.This()->Set(v8_str("data"), args.Data());
7047 args.GetReturnValue().SetNull();
7050 args.GetReturnValue().Set(args.Data());
7054 class FunctionExtension : public Extension {
7056 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7057 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7058 v8::Isolate* isolate,
7059 v8::Handle<String> name);
7063 static int lookup_count = 0;
7064 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7065 v8::Isolate* isolate, v8::Handle<String> name) {
7067 if (name->Equals(v8_str("A"))) {
7068 return v8::FunctionTemplate::New(
7069 isolate, CallFun, v8::Integer::New(isolate, 8));
7070 } else if (name->Equals(v8_str("B"))) {
7071 return v8::FunctionTemplate::New(
7072 isolate, CallFun, v8::Integer::New(isolate, 7));
7073 } else if (name->Equals(v8_str("C"))) {
7074 return v8::FunctionTemplate::New(
7075 isolate, CallFun, v8::Integer::New(isolate, 6));
7077 return v8::Handle<v8::FunctionTemplate>();
7082 THREADED_TEST(FunctionLookup) {
7083 v8::RegisterExtension(new FunctionExtension());
7084 v8::HandleScope handle_scope(CcTest::isolate());
7085 static const char* exts[1] = { "functiontest" };
7086 v8::ExtensionConfiguration config(1, exts);
7087 LocalContext context(&config);
7088 CHECK_EQ(3, lookup_count);
7089 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7090 CompileRun("Foo(0)"));
7091 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7092 CompileRun("Foo(1)"));
7093 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7094 CompileRun("Foo(2)"));
7098 THREADED_TEST(NativeFunctionConstructCall) {
7099 v8::RegisterExtension(new FunctionExtension());
7100 v8::HandleScope handle_scope(CcTest::isolate());
7101 static const char* exts[1] = { "functiontest" };
7102 v8::ExtensionConfiguration config(1, exts);
7103 LocalContext context(&config);
7104 for (int i = 0; i < 10; i++) {
7105 // Run a few times to ensure that allocation of objects doesn't
7106 // change behavior of a constructor function.
7107 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7108 CompileRun("(new A()).data"));
7109 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7110 CompileRun("(new B()).data"));
7111 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7112 CompileRun("(new C()).data"));
7117 static const char* last_location;
7118 static const char* last_message;
7119 void StoringErrorCallback(const char* location, const char* message) {
7120 if (last_location == NULL) {
7121 last_location = location;
7122 last_message = message;
7127 // ErrorReporting creates a circular extensions configuration and
7128 // tests that the fatal error handler gets called. This renders V8
7129 // unusable and therefore this test cannot be run in parallel.
7130 TEST(ErrorReporting) {
7131 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7132 static const char* aDeps[] = { "B" };
7133 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7134 static const char* bDeps[] = { "A" };
7135 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7136 last_location = NULL;
7137 v8::ExtensionConfiguration config(1, bDeps);
7138 v8::Handle<Context> context =
7139 Context::New(CcTest::isolate(), &config);
7140 CHECK(context.IsEmpty());
7141 CHECK_NE(last_location, NULL);
7145 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7146 v8::Handle<Value> data) {
7147 CHECK(message->GetScriptResourceName()->IsUndefined());
7148 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7149 message->GetLineNumber();
7150 message->GetSourceLine();
7154 THREADED_TEST(ErrorWithMissingScriptInfo) {
7155 LocalContext context;
7156 v8::HandleScope scope(context->GetIsolate());
7157 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7158 CompileRun("throw Error()");
7159 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7163 struct FlagAndPersistent {
7165 v8::Persistent<v8::Object> handle;
7169 static void DisposeAndSetFlag(
7170 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7171 data.GetParameter()->handle.Reset();
7172 data.GetParameter()->flag = true;
7176 THREADED_TEST(IndependentWeakHandle) {
7177 v8::Isolate* iso = CcTest::isolate();
7178 v8::HandleScope scope(iso);
7179 v8::Handle<Context> context = Context::New(iso);
7180 Context::Scope context_scope(context);
7182 FlagAndPersistent object_a, object_b;
7185 v8::HandleScope handle_scope(iso);
7186 object_a.handle.Reset(iso, v8::Object::New(iso));
7187 object_b.handle.Reset(iso, v8::Object::New(iso));
7190 object_a.flag = false;
7191 object_b.flag = false;
7192 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7193 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7194 CHECK(!object_b.handle.IsIndependent());
7195 object_a.handle.MarkIndependent();
7196 object_b.handle.MarkIndependent();
7197 CHECK(object_b.handle.IsIndependent());
7198 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7199 CHECK(object_a.flag);
7200 CHECK(object_b.flag);
7204 static void InvokeScavenge() {
7205 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7209 static void InvokeMarkSweep() {
7210 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7214 static void ForceScavenge(
7215 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7216 data.GetParameter()->handle.Reset();
7217 data.GetParameter()->flag = true;
7222 static void ForceMarkSweep(
7223 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7224 data.GetParameter()->handle.Reset();
7225 data.GetParameter()->flag = true;
7230 THREADED_TEST(GCFromWeakCallbacks) {
7231 v8::Isolate* isolate = CcTest::isolate();
7232 v8::HandleScope scope(isolate);
7233 v8::Handle<Context> context = Context::New(isolate);
7234 Context::Scope context_scope(context);
7236 static const int kNumberOfGCTypes = 2;
7237 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7239 Callback gc_forcing_callback[kNumberOfGCTypes] =
7240 {&ForceScavenge, &ForceMarkSweep};
7242 typedef void (*GCInvoker)();
7243 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7245 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7246 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7247 FlagAndPersistent object;
7249 v8::HandleScope handle_scope(isolate);
7250 object.handle.Reset(isolate, v8::Object::New(isolate));
7252 object.flag = false;
7253 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7254 object.handle.MarkIndependent();
7255 invoke_gc[outer_gc]();
7262 static void RevivingCallback(
7263 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7264 data.GetParameter()->handle.ClearWeak();
7265 data.GetParameter()->flag = true;
7269 THREADED_TEST(IndependentHandleRevival) {
7270 v8::Isolate* isolate = CcTest::isolate();
7271 v8::HandleScope scope(isolate);
7272 v8::Handle<Context> context = Context::New(isolate);
7273 Context::Scope context_scope(context);
7275 FlagAndPersistent object;
7277 v8::HandleScope handle_scope(isolate);
7278 v8::Local<v8::Object> o = v8::Object::New(isolate);
7279 object.handle.Reset(isolate, o);
7280 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7281 v8::Local<String> y_str = v8_str("y");
7282 o->Set(y_str, y_str);
7284 object.flag = false;
7285 object.handle.SetWeak(&object, &RevivingCallback);
7286 object.handle.MarkIndependent();
7287 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7289 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7291 v8::HandleScope handle_scope(isolate);
7292 v8::Local<v8::Object> o =
7293 v8::Local<v8::Object>::New(isolate, object.handle);
7294 v8::Local<String> y_str = v8_str("y");
7295 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7296 CHECK(o->Get(y_str)->Equals(y_str));
7301 v8::Handle<Function> args_fun;
7304 static void ArgumentsTestCallback(
7305 const v8::FunctionCallbackInfo<v8::Value>& args) {
7306 ApiTestFuzzer::Fuzz();
7307 v8::Isolate* isolate = args.GetIsolate();
7308 CHECK_EQ(args_fun, args.Callee());
7309 CHECK_EQ(3, args.Length());
7310 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7311 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7312 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7313 CHECK_EQ(v8::Undefined(isolate), args[3]);
7314 v8::HandleScope scope(args.GetIsolate());
7315 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7319 THREADED_TEST(Arguments) {
7320 v8::Isolate* isolate = CcTest::isolate();
7321 v8::HandleScope scope(isolate);
7322 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7323 global->Set(v8_str("f"),
7324 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7325 LocalContext context(NULL, global);
7326 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7327 v8_compile("f(1, 2, 3)")->Run();
7331 static void NoBlockGetterX(Local<String> name,
7332 const v8::PropertyCallbackInfo<v8::Value>&) {
7336 static void NoBlockGetterI(uint32_t index,
7337 const v8::PropertyCallbackInfo<v8::Value>&) {
7341 static void PDeleter(Local<String> name,
7342 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7343 if (!name->Equals(v8_str("foo"))) {
7344 return; // not intercepted
7347 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7351 static void IDeleter(uint32_t index,
7352 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7354 return; // not intercepted
7357 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7361 THREADED_TEST(Deleter) {
7362 v8::Isolate* isolate = CcTest::isolate();
7363 v8::HandleScope scope(isolate);
7364 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7365 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7366 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7367 LocalContext context;
7368 context->Global()->Set(v8_str("k"), obj->NewInstance());
7374 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7375 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7377 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7378 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7380 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7381 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7383 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7384 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7388 static void GetK(Local<String> name,
7389 const v8::PropertyCallbackInfo<v8::Value>& info) {
7390 ApiTestFuzzer::Fuzz();
7391 if (name->Equals(v8_str("foo")) ||
7392 name->Equals(v8_str("bar")) ||
7393 name->Equals(v8_str("baz"))) {
7394 info.GetReturnValue().SetUndefined();
7399 static void IndexedGetK(uint32_t index,
7400 const v8::PropertyCallbackInfo<v8::Value>& info) {
7401 ApiTestFuzzer::Fuzz();
7402 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7406 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7407 ApiTestFuzzer::Fuzz();
7408 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7409 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7410 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7411 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7412 info.GetReturnValue().Set(result);
7416 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7417 ApiTestFuzzer::Fuzz();
7418 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7419 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7420 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7421 info.GetReturnValue().Set(result);
7425 THREADED_TEST(Enumerators) {
7426 v8::Isolate* isolate = CcTest::isolate();
7427 v8::HandleScope scope(isolate);
7428 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7429 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7430 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7431 LocalContext context;
7432 context->Global()->Set(v8_str("k"), obj->NewInstance());
7433 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7438 "k[4294967295] = 0;"
7440 "k[4294967296] = 0;"
7444 "k[30000000000] = 0;"
7447 "for (var prop in k) {"
7448 " result.push(prop);"
7451 // Check that we get all the property names returned including the
7452 // ones from the enumerators in the right order: indexed properties
7453 // in numerical order, indexed interceptor properties, named
7454 // properties in insertion order, named interceptor properties.
7455 // This order is not mandated by the spec, so this test is just
7456 // documenting our behavior.
7457 CHECK_EQ(17, result->Length());
7458 // Indexed properties in numerical order.
7459 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7460 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7461 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7462 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7463 // Indexed interceptor properties in the order they are returned
7464 // from the enumerator interceptor.
7465 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7466 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7467 // Named properties in insertion order.
7468 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7469 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7470 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7471 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7472 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7473 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7474 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7475 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7476 // Named interceptor properties.
7477 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7478 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7479 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7484 int p_getter_count2;
7487 static void PGetter(Local<String> name,
7488 const v8::PropertyCallbackInfo<v8::Value>& info) {
7489 ApiTestFuzzer::Fuzz();
7491 v8::Handle<v8::Object> global =
7492 info.GetIsolate()->GetCurrentContext()->Global();
7493 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7494 if (name->Equals(v8_str("p1"))) {
7495 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7496 } else if (name->Equals(v8_str("p2"))) {
7497 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7498 } else if (name->Equals(v8_str("p3"))) {
7499 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7500 } else if (name->Equals(v8_str("p4"))) {
7501 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7506 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7507 ApiTestFuzzer::Fuzz();
7508 LocalContext context;
7509 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7511 "o1.__proto__ = { };"
7512 "var o2 = { __proto__: o1 };"
7513 "var o3 = { __proto__: o2 };"
7514 "var o4 = { __proto__: o3 };"
7515 "for (var i = 0; i < 10; i++) o4.p4;"
7516 "for (var i = 0; i < 10; i++) o3.p3;"
7517 "for (var i = 0; i < 10; i++) o2.p2;"
7518 "for (var i = 0; i < 10; i++) o1.p1;");
7522 static void PGetter2(Local<String> name,
7523 const v8::PropertyCallbackInfo<v8::Value>& info) {
7524 ApiTestFuzzer::Fuzz();
7526 v8::Handle<v8::Object> global =
7527 info.GetIsolate()->GetCurrentContext()->Global();
7528 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7529 if (name->Equals(v8_str("p1"))) {
7530 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7531 } else if (name->Equals(v8_str("p2"))) {
7532 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7533 } else if (name->Equals(v8_str("p3"))) {
7534 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7535 } else if (name->Equals(v8_str("p4"))) {
7536 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7541 THREADED_TEST(GetterHolders) {
7542 v8::Isolate* isolate = CcTest::isolate();
7543 v8::HandleScope scope(isolate);
7544 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7545 obj->SetAccessor(v8_str("p1"), PGetter);
7546 obj->SetAccessor(v8_str("p2"), PGetter);
7547 obj->SetAccessor(v8_str("p3"), PGetter);
7548 obj->SetAccessor(v8_str("p4"), PGetter);
7551 CHECK_EQ(40, p_getter_count);
7555 THREADED_TEST(PreInterceptorHolders) {
7556 v8::Isolate* isolate = CcTest::isolate();
7557 v8::HandleScope scope(isolate);
7558 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7559 obj->SetNamedPropertyHandler(PGetter2);
7560 p_getter_count2 = 0;
7562 CHECK_EQ(40, p_getter_count2);
7566 THREADED_TEST(ObjectInstantiation) {
7567 v8::Isolate* isolate = CcTest::isolate();
7568 v8::HandleScope scope(isolate);
7569 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7570 templ->SetAccessor(v8_str("t"), PGetter2);
7571 LocalContext context;
7572 context->Global()->Set(v8_str("o"), templ->NewInstance());
7573 for (int i = 0; i < 100; i++) {
7574 v8::HandleScope inner_scope(CcTest::isolate());
7575 v8::Handle<v8::Object> obj = templ->NewInstance();
7576 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7577 context->Global()->Set(v8_str("o2"), obj);
7578 v8::Handle<Value> value =
7579 CompileRun("o.__proto__ === o2.__proto__");
7580 CHECK_EQ(v8::True(isolate), value);
7581 context->Global()->Set(v8_str("o"), obj);
7586 static int StrCmp16(uint16_t* a, uint16_t* b) {
7588 if (*a == 0 && *b == 0) return 0;
7589 if (*a != *b) return 0 + *a - *b;
7596 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7598 if (n-- == 0) return 0;
7599 if (*a == 0 && *b == 0) return 0;
7600 if (*a != *b) return 0 + *a - *b;
7607 int GetUtf8Length(Handle<String> str) {
7608 int len = str->Utf8Length();
7610 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7611 i::String::Flatten(istr);
7612 len = str->Utf8Length();
7618 THREADED_TEST(StringWrite) {
7619 LocalContext context;
7620 v8::HandleScope scope(context->GetIsolate());
7621 v8::Handle<String> str = v8_str("abcde");
7622 // abc<Icelandic eth><Unicode snowman>.
7623 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7624 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7625 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7626 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7627 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7628 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7629 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7630 // single lead surrogate
7631 uint16_t lead[1] = { 0xd800 };
7632 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7633 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7634 // single trail surrogate
7635 uint16_t trail[1] = { 0xdc00 };
7636 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7637 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7639 uint16_t pair[2] = { 0xd800, 0xdc00 };
7640 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7641 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7642 const int kStride = 4; // Must match stride in for loops in JS below.
7645 "for (var i = 0; i < 0xd800; i += 4) {"
7646 " left = left + String.fromCharCode(i);"
7650 "for (var i = 0; i < 0xd800; i += 4) {"
7651 " right = String.fromCharCode(i) + right;"
7653 v8::Handle<v8::Object> global = context->Global();
7654 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7655 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7657 CHECK_EQ(5, str2->Length());
7658 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7659 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7662 char utf8buf[0xd800 * 3];
7667 memset(utf8buf, 0x1, 1000);
7668 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7670 CHECK_EQ(5, charlen);
7671 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7673 memset(utf8buf, 0x1, 1000);
7674 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7676 CHECK_EQ(5, charlen);
7677 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7679 memset(utf8buf, 0x1, 1000);
7680 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7682 CHECK_EQ(4, charlen);
7683 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7685 memset(utf8buf, 0x1, 1000);
7686 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7688 CHECK_EQ(4, charlen);
7689 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7691 memset(utf8buf, 0x1, 1000);
7692 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7694 CHECK_EQ(4, charlen);
7695 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7697 memset(utf8buf, 0x1, 1000);
7698 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7700 CHECK_EQ(3, charlen);
7701 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7703 memset(utf8buf, 0x1, 1000);
7704 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7706 CHECK_EQ(3, charlen);
7707 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7709 memset(utf8buf, 0x1, 1000);
7710 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7712 CHECK_EQ(2, charlen);
7713 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7715 // allow orphan surrogates by default
7716 memset(utf8buf, 0x1, 1000);
7717 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7719 CHECK_EQ(8, charlen);
7720 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7722 // replace orphan surrogates with unicode replacement character
7723 memset(utf8buf, 0x1, 1000);
7724 len = orphans_str->WriteUtf8(utf8buf,
7727 String::REPLACE_INVALID_UTF8);
7729 CHECK_EQ(8, charlen);
7730 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7732 // replace single lead surrogate with unicode replacement character
7733 memset(utf8buf, 0x1, 1000);
7734 len = lead_str->WriteUtf8(utf8buf,
7737 String::REPLACE_INVALID_UTF8);
7739 CHECK_EQ(1, charlen);
7740 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7742 // replace single trail surrogate with unicode replacement character
7743 memset(utf8buf, 0x1, 1000);
7744 len = trail_str->WriteUtf8(utf8buf,
7747 String::REPLACE_INVALID_UTF8);
7749 CHECK_EQ(1, charlen);
7750 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7752 // do not replace / write anything if surrogate pair does not fit the buffer
7754 memset(utf8buf, 0x1, 1000);
7755 len = pair_str->WriteUtf8(utf8buf,
7758 String::REPLACE_INVALID_UTF8);
7760 CHECK_EQ(0, charlen);
7762 memset(utf8buf, 0x1, sizeof(utf8buf));
7763 len = GetUtf8Length(left_tree);
7765 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7766 CHECK_EQ(utf8_expected, len);
7767 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7768 CHECK_EQ(utf8_expected, len);
7769 CHECK_EQ(0xd800 / kStride, charlen);
7770 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7771 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7772 CHECK_EQ(0xc0 - kStride,
7773 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7774 CHECK_EQ(1, utf8buf[utf8_expected]);
7776 memset(utf8buf, 0x1, sizeof(utf8buf));
7777 len = GetUtf8Length(right_tree);
7778 CHECK_EQ(utf8_expected, len);
7779 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7780 CHECK_EQ(utf8_expected, len);
7781 CHECK_EQ(0xd800 / kStride, charlen);
7782 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7783 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7784 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7785 CHECK_EQ(1, utf8buf[utf8_expected]);
7787 memset(buf, 0x1, sizeof(buf));
7788 memset(wbuf, 0x1, sizeof(wbuf));
7789 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7791 len = str->Write(wbuf);
7793 CHECK_EQ(0, strcmp("abcde", buf));
7794 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7795 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7797 memset(buf, 0x1, sizeof(buf));
7798 memset(wbuf, 0x1, sizeof(wbuf));
7799 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7801 len = str->Write(wbuf, 0, 4);
7803 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7804 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7805 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7807 memset(buf, 0x1, sizeof(buf));
7808 memset(wbuf, 0x1, sizeof(wbuf));
7809 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7811 len = str->Write(wbuf, 0, 5);
7813 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7814 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7815 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7817 memset(buf, 0x1, sizeof(buf));
7818 memset(wbuf, 0x1, sizeof(wbuf));
7819 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7821 len = str->Write(wbuf, 0, 6);
7823 CHECK_EQ(0, strcmp("abcde", buf));
7824 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7825 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7827 memset(buf, 0x1, sizeof(buf));
7828 memset(wbuf, 0x1, sizeof(wbuf));
7829 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7831 len = str->Write(wbuf, 4, -1);
7833 CHECK_EQ(0, strcmp("e", buf));
7834 uint16_t answer5[] = {'e', '\0'};
7835 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7837 memset(buf, 0x1, sizeof(buf));
7838 memset(wbuf, 0x1, sizeof(wbuf));
7839 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7841 len = str->Write(wbuf, 4, 6);
7843 CHECK_EQ(0, strcmp("e", buf));
7844 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7846 memset(buf, 0x1, sizeof(buf));
7847 memset(wbuf, 0x1, sizeof(wbuf));
7848 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7850 len = str->Write(wbuf, 4, 1);
7852 CHECK_EQ(0, strncmp("e\1", buf, 2));
7853 uint16_t answer6[] = {'e', 0x101};
7854 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7856 memset(buf, 0x1, sizeof(buf));
7857 memset(wbuf, 0x1, sizeof(wbuf));
7858 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7860 len = str->Write(wbuf, 3, 1);
7862 CHECK_EQ(0, strncmp("d\1", buf, 2));
7863 uint16_t answer7[] = {'d', 0x101};
7864 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7866 memset(wbuf, 0x1, sizeof(wbuf));
7868 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7870 CHECK_EQ('X', wbuf[5]);
7871 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7872 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7873 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7874 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7876 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7878 memset(buf, 0x1, sizeof(buf));
7880 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7883 String::NO_NULL_TERMINATION);
7885 CHECK_EQ('X', buf[5]);
7886 CHECK_EQ(0, strncmp("abcde", buf, 5));
7887 CHECK_NE(0, strcmp("abcde", buf));
7889 CHECK_EQ(0, strcmp("abcde", buf));
7891 memset(utf8buf, 0x1, sizeof(utf8buf));
7893 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7894 String::NO_NULL_TERMINATION);
7896 CHECK_EQ('X', utf8buf[8]);
7897 CHECK_EQ(5, charlen);
7898 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7899 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7901 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7903 memset(utf8buf, 0x1, sizeof(utf8buf));
7905 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7906 String::NO_NULL_TERMINATION);
7908 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7909 CHECK_EQ(5, charlen);
7911 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7913 memset(buf, 0x1, sizeof(buf));
7914 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7916 CHECK_EQ(0, strcmp("abc", buf));
7917 CHECK_EQ(0, buf[3]);
7918 CHECK_EQ(0, strcmp("def", buf + 4));
7920 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7921 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7922 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7926 static void Utf16Helper(
7927 LocalContext& context,
7929 const char* lengths_name,
7931 Local<v8::Array> a =
7932 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7933 Local<v8::Array> alens =
7934 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7935 for (int i = 0; i < len; i++) {
7936 Local<v8::String> string =
7937 Local<v8::String>::Cast(a->Get(i));
7938 Local<v8::Number> expected_len =
7939 Local<v8::Number>::Cast(alens->Get(i));
7940 int length = GetUtf8Length(string);
7941 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7946 static uint16_t StringGet(Handle<String> str, int index) {
7947 i::Handle<i::String> istring =
7948 v8::Utils::OpenHandle(String::Cast(*str));
7949 return istring->Get(index);
7953 static void WriteUtf8Helper(
7954 LocalContext& context,
7956 const char* lengths_name,
7958 Local<v8::Array> b =
7959 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7960 Local<v8::Array> alens =
7961 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7964 for (int i = 0; i < len; i++) {
7965 Local<v8::String> string =
7966 Local<v8::String>::Cast(b->Get(i));
7967 Local<v8::Number> expected_len =
7968 Local<v8::Number>::Cast(alens->Get(i));
7969 int utf8_length = static_cast<int>(expected_len->Value());
7970 for (int j = utf8_length + 1; j >= 0; j--) {
7971 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7972 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7975 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7977 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7978 CHECK_GE(utf8_length + 1, utf8_written);
7979 CHECK_GE(utf8_length, utf8_written2);
7980 for (int k = 0; k < utf8_written2; k++) {
7981 CHECK_EQ(buffer[k], buffer2[k]);
7983 CHECK(nchars * 3 >= utf8_written - 1);
7984 CHECK(nchars <= utf8_written);
7985 if (j == utf8_length + 1) {
7986 CHECK_EQ(utf8_written2, utf8_length);
7987 CHECK_EQ(utf8_written2 + 1, utf8_written);
7989 CHECK_EQ(buffer[utf8_written], 42);
7990 if (j > utf8_length) {
7991 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7992 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7993 Handle<String> roundtrip = v8_str(buffer);
7994 CHECK(roundtrip->Equals(string));
7996 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7998 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8000 uint16_t trail = StringGet(string, nchars - 1);
8001 uint16_t lead = StringGet(string, nchars - 2);
8002 if (((lead & 0xfc00) == 0xd800) &&
8003 ((trail & 0xfc00) == 0xdc00)) {
8004 unsigned char u1 = buffer2[utf8_written2 - 4];
8005 unsigned char u2 = buffer2[utf8_written2 - 3];
8006 unsigned char u3 = buffer2[utf8_written2 - 2];
8007 unsigned char u4 = buffer2[utf8_written2 - 1];
8008 CHECK_EQ((u1 & 0xf8), 0xf0);
8009 CHECK_EQ((u2 & 0xc0), 0x80);
8010 CHECK_EQ((u3 & 0xc0), 0x80);
8011 CHECK_EQ((u4 & 0xc0), 0x80);
8012 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8013 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8014 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8015 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8016 CHECK_EQ((u1 & 0x3), c >> 18);
8024 THREADED_TEST(Utf16) {
8025 LocalContext context;
8026 v8::HandleScope scope(context->GetIsolate());
8028 "var pad = '01234567890123456789';"
8030 "var plens = [20, 3, 3];"
8031 "p.push('01234567890123456789');"
8032 "var lead = 0xd800;"
8033 "var trail = 0xdc00;"
8034 "p.push(String.fromCharCode(0xd800));"
8035 "p.push(String.fromCharCode(0xdc00));"
8040 "for (var i = 0; i < 3; i++) {"
8041 " p[1] = String.fromCharCode(lead++);"
8042 " for (var j = 0; j < 3; j++) {"
8043 " p[2] = String.fromCharCode(trail++);"
8044 " a.push(p[i] + p[j]);"
8045 " b.push(p[i] + p[j]);"
8046 " c.push(p[i] + p[j]);"
8047 " alens.push(plens[i] + plens[j]);"
8050 "alens[5] -= 2;" // Here the surrogate pairs match up.
8055 "for (var m = 0; m < 9; m++) {"
8056 " for (var n = 0; n < 9; n++) {"
8057 " a2.push(a[m] + a[n]);"
8058 " b2.push(b[m] + b[n]);"
8059 " var newc = 'x' + c[m] + c[n] + 'y';"
8060 " c2.push(newc.substring(1, newc.length - 1));"
8061 " var utf = alens[m] + alens[n];" // And here.
8062 // The 'n's that start with 0xdc.. are 6-8
8063 // The 'm's that end with 0xd8.. are 1, 4 and 7
8064 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8065 " a2lens.push(utf);"
8068 Utf16Helper(context, "a", "alens", 9);
8069 Utf16Helper(context, "a2", "a2lens", 81);
8070 WriteUtf8Helper(context, "b", "alens", 9);
8071 WriteUtf8Helper(context, "b2", "a2lens", 81);
8072 WriteUtf8Helper(context, "c2", "a2lens", 81);
8076 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8077 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8078 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8079 return *is1 == *is2;
8082 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8084 Handle<String> symbol1 =
8085 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8086 Handle<String> symbol2 =
8087 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8088 CHECK(SameSymbol(symbol1, symbol2));
8092 THREADED_TEST(Utf16Symbol) {
8093 LocalContext context;
8094 v8::HandleScope scope(context->GetIsolate());
8096 Handle<String> symbol1 = v8::String::NewFromUtf8(
8097 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8098 Handle<String> symbol2 = v8::String::NewFromUtf8(
8099 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8100 CHECK(SameSymbol(symbol1, symbol2));
8102 SameSymbolHelper(context->GetIsolate(),
8103 "\360\220\220\205", // 4 byte encoding.
8104 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8105 SameSymbolHelper(context->GetIsolate(),
8106 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8107 "\360\220\220\206"); // 4 byte encoding.
8108 SameSymbolHelper(context->GetIsolate(),
8109 "x\360\220\220\205", // 4 byte encoding.
8110 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8111 SameSymbolHelper(context->GetIsolate(),
8112 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8113 "x\360\220\220\206"); // 4 byte encoding.
8115 "var sym0 = 'benedictus';"
8116 "var sym0b = 'S\303\270ren';"
8117 "var sym1 = '\355\240\201\355\260\207';"
8118 "var sym2 = '\360\220\220\210';"
8119 "var sym3 = 'x\355\240\201\355\260\207';"
8120 "var sym4 = 'x\360\220\220\210';"
8121 "if (sym1.length != 2) throw sym1;"
8122 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8123 "if (sym2.length != 2) throw sym2;"
8124 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8125 "if (sym3.length != 3) throw sym3;"
8126 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8127 "if (sym4.length != 3) throw sym4;"
8128 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8129 Handle<String> sym0 = v8::String::NewFromUtf8(
8130 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8131 Handle<String> sym0b = v8::String::NewFromUtf8(
8132 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8133 Handle<String> sym1 =
8134 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8135 v8::String::kInternalizedString);
8136 Handle<String> sym2 =
8137 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8138 v8::String::kInternalizedString);
8139 Handle<String> sym3 = v8::String::NewFromUtf8(
8140 context->GetIsolate(), "x\355\240\201\355\260\207",
8141 v8::String::kInternalizedString);
8142 Handle<String> sym4 =
8143 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8144 v8::String::kInternalizedString);
8145 v8::Local<v8::Object> global = context->Global();
8146 Local<Value> s0 = global->Get(v8_str("sym0"));
8147 Local<Value> s0b = global->Get(v8_str("sym0b"));
8148 Local<Value> s1 = global->Get(v8_str("sym1"));
8149 Local<Value> s2 = global->Get(v8_str("sym2"));
8150 Local<Value> s3 = global->Get(v8_str("sym3"));
8151 Local<Value> s4 = global->Get(v8_str("sym4"));
8152 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8153 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8154 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8155 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8156 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8157 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8161 THREADED_TEST(ToArrayIndex) {
8162 LocalContext context;
8163 v8::Isolate* isolate = context->GetIsolate();
8164 v8::HandleScope scope(isolate);
8166 v8::Handle<String> str = v8_str("42");
8167 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8168 CHECK(!index.IsEmpty());
8169 CHECK_EQ(42.0, index->Uint32Value());
8170 str = v8_str("42asdf");
8171 index = str->ToArrayIndex();
8172 CHECK(index.IsEmpty());
8173 str = v8_str("-42");
8174 index = str->ToArrayIndex();
8175 CHECK(index.IsEmpty());
8176 str = v8_str("4294967295");
8177 index = str->ToArrayIndex();
8178 CHECK(!index.IsEmpty());
8179 CHECK_EQ(4294967295.0, index->Uint32Value());
8180 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8181 index = num->ToArrayIndex();
8182 CHECK(!index.IsEmpty());
8183 CHECK_EQ(1.0, index->Uint32Value());
8184 num = v8::Number::New(isolate, -1);
8185 index = num->ToArrayIndex();
8186 CHECK(index.IsEmpty());
8187 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8188 index = obj->ToArrayIndex();
8189 CHECK(index.IsEmpty());
8193 THREADED_TEST(ErrorConstruction) {
8194 LocalContext context;
8195 v8::HandleScope scope(context->GetIsolate());
8197 v8::Handle<String> foo = v8_str("foo");
8198 v8::Handle<String> message = v8_str("message");
8199 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8200 CHECK(range_error->IsObject());
8201 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8202 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8203 CHECK(reference_error->IsObject());
8204 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8205 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8206 CHECK(syntax_error->IsObject());
8207 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8208 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8209 CHECK(type_error->IsObject());
8210 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8211 v8::Handle<Value> error = v8::Exception::Error(foo);
8212 CHECK(error->IsObject());
8213 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8217 static void YGetter(Local<String> name,
8218 const v8::PropertyCallbackInfo<v8::Value>& info) {
8219 ApiTestFuzzer::Fuzz();
8220 info.GetReturnValue().Set(v8_num(10));
8224 static void YSetter(Local<String> name,
8226 const v8::PropertyCallbackInfo<void>& info) {
8227 Local<Object> this_obj = Local<Object>::Cast(info.This());
8228 if (this_obj->Has(name)) this_obj->Delete(name);
8229 this_obj->Set(name, value);
8233 THREADED_TEST(DeleteAccessor) {
8234 v8::Isolate* isolate = CcTest::isolate();
8235 v8::HandleScope scope(isolate);
8236 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8237 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8238 LocalContext context;
8239 v8::Handle<v8::Object> holder = obj->NewInstance();
8240 context->Global()->Set(v8_str("holder"), holder);
8241 v8::Handle<Value> result = CompileRun(
8242 "holder.y = 11; holder.y = 12; holder.y");
8243 CHECK_EQ(12, result->Uint32Value());
8247 THREADED_TEST(TypeSwitch) {
8248 v8::Isolate* isolate = CcTest::isolate();
8249 v8::HandleScope scope(isolate);
8250 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8251 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8252 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8253 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8254 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8255 LocalContext context;
8256 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8257 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8258 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8259 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8260 for (int i = 0; i < 10; i++) {
8261 CHECK_EQ(0, type_switch->match(obj0));
8262 CHECK_EQ(1, type_switch->match(obj1));
8263 CHECK_EQ(2, type_switch->match(obj2));
8264 CHECK_EQ(3, type_switch->match(obj3));
8265 CHECK_EQ(3, type_switch->match(obj3));
8266 CHECK_EQ(2, type_switch->match(obj2));
8267 CHECK_EQ(1, type_switch->match(obj1));
8268 CHECK_EQ(0, type_switch->match(obj0));
8273 static int trouble_nesting = 0;
8274 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8275 ApiTestFuzzer::Fuzz();
8278 // Call a JS function that throws an uncaught exception.
8279 Local<v8::Object> arg_this =
8280 args.GetIsolate()->GetCurrentContext()->Global();
8281 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8282 arg_this->Get(v8_str("trouble_callee")) :
8283 arg_this->Get(v8_str("trouble_caller"));
8284 CHECK(trouble_callee->IsFunction());
8285 args.GetReturnValue().Set(
8286 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8290 static int report_count = 0;
8291 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8292 v8::Handle<Value>) {
8297 // Counts uncaught exceptions, but other tests running in parallel
8298 // also have uncaught exceptions.
8299 TEST(ApiUncaughtException) {
8302 v8::Isolate* isolate = env->GetIsolate();
8303 v8::HandleScope scope(isolate);
8304 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8306 Local<v8::FunctionTemplate> fun =
8307 v8::FunctionTemplate::New(isolate, TroubleCallback);
8308 v8::Local<v8::Object> global = env->Global();
8309 global->Set(v8_str("trouble"), fun->GetFunction());
8312 "function trouble_callee() {"
8316 "function trouble_caller() {"
8319 Local<Value> trouble = global->Get(v8_str("trouble"));
8320 CHECK(trouble->IsFunction());
8321 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8322 CHECK(trouble_callee->IsFunction());
8323 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8324 CHECK(trouble_caller->IsFunction());
8325 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8326 CHECK_EQ(1, report_count);
8327 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8330 static const char* script_resource_name = "ExceptionInNativeScript.js";
8331 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8332 v8::Handle<Value>) {
8333 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8334 CHECK(!name_val.IsEmpty() && name_val->IsString());
8335 v8::String::Utf8Value name(message->GetScriptResourceName());
8336 CHECK_EQ(script_resource_name, *name);
8337 CHECK_EQ(3, message->GetLineNumber());
8338 v8::String::Utf8Value source_line(message->GetSourceLine());
8339 CHECK_EQ(" new o.foo();", *source_line);
8343 TEST(ExceptionInNativeScript) {
8345 v8::Isolate* isolate = env->GetIsolate();
8346 v8::HandleScope scope(isolate);
8347 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8349 Local<v8::FunctionTemplate> fun =
8350 v8::FunctionTemplate::New(isolate, TroubleCallback);
8351 v8::Local<v8::Object> global = env->Global();
8352 global->Set(v8_str("trouble"), fun->GetFunction());
8354 CompileRunWithOrigin(
8355 "function trouble() {\n"
8359 script_resource_name);
8360 Local<Value> trouble = global->Get(v8_str("trouble"));
8361 CHECK(trouble->IsFunction());
8362 Function::Cast(*trouble)->Call(global, 0, NULL);
8363 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8367 TEST(CompilationErrorUsingTryCatchHandler) {
8369 v8::HandleScope scope(env->GetIsolate());
8370 v8::TryCatch try_catch;
8371 v8_compile("This doesn't &*&@#$&*^ compile.");
8372 CHECK_NE(NULL, *try_catch.Exception());
8373 CHECK(try_catch.HasCaught());
8377 TEST(TryCatchFinallyUsingTryCatchHandler) {
8379 v8::HandleScope scope(env->GetIsolate());
8380 v8::TryCatch try_catch;
8381 CompileRun("try { throw ''; } catch (e) {}");
8382 CHECK(!try_catch.HasCaught());
8383 CompileRun("try { throw ''; } finally {}");
8384 CHECK(try_catch.HasCaught());
8388 "try { throw ''; } finally { return; }"
8390 CHECK(!try_catch.HasCaught());
8393 " { try { throw ''; } finally { throw 0; }"
8395 CHECK(try_catch.HasCaught());
8399 // For use within the TestSecurityHandler() test.
8400 static bool g_security_callback_result = false;
8401 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8403 v8::AccessType type,
8404 Local<Value> data) {
8406 // Always allow read access.
8407 if (type == v8::ACCESS_GET)
8410 // Sometimes allow other access.
8411 return g_security_callback_result;
8415 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8417 v8::AccessType type,
8418 Local<Value> data) {
8420 // Always allow read access.
8421 if (type == v8::ACCESS_GET)
8424 // Sometimes allow other access.
8425 return g_security_callback_result;
8429 // SecurityHandler can't be run twice
8430 TEST(SecurityHandler) {
8431 v8::Isolate* isolate = CcTest::isolate();
8432 v8::HandleScope scope0(isolate);
8433 v8::Handle<v8::ObjectTemplate> global_template =
8434 v8::ObjectTemplate::New(isolate);
8435 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8436 IndexedSecurityTestCallback);
8437 // Create an environment
8438 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8441 v8::Handle<v8::Object> global0 = context0->Global();
8442 v8::Handle<Script> script0 = v8_compile("foo = 111");
8444 global0->Set(v8_str("0"), v8_num(999));
8445 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8446 CHECK_EQ(111, foo0->Int32Value());
8447 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8448 CHECK_EQ(999, z0->Int32Value());
8450 // Create another environment, should fail security checks.
8451 v8::HandleScope scope1(isolate);
8453 v8::Handle<Context> context1 =
8454 Context::New(isolate, NULL, global_template);
8457 v8::Handle<v8::Object> global1 = context1->Global();
8458 global1->Set(v8_str("othercontext"), global0);
8459 // This set will fail the security check.
8460 v8::Handle<Script> script1 =
8461 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8463 // This read will pass the security check.
8464 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8465 CHECK_EQ(111, foo1->Int32Value());
8466 // This read will pass the security check.
8467 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8468 CHECK_EQ(999, z1->Int32Value());
8470 // Create another environment, should pass security checks.
8471 { g_security_callback_result = true; // allow security handler to pass.
8472 v8::HandleScope scope2(isolate);
8473 LocalContext context2;
8474 v8::Handle<v8::Object> global2 = context2->Global();
8475 global2->Set(v8_str("othercontext"), global0);
8476 v8::Handle<Script> script2 =
8477 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8479 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8480 CHECK_EQ(333, foo2->Int32Value());
8481 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8482 CHECK_EQ(888, z2->Int32Value());
8490 THREADED_TEST(SecurityChecks) {
8492 v8::HandleScope handle_scope(env1->GetIsolate());
8493 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8495 Local<Value> foo = v8_str("foo");
8496 Local<Value> bar = v8_str("bar");
8498 // Set to the same domain.
8499 env1->SetSecurityToken(foo);
8501 // Create a function in env1.
8502 CompileRun("spy=function(){return spy;}");
8503 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8504 CHECK(spy->IsFunction());
8506 // Create another function accessing global objects.
8507 CompileRun("spy2=function(){return new this.Array();}");
8508 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8509 CHECK(spy2->IsFunction());
8511 // Switch to env2 in the same domain and invoke spy on env2.
8513 env2->SetSecurityToken(foo);
8515 Context::Scope scope_env2(env2);
8516 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8517 CHECK(result->IsFunction());
8521 env2->SetSecurityToken(bar);
8522 Context::Scope scope_env2(env2);
8524 // Call cross_domain_call, it should throw an exception
8525 v8::TryCatch try_catch;
8526 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8527 CHECK(try_catch.HasCaught());
8532 // Regression test case for issue 1183439.
8533 THREADED_TEST(SecurityChecksForPrototypeChain) {
8534 LocalContext current;
8535 v8::HandleScope scope(current->GetIsolate());
8536 v8::Handle<Context> other = Context::New(current->GetIsolate());
8538 // Change context to be able to get to the Object function in the
8539 // other context without hitting the security checks.
8540 v8::Local<Value> other_object;
8541 { Context::Scope scope(other);
8542 other_object = other->Global()->Get(v8_str("Object"));
8543 other->Global()->Set(v8_num(42), v8_num(87));
8546 current->Global()->Set(v8_str("other"), other->Global());
8547 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8549 // Make sure the security check fails here and we get an undefined
8550 // result instead of getting the Object function. Repeat in a loop
8551 // to make sure to exercise the IC code.
8552 v8::Local<Script> access_other0 = v8_compile("other.Object");
8553 v8::Local<Script> access_other1 = v8_compile("other[42]");
8554 for (int i = 0; i < 5; i++) {
8555 CHECK(!access_other0->Run()->Equals(other_object));
8556 CHECK(access_other0->Run()->IsUndefined());
8557 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8558 CHECK(access_other1->Run()->IsUndefined());
8561 // Create an object that has 'other' in its prototype chain and make
8562 // sure we cannot access the Object function indirectly through
8563 // that. Repeat in a loop to make sure to exercise the IC code.
8564 v8_compile("function F() { };"
8565 "F.prototype = other;"
8566 "var f = new F();")->Run();
8567 v8::Local<Script> access_f0 = v8_compile("f.Object");
8568 v8::Local<Script> access_f1 = v8_compile("f[42]");
8569 for (int j = 0; j < 5; j++) {
8570 CHECK(!access_f0->Run()->Equals(other_object));
8571 CHECK(access_f0->Run()->IsUndefined());
8572 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8573 CHECK(access_f1->Run()->IsUndefined());
8576 // Now it gets hairy: Set the prototype for the other global object
8577 // to be the current global object. The prototype chain for 'f' now
8578 // goes through 'other' but ends up in the current global object.
8579 { Context::Scope scope(other);
8580 other->Global()->Set(v8_str("__proto__"), current->Global());
8582 // Set a named and an index property on the current global
8583 // object. To force the lookup to go through the other global object,
8584 // the properties must not exist in the other global object.
8585 current->Global()->Set(v8_str("foo"), v8_num(100));
8586 current->Global()->Set(v8_num(99), v8_num(101));
8587 // Try to read the properties from f and make sure that the access
8588 // gets stopped by the security checks on the other global object.
8589 Local<Script> access_f2 = v8_compile("f.foo");
8590 Local<Script> access_f3 = v8_compile("f[99]");
8591 for (int k = 0; k < 5; k++) {
8592 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8593 CHECK(access_f2->Run()->IsUndefined());
8594 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8595 CHECK(access_f3->Run()->IsUndefined());
8600 static bool named_security_check_with_gc_called;
8602 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8604 v8::AccessType type,
8605 Local<Value> data) {
8606 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8607 named_security_check_with_gc_called = true;
8612 static bool indexed_security_check_with_gc_called;
8614 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8616 v8::AccessType type,
8617 Local<Value> data) {
8618 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8619 indexed_security_check_with_gc_called = true;
8624 TEST(SecurityTestGCAllowed) {
8625 v8::Isolate* isolate = CcTest::isolate();
8626 v8::HandleScope handle_scope(isolate);
8627 v8::Handle<v8::ObjectTemplate> object_template =
8628 v8::ObjectTemplate::New(isolate);
8629 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8630 IndexedSecurityTestCallbackWithGC);
8632 v8::Handle<Context> context = Context::New(isolate);
8633 v8::Context::Scope context_scope(context);
8635 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8637 named_security_check_with_gc_called = false;
8638 CompileRun("obj.foo = new String(1001);");
8639 CHECK(named_security_check_with_gc_called);
8641 indexed_security_check_with_gc_called = false;
8642 CompileRun("obj[0] = new String(1002);");
8643 CHECK(indexed_security_check_with_gc_called);
8645 named_security_check_with_gc_called = false;
8646 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8647 CHECK(named_security_check_with_gc_called);
8649 indexed_security_check_with_gc_called = false;
8650 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8651 CHECK(indexed_security_check_with_gc_called);
8655 THREADED_TEST(CrossDomainDelete) {
8657 v8::HandleScope handle_scope(env1->GetIsolate());
8658 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8660 Local<Value> foo = v8_str("foo");
8661 Local<Value> bar = v8_str("bar");
8663 // Set to the same domain.
8664 env1->SetSecurityToken(foo);
8665 env2->SetSecurityToken(foo);
8667 env1->Global()->Set(v8_str("prop"), v8_num(3));
8668 env2->Global()->Set(v8_str("env1"), env1->Global());
8670 // Change env2 to a different domain and delete env1.prop.
8671 env2->SetSecurityToken(bar);
8673 Context::Scope scope_env2(env2);
8674 Local<Value> result =
8675 CompileRun("delete env1.prop");
8676 CHECK(result->IsFalse());
8679 // Check that env1.prop still exists.
8680 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8681 CHECK(v->IsNumber());
8682 CHECK_EQ(3, v->Int32Value());
8686 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8688 v8::HandleScope handle_scope(env1->GetIsolate());
8689 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8691 Local<Value> foo = v8_str("foo");
8692 Local<Value> bar = v8_str("bar");
8694 // Set to the same domain.
8695 env1->SetSecurityToken(foo);
8696 env2->SetSecurityToken(foo);
8698 env1->Global()->Set(v8_str("prop"), v8_num(3));
8699 env2->Global()->Set(v8_str("env1"), env1->Global());
8701 // env1.prop is enumerable in env2.
8702 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8704 Context::Scope scope_env2(env2);
8705 Local<Value> result = CompileRun(test);
8706 CHECK(result->IsTrue());
8709 // Change env2 to a different domain and test again.
8710 env2->SetSecurityToken(bar);
8712 Context::Scope scope_env2(env2);
8713 Local<Value> result = CompileRun(test);
8714 CHECK(result->IsFalse());
8719 THREADED_TEST(CrossDomainForIn) {
8721 v8::HandleScope handle_scope(env1->GetIsolate());
8722 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8724 Local<Value> foo = v8_str("foo");
8725 Local<Value> bar = v8_str("bar");
8727 // Set to the same domain.
8728 env1->SetSecurityToken(foo);
8729 env2->SetSecurityToken(foo);
8731 env1->Global()->Set(v8_str("prop"), v8_num(3));
8732 env2->Global()->Set(v8_str("env1"), env1->Global());
8734 // Change env2 to a different domain and set env1's global object
8735 // as the __proto__ of an object in env2 and enumerate properties
8736 // in for-in. It shouldn't enumerate properties on env1's global
8738 env2->SetSecurityToken(bar);
8740 Context::Scope scope_env2(env2);
8741 Local<Value> result =
8742 CompileRun("(function(){var obj = {'__proto__':env1};"
8743 "for (var p in obj)"
8744 " if (p == 'prop') return false;"
8745 "return true;})()");
8746 CHECK(result->IsTrue());
8751 TEST(ContextDetachGlobal) {
8753 v8::HandleScope handle_scope(env1->GetIsolate());
8754 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8756 Local<v8::Object> global1 = env1->Global();
8758 Local<Value> foo = v8_str("foo");
8760 // Set to the same domain.
8761 env1->SetSecurityToken(foo);
8762 env2->SetSecurityToken(foo);
8767 // Create a function in env2 and add a reference to it in env1.
8768 Local<v8::Object> global2 = env2->Global();
8769 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8770 CompileRun("function getProp() {return prop;}");
8772 env1->Global()->Set(v8_str("getProp"),
8773 global2->Get(v8_str("getProp")));
8775 // Detach env2's global, and reuse the global object of env2
8777 env2->DetachGlobal();
8779 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8781 v8::Handle<v8::ObjectTemplate>(),
8783 env3->SetSecurityToken(v8_str("bar"));
8786 Local<v8::Object> global3 = env3->Global();
8787 CHECK_EQ(global2, global3);
8788 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8789 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8790 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8791 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8794 // Call getProp in env1, and it should return the value 1
8796 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8797 CHECK(get_prop->IsFunction());
8798 v8::TryCatch try_catch;
8799 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8800 CHECK(!try_catch.HasCaught());
8801 CHECK_EQ(1, r->Int32Value());
8804 // Check that env3 is not accessible from env1
8806 Local<Value> r = global3->Get(v8_str("prop2"));
8807 CHECK(r->IsUndefined());
8812 TEST(DetachGlobal) {
8814 v8::HandleScope scope(env1->GetIsolate());
8816 // Create second environment.
8817 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8819 Local<Value> foo = v8_str("foo");
8821 // Set same security token for env1 and env2.
8822 env1->SetSecurityToken(foo);
8823 env2->SetSecurityToken(foo);
8825 // Create a property on the global object in env2.
8827 v8::Context::Scope scope(env2);
8828 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8831 // Create a reference to env2 global from env1 global.
8832 env1->Global()->Set(v8_str("other"), env2->Global());
8834 // Check that we have access to other.p in env2 from env1.
8835 Local<Value> result = CompileRun("other.p");
8836 CHECK(result->IsInt32());
8837 CHECK_EQ(42, result->Int32Value());
8839 // Hold on to global from env2 and detach global from env2.
8840 Local<v8::Object> global2 = env2->Global();
8841 env2->DetachGlobal();
8843 // Check that the global has been detached. No other.p property can
8845 result = CompileRun("other.p");
8846 CHECK(result->IsUndefined());
8848 // Reuse global2 for env3.
8849 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8851 v8::Handle<v8::ObjectTemplate>(),
8853 CHECK_EQ(global2, env3->Global());
8855 // Start by using the same security token for env3 as for env1 and env2.
8856 env3->SetSecurityToken(foo);
8858 // Create a property on the global object in env3.
8860 v8::Context::Scope scope(env3);
8861 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8864 // Check that other.p is now the property in env3 and that we have access.
8865 result = CompileRun("other.p");
8866 CHECK(result->IsInt32());
8867 CHECK_EQ(24, result->Int32Value());
8869 // Change security token for env3 to something different from env1 and env2.
8870 env3->SetSecurityToken(v8_str("bar"));
8872 // Check that we do not have access to other.p in env1. |other| is now
8873 // the global object for env3 which has a different security token,
8874 // so access should be blocked.
8875 result = CompileRun("other.p");
8876 CHECK(result->IsUndefined());
8880 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8881 info.GetReturnValue().Set(
8882 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8886 TEST(DetachedAccesses) {
8888 v8::HandleScope scope(env1->GetIsolate());
8890 // Create second environment.
8891 Local<ObjectTemplate> inner_global_template =
8892 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8893 inner_global_template ->SetAccessorProperty(
8894 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8895 v8::Local<Context> env2 =
8896 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8898 Local<Value> foo = v8_str("foo");
8900 // Set same security token for env1 and env2.
8901 env1->SetSecurityToken(foo);
8902 env2->SetSecurityToken(foo);
8904 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8907 v8::Context::Scope scope(env2);
8908 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8910 "function bound_x() { return x; }"
8911 "function get_x() { return this.x; }"
8912 "function get_x_w() { return (function() {return this.x;})(); }");
8913 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8914 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8915 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8916 env1->Global()->Set(
8918 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8921 Local<Object> env2_global = env2->Global();
8922 env2_global->TurnOnAccessCheck();
8923 env2->DetachGlobal();
8925 Local<Value> result;
8926 result = CompileRun("bound_x()");
8927 CHECK_EQ(v8_str("env2_x"), result);
8928 result = CompileRun("get_x()");
8929 CHECK(result->IsUndefined());
8930 result = CompileRun("get_x_w()");
8931 CHECK(result->IsUndefined());
8932 result = CompileRun("this_x()");
8933 CHECK_EQ(v8_str("env2_x"), result);
8935 // Reattach env2's proxy
8936 env2 = Context::New(env1->GetIsolate(),
8938 v8::Handle<v8::ObjectTemplate>(),
8940 env2->SetSecurityToken(foo);
8942 v8::Context::Scope scope(env2);
8943 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8944 env2->Global()->Set(v8_str("env1"), env1->Global());
8945 result = CompileRun(
8947 "for (var i = 0; i < 4; i++ ) {"
8948 " results.push(env1.bound_x());"
8949 " results.push(env1.get_x());"
8950 " results.push(env1.get_x_w());"
8951 " results.push(env1.this_x());"
8954 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8955 CHECK_EQ(16, results->Length());
8956 for (int i = 0; i < 16; i += 4) {
8957 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8958 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8959 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8960 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8964 result = CompileRun(
8966 "for (var i = 0; i < 4; i++ ) {"
8967 " results.push(bound_x());"
8968 " results.push(get_x());"
8969 " results.push(get_x_w());"
8970 " results.push(this_x());"
8973 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8974 CHECK_EQ(16, results->Length());
8975 for (int i = 0; i < 16; i += 4) {
8976 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8977 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8978 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8979 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8982 result = CompileRun(
8984 "for (var i = 0; i < 4; i++ ) {"
8985 " results.push(this.bound_x());"
8986 " results.push(this.get_x());"
8987 " results.push(this.get_x_w());"
8988 " results.push(this.this_x());"
8991 results = Local<v8::Array>::Cast(result);
8992 CHECK_EQ(16, results->Length());
8993 for (int i = 0; i < 16; i += 4) {
8994 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8995 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8996 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8997 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9002 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9003 static bool NamedAccessBlocker(Local<v8::Object> global,
9005 v8::AccessType type,
9006 Local<Value> data) {
9007 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9008 allowed_access_type[type];
9012 static bool IndexedAccessBlocker(Local<v8::Object> global,
9014 v8::AccessType type,
9015 Local<Value> data) {
9016 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9017 allowed_access_type[type];
9021 static int g_echo_value_1 = -1;
9022 static int g_echo_value_2 = -1;
9025 static void EchoGetter(
9027 const v8::PropertyCallbackInfo<v8::Value>& info) {
9028 info.GetReturnValue().Set(v8_num(g_echo_value_1));
9032 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9033 info.GetReturnValue().Set(v8_num(g_echo_value_2));
9037 static void EchoSetter(Local<String> name,
9039 const v8::PropertyCallbackInfo<void>&) {
9040 if (value->IsNumber())
9041 g_echo_value_1 = value->Int32Value();
9045 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9046 v8::Handle<v8::Value> value = info[0];
9047 if (value->IsNumber())
9048 g_echo_value_2 = value->Int32Value();
9052 static void UnreachableGetter(
9054 const v8::PropertyCallbackInfo<v8::Value>& info) {
9055 CHECK(false); // This function should not be called..
9059 static void UnreachableSetter(Local<String>,
9061 const v8::PropertyCallbackInfo<void>&) {
9062 CHECK(false); // This function should nto be called.
9066 static void UnreachableFunction(
9067 const v8::FunctionCallbackInfo<v8::Value>& info) {
9068 CHECK(false); // This function should not be called..
9072 TEST(AccessControl) {
9073 v8::Isolate* isolate = CcTest::isolate();
9074 v8::HandleScope handle_scope(isolate);
9075 v8::Handle<v8::ObjectTemplate> global_template =
9076 v8::ObjectTemplate::New(isolate);
9078 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9079 IndexedAccessBlocker);
9081 // Add an accessor accessible by cross-domain JS code.
9082 global_template->SetAccessor(
9083 v8_str("accessible_prop"),
9084 EchoGetter, EchoSetter,
9085 v8::Handle<Value>(),
9086 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9089 global_template->SetAccessorProperty(
9090 v8_str("accessible_js_prop"),
9091 v8::FunctionTemplate::New(isolate, EchoGetter),
9092 v8::FunctionTemplate::New(isolate, EchoSetter),
9094 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9096 // Add an accessor that is not accessible by cross-domain JS code.
9097 global_template->SetAccessor(v8_str("blocked_prop"),
9098 UnreachableGetter, UnreachableSetter,
9099 v8::Handle<Value>(),
9102 global_template->SetAccessorProperty(
9103 v8_str("blocked_js_prop"),
9104 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9105 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9109 // Create an environment
9110 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9113 v8::Handle<v8::Object> global0 = context0->Global();
9115 // Define a property with JS getter and setter.
9117 "function getter() { return 'getter'; };\n"
9118 "function setter() { return 'setter'; }\n"
9119 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9121 Local<Value> getter = global0->Get(v8_str("getter"));
9122 Local<Value> setter = global0->Get(v8_str("setter"));
9124 // And define normal element.
9125 global0->Set(239, v8_str("239"));
9127 // Define an element with JS getter and setter.
9129 "function el_getter() { return 'el_getter'; };\n"
9130 "function el_setter() { return 'el_setter'; };\n"
9131 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9133 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9134 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9136 v8::HandleScope scope1(isolate);
9138 v8::Local<Context> context1 = Context::New(isolate);
9141 v8::Handle<v8::Object> global1 = context1->Global();
9142 global1->Set(v8_str("other"), global0);
9144 // Access blocked property.
9145 CompileRun("other.blocked_prop = 1");
9147 ExpectUndefined("other.blocked_prop");
9149 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9150 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9152 // Enable ACCESS_HAS
9153 allowed_access_type[v8::ACCESS_HAS] = true;
9154 ExpectUndefined("other.blocked_prop");
9155 // ... and now we can get the descriptor...
9157 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9158 // ... and enumerate the property.
9159 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9160 allowed_access_type[v8::ACCESS_HAS] = false;
9162 // Access blocked element.
9163 CompileRun("other[239] = 1");
9165 ExpectUndefined("other[239]");
9166 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9167 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9169 // Enable ACCESS_HAS
9170 allowed_access_type[v8::ACCESS_HAS] = true;
9171 ExpectUndefined("other[239]");
9172 // ... and now we can get the descriptor...
9173 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9174 // ... and enumerate the property.
9175 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9176 allowed_access_type[v8::ACCESS_HAS] = false;
9178 // Access a property with JS accessor.
9179 CompileRun("other.js_accessor_p = 2");
9181 ExpectUndefined("other.js_accessor_p");
9183 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9185 // Enable ACCESS_HAS.
9186 allowed_access_type[v8::ACCESS_HAS] = true;
9187 ExpectUndefined("other.js_accessor_p");
9189 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9191 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9193 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9194 allowed_access_type[v8::ACCESS_HAS] = false;
9196 // Enable both ACCESS_HAS and ACCESS_GET.
9197 allowed_access_type[v8::ACCESS_HAS] = true;
9198 allowed_access_type[v8::ACCESS_GET] = true;
9200 ExpectString("other.js_accessor_p", "getter");
9202 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9204 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9206 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9208 allowed_access_type[v8::ACCESS_GET] = false;
9209 allowed_access_type[v8::ACCESS_HAS] = false;
9211 // Enable both ACCESS_HAS and ACCESS_SET.
9212 allowed_access_type[v8::ACCESS_HAS] = true;
9213 allowed_access_type[v8::ACCESS_SET] = true;
9215 ExpectUndefined("other.js_accessor_p");
9217 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9219 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9221 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9223 allowed_access_type[v8::ACCESS_SET] = false;
9224 allowed_access_type[v8::ACCESS_HAS] = false;
9226 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9227 allowed_access_type[v8::ACCESS_HAS] = true;
9228 allowed_access_type[v8::ACCESS_GET] = true;
9229 allowed_access_type[v8::ACCESS_SET] = true;
9231 ExpectString("other.js_accessor_p", "getter");
9233 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9235 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9237 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9239 allowed_access_type[v8::ACCESS_SET] = false;
9240 allowed_access_type[v8::ACCESS_GET] = false;
9241 allowed_access_type[v8::ACCESS_HAS] = false;
9243 // Access an element with JS accessor.
9244 CompileRun("other[42] = 2");
9246 ExpectUndefined("other[42]");
9247 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9249 // Enable ACCESS_HAS.
9250 allowed_access_type[v8::ACCESS_HAS] = true;
9251 ExpectUndefined("other[42]");
9252 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9253 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9254 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9255 allowed_access_type[v8::ACCESS_HAS] = false;
9257 // Enable both ACCESS_HAS and ACCESS_GET.
9258 allowed_access_type[v8::ACCESS_HAS] = true;
9259 allowed_access_type[v8::ACCESS_GET] = true;
9261 ExpectString("other[42]", "el_getter");
9262 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9263 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9264 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9266 allowed_access_type[v8::ACCESS_GET] = false;
9267 allowed_access_type[v8::ACCESS_HAS] = false;
9269 // Enable both ACCESS_HAS and ACCESS_SET.
9270 allowed_access_type[v8::ACCESS_HAS] = true;
9271 allowed_access_type[v8::ACCESS_SET] = true;
9273 ExpectUndefined("other[42]");
9274 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9275 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9276 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9278 allowed_access_type[v8::ACCESS_SET] = false;
9279 allowed_access_type[v8::ACCESS_HAS] = false;
9281 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9282 allowed_access_type[v8::ACCESS_HAS] = true;
9283 allowed_access_type[v8::ACCESS_GET] = true;
9284 allowed_access_type[v8::ACCESS_SET] = true;
9286 ExpectString("other[42]", "el_getter");
9287 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9288 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9289 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9291 allowed_access_type[v8::ACCESS_SET] = false;
9292 allowed_access_type[v8::ACCESS_GET] = false;
9293 allowed_access_type[v8::ACCESS_HAS] = false;
9295 v8::Handle<Value> value;
9297 // Access accessible property
9298 value = CompileRun("other.accessible_prop = 3");
9299 CHECK(value->IsNumber());
9300 CHECK_EQ(3, value->Int32Value());
9301 CHECK_EQ(3, g_echo_value_1);
9303 // Access accessible js property
9304 value = CompileRun("other.accessible_js_prop = 3");
9305 CHECK(value->IsNumber());
9306 CHECK_EQ(3, value->Int32Value());
9307 CHECK_EQ(3, g_echo_value_2);
9309 value = CompileRun("other.accessible_prop");
9310 CHECK(value->IsNumber());
9311 CHECK_EQ(3, value->Int32Value());
9313 value = CompileRun("other.accessible_js_prop");
9314 CHECK(value->IsNumber());
9315 CHECK_EQ(3, value->Int32Value());
9318 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9319 CHECK(value->IsNumber());
9320 CHECK_EQ(3, value->Int32Value());
9323 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9324 CHECK(value->IsNumber());
9325 CHECK_EQ(3, value->Int32Value());
9327 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9328 CHECK(value->IsTrue());
9330 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9331 CHECK(value->IsTrue());
9333 // Enumeration doesn't enumerate accessors from inaccessible objects in
9334 // the prototype chain even if the accessors are in themselves accessible.
9336 CompileRun("(function(){var obj = {'__proto__':other};"
9337 "for (var p in obj)"
9338 " if (p == 'accessible_prop' ||"
9339 " p == 'accessible_js_prop' ||"
9340 " p == 'blocked_js_prop' ||"
9341 " p == 'blocked_js_prop') {"
9344 "return true;})()");
9345 CHECK(value->IsTrue());
9352 TEST(AccessControlES5) {
9353 v8::Isolate* isolate = CcTest::isolate();
9354 v8::HandleScope handle_scope(isolate);
9355 v8::Handle<v8::ObjectTemplate> global_template =
9356 v8::ObjectTemplate::New(isolate);
9358 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9359 IndexedAccessBlocker);
9361 // Add accessible accessor.
9362 global_template->SetAccessor(
9363 v8_str("accessible_prop"),
9364 EchoGetter, EchoSetter,
9365 v8::Handle<Value>(),
9366 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9369 // Add an accessor that is not accessible by cross-domain JS code.
9370 global_template->SetAccessor(v8_str("blocked_prop"),
9371 UnreachableGetter, UnreachableSetter,
9372 v8::Handle<Value>(),
9375 // Create an environment
9376 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9379 v8::Handle<v8::Object> global0 = context0->Global();
9381 v8::Local<Context> context1 = Context::New(isolate);
9383 v8::Handle<v8::Object> global1 = context1->Global();
9384 global1->Set(v8_str("other"), global0);
9386 // Regression test for issue 1154.
9387 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9389 ExpectUndefined("other.blocked_prop");
9391 // Regression test for issue 1027.
9392 CompileRun("Object.defineProperty(\n"
9393 " other, 'blocked_prop', {configurable: false})");
9394 ExpectUndefined("other.blocked_prop");
9396 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9398 // Regression test for issue 1171.
9399 ExpectTrue("Object.isExtensible(other)");
9400 CompileRun("Object.preventExtensions(other)");
9401 ExpectTrue("Object.isExtensible(other)");
9403 // Object.seal and Object.freeze.
9404 CompileRun("Object.freeze(other)");
9405 ExpectTrue("Object.isExtensible(other)");
9407 CompileRun("Object.seal(other)");
9408 ExpectTrue("Object.isExtensible(other)");
9410 // Regression test for issue 1250.
9411 // Make sure that we can set the accessible accessors value using normal
9413 CompileRun("other.accessible_prop = 42");
9414 CHECK_EQ(42, g_echo_value_1);
9416 v8::Handle<Value> value;
9417 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9418 value = CompileRun("other.accessible_prop == 42");
9419 CHECK(value->IsTrue());
9423 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9425 v8::AccessType type,
9426 Local<Value> data) {
9431 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9433 v8::AccessType type,
9434 Local<Value> data) {
9439 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9440 v8::Isolate* isolate = CcTest::isolate();
9441 v8::HandleScope handle_scope(isolate);
9442 v8::Handle<v8::ObjectTemplate> obj_template =
9443 v8::ObjectTemplate::New(isolate);
9445 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9446 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9447 GetOwnPropertyNamesIndexedBlocker);
9449 // Create an environment
9450 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9453 v8::Handle<v8::Object> global0 = context0->Global();
9455 v8::HandleScope scope1(CcTest::isolate());
9457 v8::Local<Context> context1 = Context::New(isolate);
9460 v8::Handle<v8::Object> global1 = context1->Global();
9461 global1->Set(v8_str("other"), global0);
9462 global1->Set(v8_str("object"), obj_template->NewInstance());
9464 v8::Handle<Value> value;
9466 // Attempt to get the property names of the other global object and
9467 // of an object that requires access checks. Accessing the other
9468 // global object should be blocked by access checks on the global
9469 // proxy object. Accessing the object that requires access checks
9470 // is blocked by the access checks on the object itself.
9471 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9472 CHECK(value->IsTrue());
9474 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9475 CHECK(value->IsTrue());
9482 static void IndexedPropertyEnumerator(
9483 const v8::PropertyCallbackInfo<v8::Array>& info) {
9484 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9485 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9486 result->Set(1, v8::Object::New(info.GetIsolate()));
9487 info.GetReturnValue().Set(result);
9491 static void NamedPropertyEnumerator(
9492 const v8::PropertyCallbackInfo<v8::Array>& info) {
9493 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9494 result->Set(0, v8_str("x"));
9495 result->Set(1, v8::Object::New(info.GetIsolate()));
9496 info.GetReturnValue().Set(result);
9500 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9501 v8::Isolate* isolate = CcTest::isolate();
9502 v8::HandleScope handle_scope(isolate);
9503 v8::Handle<v8::ObjectTemplate> obj_template =
9504 v8::ObjectTemplate::New(isolate);
9506 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9507 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9508 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9509 IndexedPropertyEnumerator);
9510 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9511 NamedPropertyEnumerator);
9513 LocalContext context;
9514 v8::Handle<v8::Object> global = context->Global();
9515 global->Set(v8_str("object"), obj_template->NewInstance());
9517 v8::Handle<v8::Value> result =
9518 CompileRun("Object.getOwnPropertyNames(object)");
9519 CHECK(result->IsArray());
9520 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9521 CHECK_EQ(3, result_array->Length());
9522 CHECK(result_array->Get(0)->IsString());
9523 CHECK(result_array->Get(1)->IsString());
9524 CHECK(result_array->Get(2)->IsString());
9525 CHECK_EQ(v8_str("7"), result_array->Get(0));
9526 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9527 CHECK_EQ(v8_str("x"), result_array->Get(2));
9531 static void ConstTenGetter(Local<String> name,
9532 const v8::PropertyCallbackInfo<v8::Value>& info) {
9533 info.GetReturnValue().Set(v8_num(10));
9537 THREADED_TEST(CrossDomainAccessors) {
9538 v8::Isolate* isolate = CcTest::isolate();
9539 v8::HandleScope handle_scope(isolate);
9541 v8::Handle<v8::FunctionTemplate> func_template =
9542 v8::FunctionTemplate::New(isolate);
9544 v8::Handle<v8::ObjectTemplate> global_template =
9545 func_template->InstanceTemplate();
9547 v8::Handle<v8::ObjectTemplate> proto_template =
9548 func_template->PrototypeTemplate();
9550 // Add an accessor to proto that's accessible by cross-domain JS code.
9551 proto_template->SetAccessor(v8_str("accessible"),
9553 v8::Handle<Value>(),
9556 // Add an accessor that is not accessible by cross-domain JS code.
9557 global_template->SetAccessor(v8_str("unreachable"),
9558 UnreachableGetter, 0,
9559 v8::Handle<Value>(),
9562 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9565 Local<v8::Object> global = context0->Global();
9566 // Add a normal property that shadows 'accessible'
9567 global->Set(v8_str("accessible"), v8_num(11));
9569 // Enter a new context.
9570 v8::HandleScope scope1(CcTest::isolate());
9571 v8::Local<Context> context1 = Context::New(isolate);
9574 v8::Handle<v8::Object> global1 = context1->Global();
9575 global1->Set(v8_str("other"), global);
9577 // Should return 10, instead of 11
9578 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9579 CHECK(value->IsNumber());
9580 CHECK_EQ(10, value->Int32Value());
9582 value = v8_compile("other.unreachable")->Run();
9583 CHECK(value->IsUndefined());
9590 static int named_access_count = 0;
9591 static int indexed_access_count = 0;
9593 static bool NamedAccessCounter(Local<v8::Object> global,
9595 v8::AccessType type,
9596 Local<Value> data) {
9597 named_access_count++;
9602 static bool IndexedAccessCounter(Local<v8::Object> global,
9604 v8::AccessType type,
9605 Local<Value> data) {
9606 indexed_access_count++;
9611 // This one is too easily disturbed by other tests.
9612 TEST(AccessControlIC) {
9613 named_access_count = 0;
9614 indexed_access_count = 0;
9616 v8::Isolate* isolate = CcTest::isolate();
9617 v8::HandleScope handle_scope(isolate);
9619 // Create an environment.
9620 v8::Local<Context> context0 = Context::New(isolate);
9623 // Create an object that requires access-check functions to be
9624 // called for cross-domain access.
9625 v8::Handle<v8::ObjectTemplate> object_template =
9626 v8::ObjectTemplate::New(isolate);
9627 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9628 IndexedAccessCounter);
9629 Local<v8::Object> object = object_template->NewInstance();
9631 v8::HandleScope scope1(isolate);
9633 // Create another environment.
9634 v8::Local<Context> context1 = Context::New(isolate);
9637 // Make easy access to the object from the other environment.
9638 v8::Handle<v8::Object> global1 = context1->Global();
9639 global1->Set(v8_str("obj"), object);
9641 v8::Handle<Value> value;
9643 // Check that the named access-control function is called every time.
9644 CompileRun("function testProp(obj) {"
9645 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9646 " for (var j = 0; j < 10; j++) obj.prop;"
9649 value = CompileRun("testProp(obj)");
9650 CHECK(value->IsNumber());
9651 CHECK_EQ(1, value->Int32Value());
9652 CHECK_EQ(21, named_access_count);
9654 // Check that the named access-control function is called every time.
9655 CompileRun("var p = 'prop';"
9656 "function testKeyed(obj) {"
9657 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9658 " for (var j = 0; j < 10; j++) obj[p];"
9661 // Use obj which requires access checks. No inline caching is used
9663 value = CompileRun("testKeyed(obj)");
9664 CHECK(value->IsNumber());
9665 CHECK_EQ(1, value->Int32Value());
9666 CHECK_EQ(42, named_access_count);
9667 // Force the inline caches into generic state and try again.
9668 CompileRun("testKeyed({ a: 0 })");
9669 CompileRun("testKeyed({ b: 0 })");
9670 value = CompileRun("testKeyed(obj)");
9671 CHECK(value->IsNumber());
9672 CHECK_EQ(1, value->Int32Value());
9673 CHECK_EQ(63, named_access_count);
9675 // Check that the indexed access-control function is called every time.
9676 CompileRun("function testIndexed(obj) {"
9677 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9678 " for (var j = 0; j < 10; j++) obj[0];"
9681 value = CompileRun("testIndexed(obj)");
9682 CHECK(value->IsNumber());
9683 CHECK_EQ(1, value->Int32Value());
9684 CHECK_EQ(21, indexed_access_count);
9685 // Force the inline caches into generic state.
9686 CompileRun("testIndexed(new Array(1))");
9687 // Test that the indexed access check is called.
9688 value = CompileRun("testIndexed(obj)");
9689 CHECK(value->IsNumber());
9690 CHECK_EQ(1, value->Int32Value());
9691 CHECK_EQ(42, indexed_access_count);
9693 // Check that the named access check is called when invoking
9694 // functions on an object that requires access checks.
9695 CompileRun("obj.f = function() {}");
9696 CompileRun("function testCallNormal(obj) {"
9697 " for (var i = 0; i < 10; i++) obj.f();"
9699 CompileRun("testCallNormal(obj)");
9700 CHECK_EQ(74, named_access_count);
9702 // Force obj into slow case.
9703 value = CompileRun("delete obj.prop");
9704 CHECK(value->BooleanValue());
9705 // Force inline caches into dictionary probing mode.
9706 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9707 // Test that the named access check is called.
9708 value = CompileRun("testProp(obj);");
9709 CHECK(value->IsNumber());
9710 CHECK_EQ(1, value->Int32Value());
9711 CHECK_EQ(96, named_access_count);
9713 // Force the call inline cache into dictionary probing mode.
9714 CompileRun("o.f = function() {}; testCallNormal(o)");
9715 // Test that the named access check is still called for each
9716 // invocation of the function.
9717 value = CompileRun("testCallNormal(obj)");
9718 CHECK_EQ(106, named_access_count);
9725 static bool NamedAccessFlatten(Local<v8::Object> global,
9727 v8::AccessType type,
9728 Local<Value> data) {
9732 CHECK(name->IsString());
9734 memset(buf, 0x1, sizeof(buf));
9735 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9740 memset(buf, 0x1, sizeof(buf));
9741 len = name.As<String>()->Write(buf2);
9748 static bool IndexedAccessFlatten(Local<v8::Object> global,
9750 v8::AccessType type,
9751 Local<Value> data) {
9756 // Regression test. In access checks, operations that may cause
9757 // garbage collection are not allowed. It used to be the case that
9758 // using the Write operation on a string could cause a garbage
9759 // collection due to flattening of the string. This is no longer the
9761 THREADED_TEST(AccessControlFlatten) {
9762 named_access_count = 0;
9763 indexed_access_count = 0;
9765 v8::Isolate* isolate = CcTest::isolate();
9766 v8::HandleScope handle_scope(isolate);
9768 // Create an environment.
9769 v8::Local<Context> context0 = Context::New(isolate);
9772 // Create an object that requires access-check functions to be
9773 // called for cross-domain access.
9774 v8::Handle<v8::ObjectTemplate> object_template =
9775 v8::ObjectTemplate::New(isolate);
9776 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9777 IndexedAccessFlatten);
9778 Local<v8::Object> object = object_template->NewInstance();
9780 v8::HandleScope scope1(isolate);
9782 // Create another environment.
9783 v8::Local<Context> context1 = Context::New(isolate);
9786 // Make easy access to the object from the other environment.
9787 v8::Handle<v8::Object> global1 = context1->Global();
9788 global1->Set(v8_str("obj"), object);
9790 v8::Handle<Value> value;
9792 value = v8_compile("var p = 'as' + 'df';")->Run();
9793 value = v8_compile("obj[p];")->Run();
9800 static void AccessControlNamedGetter(
9802 const v8::PropertyCallbackInfo<v8::Value>& info) {
9803 info.GetReturnValue().Set(42);
9807 static void AccessControlNamedSetter(
9810 const v8::PropertyCallbackInfo<v8::Value>& info) {
9811 info.GetReturnValue().Set(value);
9815 static void AccessControlIndexedGetter(
9817 const v8::PropertyCallbackInfo<v8::Value>& info) {
9818 info.GetReturnValue().Set(v8_num(42));
9822 static void AccessControlIndexedSetter(
9825 const v8::PropertyCallbackInfo<v8::Value>& info) {
9826 info.GetReturnValue().Set(value);
9830 THREADED_TEST(AccessControlInterceptorIC) {
9831 named_access_count = 0;
9832 indexed_access_count = 0;
9834 v8::Isolate* isolate = CcTest::isolate();
9835 v8::HandleScope handle_scope(isolate);
9837 // Create an environment.
9838 v8::Local<Context> context0 = Context::New(isolate);
9841 // Create an object that requires access-check functions to be
9842 // called for cross-domain access. The object also has interceptors
9844 v8::Handle<v8::ObjectTemplate> object_template =
9845 v8::ObjectTemplate::New(isolate);
9846 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9847 IndexedAccessCounter);
9848 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9849 AccessControlNamedSetter);
9850 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9851 AccessControlIndexedSetter);
9852 Local<v8::Object> object = object_template->NewInstance();
9854 v8::HandleScope scope1(isolate);
9856 // Create another environment.
9857 v8::Local<Context> context1 = Context::New(isolate);
9860 // Make easy access to the object from the other environment.
9861 v8::Handle<v8::Object> global1 = context1->Global();
9862 global1->Set(v8_str("obj"), object);
9864 v8::Handle<Value> value;
9866 // Check that the named access-control function is called every time
9867 // eventhough there is an interceptor on the object.
9868 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9869 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9871 CHECK(value->IsNumber());
9872 CHECK_EQ(42, value->Int32Value());
9873 CHECK_EQ(21, named_access_count);
9875 value = v8_compile("var p = 'x';")->Run();
9876 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9877 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9879 CHECK(value->IsNumber());
9880 CHECK_EQ(42, value->Int32Value());
9881 CHECK_EQ(42, named_access_count);
9883 // Check that the indexed access-control function is called every
9884 // time eventhough there is an interceptor on the object.
9885 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9886 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9888 CHECK(value->IsNumber());
9889 CHECK_EQ(42, value->Int32Value());
9890 CHECK_EQ(21, indexed_access_count);
9897 THREADED_TEST(Version) {
9898 v8::V8::GetVersion();
9902 static void InstanceFunctionCallback(
9903 const v8::FunctionCallbackInfo<v8::Value>& args) {
9904 ApiTestFuzzer::Fuzz();
9905 args.GetReturnValue().Set(v8_num(12));
9909 THREADED_TEST(InstanceProperties) {
9910 LocalContext context;
9911 v8::Isolate* isolate = context->GetIsolate();
9912 v8::HandleScope handle_scope(isolate);
9914 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9915 Local<ObjectTemplate> instance = t->InstanceTemplate();
9917 instance->Set(v8_str("x"), v8_num(42));
9918 instance->Set(v8_str("f"),
9919 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9921 Local<Value> o = t->GetFunction()->NewInstance();
9923 context->Global()->Set(v8_str("i"), o);
9924 Local<Value> value = CompileRun("i.x");
9925 CHECK_EQ(42, value->Int32Value());
9927 value = CompileRun("i.f()");
9928 CHECK_EQ(12, value->Int32Value());
9932 static void GlobalObjectInstancePropertiesGet(
9934 const v8::PropertyCallbackInfo<v8::Value>&) {
9935 ApiTestFuzzer::Fuzz();
9939 THREADED_TEST(GlobalObjectInstanceProperties) {
9940 v8::Isolate* isolate = CcTest::isolate();
9941 v8::HandleScope handle_scope(isolate);
9943 Local<Value> global_object;
9945 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9946 t->InstanceTemplate()->SetNamedPropertyHandler(
9947 GlobalObjectInstancePropertiesGet);
9948 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9949 instance_template->Set(v8_str("x"), v8_num(42));
9950 instance_template->Set(v8_str("f"),
9951 v8::FunctionTemplate::New(isolate,
9952 InstanceFunctionCallback));
9954 // The script to check how Crankshaft compiles missing global function
9955 // invocations. function g is not defined and should throw on call.
9956 const char* script =
9957 "function wrapper(call) {"
9958 " var x = 0, y = 1;"
9959 " for (var i = 0; i < 1000; i++) {"
9965 "for (var i = 0; i < 17; i++) wrapper(false);"
9967 "try { wrapper(true); } catch (e) { thrown = 1; };"
9971 LocalContext env(NULL, instance_template);
9972 // Hold on to the global object so it can be used again in another
9973 // environment initialization.
9974 global_object = env->Global();
9976 Local<Value> value = CompileRun("x");
9977 CHECK_EQ(42, value->Int32Value());
9978 value = CompileRun("f()");
9979 CHECK_EQ(12, value->Int32Value());
9980 value = CompileRun(script);
9981 CHECK_EQ(1, value->Int32Value());
9985 // Create new environment reusing the global object.
9986 LocalContext env(NULL, instance_template, global_object);
9987 Local<Value> value = CompileRun("x");
9988 CHECK_EQ(42, value->Int32Value());
9989 value = CompileRun("f()");
9990 CHECK_EQ(12, value->Int32Value());
9991 value = CompileRun(script);
9992 CHECK_EQ(1, value->Int32Value());
9997 THREADED_TEST(CallKnownGlobalReceiver) {
9998 v8::Isolate* isolate = CcTest::isolate();
9999 v8::HandleScope handle_scope(isolate);
10001 Local<Value> global_object;
10003 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10004 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10006 // The script to check that we leave global object not
10007 // global object proxy on stack when we deoptimize from inside
10008 // arguments evaluation.
10009 // To provoke error we need to both force deoptimization
10010 // from arguments evaluation and to force CallIC to take
10011 // CallIC_Miss code path that can't cope with global proxy.
10012 const char* script =
10013 "function bar(x, y) { try { } finally { } }"
10014 "function baz(x) { try { } finally { } }"
10015 "function bom(x) { try { } finally { } }"
10016 "function foo(x) { bar([x], bom(2)); }"
10017 "for (var i = 0; i < 10000; i++) foo(1);"
10022 LocalContext env(NULL, instance_template);
10023 // Hold on to the global object so it can be used again in another
10024 // environment initialization.
10025 global_object = env->Global();
10026 foo = CompileRun(script);
10030 // Create new environment reusing the global object.
10031 LocalContext env(NULL, instance_template, global_object);
10032 env->Global()->Set(v8_str("foo"), foo);
10033 CompileRun("foo()");
10038 static void ShadowFunctionCallback(
10039 const v8::FunctionCallbackInfo<v8::Value>& args) {
10040 ApiTestFuzzer::Fuzz();
10041 args.GetReturnValue().Set(v8_num(42));
10045 static int shadow_y;
10046 static int shadow_y_setter_call_count;
10047 static int shadow_y_getter_call_count;
10050 static void ShadowYSetter(Local<String>,
10052 const v8::PropertyCallbackInfo<void>&) {
10053 shadow_y_setter_call_count++;
10058 static void ShadowYGetter(Local<String> name,
10059 const v8::PropertyCallbackInfo<v8::Value>& info) {
10060 ApiTestFuzzer::Fuzz();
10061 shadow_y_getter_call_count++;
10062 info.GetReturnValue().Set(v8_num(shadow_y));
10066 static void ShadowIndexedGet(uint32_t index,
10067 const v8::PropertyCallbackInfo<v8::Value>&) {
10071 static void ShadowNamedGet(Local<String> key,
10072 const v8::PropertyCallbackInfo<v8::Value>&) {
10076 THREADED_TEST(ShadowObject) {
10077 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10078 v8::Isolate* isolate = CcTest::isolate();
10079 v8::HandleScope handle_scope(isolate);
10081 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10082 LocalContext context(NULL, global_template);
10084 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10085 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10086 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10087 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10088 Local<ObjectTemplate> instance = t->InstanceTemplate();
10090 proto->Set(v8_str("f"),
10091 v8::FunctionTemplate::New(isolate,
10092 ShadowFunctionCallback,
10094 proto->Set(v8_str("x"), v8_num(12));
10096 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10098 Local<Value> o = t->GetFunction()->NewInstance();
10099 context->Global()->Set(v8_str("__proto__"), o);
10101 Local<Value> value =
10102 CompileRun("this.propertyIsEnumerable(0)");
10103 CHECK(value->IsBoolean());
10104 CHECK(!value->BooleanValue());
10106 value = CompileRun("x");
10107 CHECK_EQ(12, value->Int32Value());
10109 value = CompileRun("f()");
10110 CHECK_EQ(42, value->Int32Value());
10112 CompileRun("y = 43");
10113 CHECK_EQ(1, shadow_y_setter_call_count);
10114 value = CompileRun("y");
10115 CHECK_EQ(1, shadow_y_getter_call_count);
10116 CHECK_EQ(42, value->Int32Value());
10120 THREADED_TEST(HiddenPrototype) {
10121 LocalContext context;
10122 v8::Isolate* isolate = context->GetIsolate();
10123 v8::HandleScope handle_scope(isolate);
10125 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10126 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10127 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10128 t1->SetHiddenPrototype(true);
10129 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10130 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10131 t2->SetHiddenPrototype(true);
10132 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10133 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10134 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10136 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10137 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10138 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10139 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10141 // Setting the prototype on an object skips hidden prototypes.
10142 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10143 o0->Set(v8_str("__proto__"), o1);
10144 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10145 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10146 o0->Set(v8_str("__proto__"), o2);
10147 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10148 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10149 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10150 o0->Set(v8_str("__proto__"), o3);
10151 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10152 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10153 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10154 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10156 // Getting the prototype of o0 should get the first visible one
10157 // which is o3. Therefore, z should not be defined on the prototype
10159 Local<Value> proto = o0->Get(v8_str("__proto__"));
10160 CHECK(proto->IsObject());
10161 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10165 THREADED_TEST(HiddenPrototypeSet) {
10166 LocalContext context;
10167 v8::Isolate* isolate = context->GetIsolate();
10168 v8::HandleScope handle_scope(isolate);
10170 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10171 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10172 ht->SetHiddenPrototype(true);
10173 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10174 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10176 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10177 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10178 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10179 o->Set(v8_str("__proto__"), h);
10180 h->Set(v8_str("__proto__"), p);
10182 // Setting a property that exists on the hidden prototype goes there.
10183 o->Set(v8_str("x"), v8_num(7));
10184 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10185 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10186 CHECK(p->Get(v8_str("x"))->IsUndefined());
10188 // Setting a new property should not be forwarded to the hidden prototype.
10189 o->Set(v8_str("y"), v8_num(6));
10190 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10191 CHECK(h->Get(v8_str("y"))->IsUndefined());
10192 CHECK(p->Get(v8_str("y"))->IsUndefined());
10194 // Setting a property that only exists on a prototype of the hidden prototype
10195 // is treated normally again.
10196 p->Set(v8_str("z"), v8_num(8));
10197 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10198 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10199 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10200 o->Set(v8_str("z"), v8_num(9));
10201 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10202 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10203 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10207 // Regression test for issue 2457.
10208 THREADED_TEST(HiddenPrototypeIdentityHash) {
10209 LocalContext context;
10210 v8::HandleScope handle_scope(context->GetIsolate());
10212 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10213 t->SetHiddenPrototype(true);
10214 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10215 Handle<Object> p = t->GetFunction()->NewInstance();
10216 Handle<Object> o = Object::New(context->GetIsolate());
10217 o->SetPrototype(p);
10219 int hash = o->GetIdentityHash();
10221 o->Set(v8_str("foo"), v8_num(42));
10222 ASSERT_EQ(hash, o->GetIdentityHash());
10226 THREADED_TEST(SetPrototype) {
10227 LocalContext context;
10228 v8::Isolate* isolate = context->GetIsolate();
10229 v8::HandleScope handle_scope(isolate);
10231 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10232 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10233 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10234 t1->SetHiddenPrototype(true);
10235 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10236 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10237 t2->SetHiddenPrototype(true);
10238 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10239 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10240 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10242 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10243 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10244 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10245 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10247 // Setting the prototype on an object does not skip hidden prototypes.
10248 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10249 CHECK(o0->SetPrototype(o1));
10250 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10251 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10252 CHECK(o1->SetPrototype(o2));
10253 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10254 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10255 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10256 CHECK(o2->SetPrototype(o3));
10257 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10258 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10259 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10260 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10262 // Getting the prototype of o0 should get the first visible one
10263 // which is o3. Therefore, z should not be defined on the prototype
10265 Local<Value> proto = o0->Get(v8_str("__proto__"));
10266 CHECK(proto->IsObject());
10267 CHECK_EQ(proto.As<v8::Object>(), o3);
10269 // However, Object::GetPrototype ignores hidden prototype.
10270 Local<Value> proto0 = o0->GetPrototype();
10271 CHECK(proto0->IsObject());
10272 CHECK_EQ(proto0.As<v8::Object>(), o1);
10274 Local<Value> proto1 = o1->GetPrototype();
10275 CHECK(proto1->IsObject());
10276 CHECK_EQ(proto1.As<v8::Object>(), o2);
10278 Local<Value> proto2 = o2->GetPrototype();
10279 CHECK(proto2->IsObject());
10280 CHECK_EQ(proto2.As<v8::Object>(), o3);
10284 // Getting property names of an object with a prototype chain that
10285 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10286 // crash the runtime.
10287 THREADED_TEST(Regress91517) {
10288 i::FLAG_allow_natives_syntax = true;
10289 LocalContext context;
10290 v8::Isolate* isolate = context->GetIsolate();
10291 v8::HandleScope handle_scope(isolate);
10293 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10294 t1->SetHiddenPrototype(true);
10295 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10296 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10297 t2->SetHiddenPrototype(true);
10298 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10299 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10300 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10301 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10302 t3->SetHiddenPrototype(true);
10303 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10304 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10305 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10307 // Force dictionary-based properties.
10308 i::ScopedVector<char> name_buf(1024);
10309 for (int i = 1; i <= 1000; i++) {
10310 i::OS::SNPrintF(name_buf, "sdf%d", i);
10311 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10314 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10315 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10316 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10317 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10319 // Create prototype chain of hidden prototypes.
10320 CHECK(o4->SetPrototype(o3));
10321 CHECK(o3->SetPrototype(o2));
10322 CHECK(o2->SetPrototype(o1));
10324 // Call the runtime version of GetLocalPropertyNames() on the natively
10325 // created object through JavaScript.
10326 context->Global()->Set(v8_str("obj"), o4);
10327 // PROPERTY_ATTRIBUTES_NONE = 0
10328 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10330 ExpectInt32("names.length", 1006);
10331 ExpectTrue("names.indexOf(\"baz\") >= 0");
10332 ExpectTrue("names.indexOf(\"boo\") >= 0");
10333 ExpectTrue("names.indexOf(\"foo\") >= 0");
10334 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10335 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10336 ExpectFalse("names[1005] == undefined");
10340 // Getting property names of an object with a hidden and inherited
10341 // prototype should not duplicate the accessor properties inherited.
10342 THREADED_TEST(Regress269562) {
10343 i::FLAG_allow_natives_syntax = true;
10344 LocalContext context;
10345 v8::HandleScope handle_scope(context->GetIsolate());
10347 Local<v8::FunctionTemplate> t1 =
10348 v8::FunctionTemplate::New(context->GetIsolate());
10349 t1->SetHiddenPrototype(true);
10351 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10352 i1->SetAccessor(v8_str("foo"),
10353 SimpleAccessorGetter, SimpleAccessorSetter);
10354 i1->SetAccessor(v8_str("bar"),
10355 SimpleAccessorGetter, SimpleAccessorSetter);
10356 i1->SetAccessor(v8_str("baz"),
10357 SimpleAccessorGetter, SimpleAccessorSetter);
10358 i1->Set(v8_str("n1"), v8_num(1));
10359 i1->Set(v8_str("n2"), v8_num(2));
10361 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10362 Local<v8::FunctionTemplate> t2 =
10363 v8::FunctionTemplate::New(context->GetIsolate());
10364 t2->SetHiddenPrototype(true);
10366 // Inherit from t1 and mark prototype as hidden.
10368 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10370 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10371 CHECK(o2->SetPrototype(o1));
10373 v8::Local<v8::Symbol> sym =
10374 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10375 o1->Set(sym, v8_num(3));
10376 o1->SetHiddenValue(
10377 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10379 // Call the runtime version of GetLocalPropertyNames() on
10380 // the natively created object through JavaScript.
10381 context->Global()->Set(v8_str("obj"), o2);
10382 context->Global()->Set(v8_str("sym"), sym);
10383 // PROPERTY_ATTRIBUTES_NONE = 0
10384 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10386 ExpectInt32("names.length", 7);
10387 ExpectTrue("names.indexOf(\"foo\") >= 0");
10388 ExpectTrue("names.indexOf(\"bar\") >= 0");
10389 ExpectTrue("names.indexOf(\"baz\") >= 0");
10390 ExpectTrue("names.indexOf(\"n1\") >= 0");
10391 ExpectTrue("names.indexOf(\"n2\") >= 0");
10392 ExpectTrue("names.indexOf(sym) >= 0");
10393 ExpectTrue("names.indexOf(\"mine\") >= 0");
10397 THREADED_TEST(FunctionReadOnlyPrototype) {
10398 LocalContext context;
10399 v8::Isolate* isolate = context->GetIsolate();
10400 v8::HandleScope handle_scope(isolate);
10402 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10403 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10404 t1->ReadOnlyPrototype();
10405 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10406 // Configured value of ReadOnly flag.
10409 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10410 " return (descriptor['writable'] == false);"
10411 "})()")->BooleanValue());
10412 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10414 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10416 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10417 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10418 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10419 // Default value of ReadOnly flag.
10422 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10423 " return (descriptor['writable'] == true);"
10424 "})()")->BooleanValue());
10425 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10429 THREADED_TEST(SetPrototypeThrows) {
10430 LocalContext context;
10431 v8::Isolate* isolate = context->GetIsolate();
10432 v8::HandleScope handle_scope(isolate);
10434 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10436 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10437 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10439 CHECK(o0->SetPrototype(o1));
10440 // If setting the prototype leads to the cycle, SetPrototype should
10441 // return false and keep VM in sane state.
10442 v8::TryCatch try_catch;
10443 CHECK(!o1->SetPrototype(o0));
10444 CHECK(!try_catch.HasCaught());
10445 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10447 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10451 THREADED_TEST(FunctionRemovePrototype) {
10452 LocalContext context;
10453 v8::Isolate* isolate = context->GetIsolate();
10454 v8::HandleScope handle_scope(isolate);
10456 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10457 t1->RemovePrototype();
10458 Local<v8::Function> fun = t1->GetFunction();
10459 context->Global()->Set(v8_str("fun"), fun);
10460 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10462 v8::TryCatch try_catch;
10463 CompileRun("new fun()");
10464 CHECK(try_catch.HasCaught());
10467 fun->NewInstance();
10468 CHECK(try_catch.HasCaught());
10472 THREADED_TEST(GetterSetterExceptions) {
10473 LocalContext context;
10474 v8::Isolate* isolate = context->GetIsolate();
10475 v8::HandleScope handle_scope(isolate);
10477 "function Foo() { };"
10478 "function Throw() { throw 5; };"
10480 "x.__defineSetter__('set', Throw);"
10481 "x.__defineGetter__('get', Throw);");
10482 Local<v8::Object> x =
10483 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10484 v8::TryCatch try_catch;
10485 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10486 x->Get(v8_str("get"));
10487 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10488 x->Get(v8_str("get"));
10489 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10490 x->Get(v8_str("get"));
10491 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10492 x->Get(v8_str("get"));
10496 THREADED_TEST(Constructor) {
10497 LocalContext context;
10498 v8::Isolate* isolate = context->GetIsolate();
10499 v8::HandleScope handle_scope(isolate);
10500 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10501 templ->SetClassName(v8_str("Fun"));
10502 Local<Function> cons = templ->GetFunction();
10503 context->Global()->Set(v8_str("Fun"), cons);
10504 Local<v8::Object> inst = cons->NewInstance();
10505 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10506 CHECK(obj->IsJSObject());
10507 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10508 CHECK(value->BooleanValue());
10512 static void ConstructorCallback(
10513 const v8::FunctionCallbackInfo<v8::Value>& args) {
10514 ApiTestFuzzer::Fuzz();
10515 Local<Object> This;
10517 if (args.IsConstructCall()) {
10518 Local<Object> Holder = args.Holder();
10519 This = Object::New(args.GetIsolate());
10520 Local<Value> proto = Holder->GetPrototype();
10521 if (proto->IsObject()) {
10522 This->SetPrototype(proto);
10525 This = args.This();
10528 This->Set(v8_str("a"), args[0]);
10529 args.GetReturnValue().Set(This);
10533 static void FakeConstructorCallback(
10534 const v8::FunctionCallbackInfo<v8::Value>& args) {
10535 ApiTestFuzzer::Fuzz();
10536 args.GetReturnValue().Set(args[0]);
10540 THREADED_TEST(ConstructorForObject) {
10541 LocalContext context;
10542 v8::Isolate* isolate = context->GetIsolate();
10543 v8::HandleScope handle_scope(isolate);
10545 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10546 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10547 Local<Object> instance = instance_template->NewInstance();
10548 context->Global()->Set(v8_str("obj"), instance);
10549 v8::TryCatch try_catch;
10550 Local<Value> value;
10551 CHECK(!try_catch.HasCaught());
10553 // Call the Object's constructor with a 32-bit signed integer.
10554 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10555 CHECK(!try_catch.HasCaught());
10556 CHECK(value->IsInt32());
10557 CHECK_EQ(28, value->Int32Value());
10559 Local<Value> args1[] = { v8_num(28) };
10560 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10561 CHECK(value_obj1->IsObject());
10562 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10563 value = object1->Get(v8_str("a"));
10564 CHECK(value->IsInt32());
10565 CHECK(!try_catch.HasCaught());
10566 CHECK_EQ(28, value->Int32Value());
10568 // Call the Object's constructor with a String.
10569 value = CompileRun(
10570 "(function() { var o = new obj('tipli'); return o.a; })()");
10571 CHECK(!try_catch.HasCaught());
10572 CHECK(value->IsString());
10573 String::Utf8Value string_value1(value->ToString());
10574 CHECK_EQ("tipli", *string_value1);
10576 Local<Value> args2[] = { v8_str("tipli") };
10577 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10578 CHECK(value_obj2->IsObject());
10579 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10580 value = object2->Get(v8_str("a"));
10581 CHECK(!try_catch.HasCaught());
10582 CHECK(value->IsString());
10583 String::Utf8Value string_value2(value->ToString());
10584 CHECK_EQ("tipli", *string_value2);
10586 // Call the Object's constructor with a Boolean.
10587 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10588 CHECK(!try_catch.HasCaught());
10589 CHECK(value->IsBoolean());
10590 CHECK_EQ(true, value->BooleanValue());
10592 Handle<Value> args3[] = { v8::True(isolate) };
10593 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10594 CHECK(value_obj3->IsObject());
10595 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10596 value = object3->Get(v8_str("a"));
10597 CHECK(!try_catch.HasCaught());
10598 CHECK(value->IsBoolean());
10599 CHECK_EQ(true, value->BooleanValue());
10601 // Call the Object's constructor with undefined.
10602 Handle<Value> args4[] = { v8::Undefined(isolate) };
10603 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10604 CHECK(value_obj4->IsObject());
10605 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10606 value = object4->Get(v8_str("a"));
10607 CHECK(!try_catch.HasCaught());
10608 CHECK(value->IsUndefined());
10610 // Call the Object's constructor with null.
10611 Handle<Value> args5[] = { v8::Null(isolate) };
10612 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10613 CHECK(value_obj5->IsObject());
10614 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10615 value = object5->Get(v8_str("a"));
10616 CHECK(!try_catch.HasCaught());
10617 CHECK(value->IsNull());
10620 // Check exception handling when there is no constructor set for the Object.
10621 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10622 Local<Object> instance = instance_template->NewInstance();
10623 context->Global()->Set(v8_str("obj2"), instance);
10624 v8::TryCatch try_catch;
10625 Local<Value> value;
10626 CHECK(!try_catch.HasCaught());
10628 value = CompileRun("new obj2(28)");
10629 CHECK(try_catch.HasCaught());
10630 String::Utf8Value exception_value1(try_catch.Exception());
10631 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10634 Local<Value> args[] = { v8_num(29) };
10635 value = instance->CallAsConstructor(1, args);
10636 CHECK(try_catch.HasCaught());
10637 String::Utf8Value exception_value2(try_catch.Exception());
10638 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10642 // Check the case when constructor throws exception.
10643 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10644 instance_template->SetCallAsFunctionHandler(ThrowValue);
10645 Local<Object> instance = instance_template->NewInstance();
10646 context->Global()->Set(v8_str("obj3"), instance);
10647 v8::TryCatch try_catch;
10648 Local<Value> value;
10649 CHECK(!try_catch.HasCaught());
10651 value = CompileRun("new obj3(22)");
10652 CHECK(try_catch.HasCaught());
10653 String::Utf8Value exception_value1(try_catch.Exception());
10654 CHECK_EQ("22", *exception_value1);
10657 Local<Value> args[] = { v8_num(23) };
10658 value = instance->CallAsConstructor(1, args);
10659 CHECK(try_catch.HasCaught());
10660 String::Utf8Value exception_value2(try_catch.Exception());
10661 CHECK_EQ("23", *exception_value2);
10665 // Check whether constructor returns with an object or non-object.
10666 { Local<FunctionTemplate> function_template =
10667 FunctionTemplate::New(isolate, FakeConstructorCallback);
10668 Local<Function> function = function_template->GetFunction();
10669 Local<Object> instance1 = function;
10670 context->Global()->Set(v8_str("obj4"), instance1);
10671 v8::TryCatch try_catch;
10672 Local<Value> value;
10673 CHECK(!try_catch.HasCaught());
10675 CHECK(instance1->IsObject());
10676 CHECK(instance1->IsFunction());
10678 value = CompileRun("new obj4(28)");
10679 CHECK(!try_catch.HasCaught());
10680 CHECK(value->IsObject());
10682 Local<Value> args1[] = { v8_num(28) };
10683 value = instance1->CallAsConstructor(1, args1);
10684 CHECK(!try_catch.HasCaught());
10685 CHECK(value->IsObject());
10687 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10688 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10689 Local<Object> instance2 = instance_template->NewInstance();
10690 context->Global()->Set(v8_str("obj5"), instance2);
10691 CHECK(!try_catch.HasCaught());
10693 CHECK(instance2->IsObject());
10694 CHECK(!instance2->IsFunction());
10696 value = CompileRun("new obj5(28)");
10697 CHECK(!try_catch.HasCaught());
10698 CHECK(!value->IsObject());
10700 Local<Value> args2[] = { v8_num(28) };
10701 value = instance2->CallAsConstructor(1, args2);
10702 CHECK(!try_catch.HasCaught());
10703 CHECK(!value->IsObject());
10708 THREADED_TEST(FunctionDescriptorException) {
10709 LocalContext context;
10710 v8::Isolate* isolate = context->GetIsolate();
10711 v8::HandleScope handle_scope(isolate);
10712 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10713 templ->SetClassName(v8_str("Fun"));
10714 Local<Function> cons = templ->GetFunction();
10715 context->Global()->Set(v8_str("Fun"), cons);
10716 Local<Value> value = CompileRun(
10717 "function test() {"
10719 " (new Fun()).blah()"
10721 " var str = String(e);"
10722 // " if (str.indexOf('TypeError') == -1) return 1;"
10723 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10724 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10730 CHECK_EQ(0, value->Int32Value());
10734 THREADED_TEST(EvalAliasedDynamic) {
10735 LocalContext current;
10736 v8::HandleScope scope(current->GetIsolate());
10738 // Tests where aliased eval can only be resolved dynamically.
10739 Local<Script> script = v8_compile(
10742 " with (x) { return eval('foo'); }"
10745 "result1 = f(new Object());"
10746 "result2 = f(this);"
10747 "var x = new Object();"
10748 "x.eval = function(x) { return 1; };"
10749 "result3 = f(x);");
10751 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10752 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10753 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10755 v8::TryCatch try_catch;
10756 script = v8_compile(
10759 " with (x) { return eval('bar'); }"
10761 "result4 = f(this)");
10763 CHECK(!try_catch.HasCaught());
10764 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10770 THREADED_TEST(CrossEval) {
10771 v8::HandleScope scope(CcTest::isolate());
10772 LocalContext other;
10773 LocalContext current;
10775 Local<String> token = v8_str("<security token>");
10776 other->SetSecurityToken(token);
10777 current->SetSecurityToken(token);
10779 // Set up reference from current to other.
10780 current->Global()->Set(v8_str("other"), other->Global());
10782 // Check that new variables are introduced in other context.
10783 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10785 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10786 CHECK_EQ(1234, foo->Int32Value());
10787 CHECK(!current->Global()->Has(v8_str("foo")));
10789 // Check that writing to non-existing properties introduces them in
10790 // the other context.
10791 script = v8_compile("other.eval('na = 1234')");
10793 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10794 CHECK(!current->Global()->Has(v8_str("na")));
10796 // Check that global variables in current context are not visible in other
10798 v8::TryCatch try_catch;
10799 script = v8_compile("var bar = 42; other.eval('bar');");
10800 Local<Value> result = script->Run();
10801 CHECK(try_catch.HasCaught());
10804 // Check that local variables in current context are not visible in other
10806 script = v8_compile(
10809 " return other.eval('baz');"
10811 result = script->Run();
10812 CHECK(try_catch.HasCaught());
10815 // Check that global variables in the other environment are visible
10816 // when evaluting code.
10817 other->Global()->Set(v8_str("bis"), v8_num(1234));
10818 script = v8_compile("other.eval('bis')");
10819 CHECK_EQ(1234, script->Run()->Int32Value());
10820 CHECK(!try_catch.HasCaught());
10822 // Check that the 'this' pointer points to the global object evaluating
10824 other->Global()->Set(v8_str("t"), other->Global());
10825 script = v8_compile("other.eval('this == t')");
10826 result = script->Run();
10827 CHECK(result->IsTrue());
10828 CHECK(!try_catch.HasCaught());
10830 // Check that variables introduced in with-statement are not visible in
10832 script = v8_compile("with({x:2}){other.eval('x')}");
10833 result = script->Run();
10834 CHECK(try_catch.HasCaught());
10837 // Check that you cannot use 'eval.call' with another object than the
10838 // current global object.
10839 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10840 result = script->Run();
10841 CHECK(try_catch.HasCaught());
10845 // Test that calling eval in a context which has been detached from
10846 // its global throws an exception. This behavior is consistent with
10847 // other JavaScript implementations.
10848 THREADED_TEST(EvalInDetachedGlobal) {
10849 v8::Isolate* isolate = CcTest::isolate();
10850 v8::HandleScope scope(isolate);
10852 v8::Local<Context> context0 = Context::New(isolate);
10853 v8::Local<Context> context1 = Context::New(isolate);
10855 // Set up function in context0 that uses eval from context0.
10857 v8::Handle<v8::Value> fun =
10858 CompileRun("var x = 42;"
10861 " return function(s) { return e(s); }"
10865 // Put the function into context1 and call it before and after
10866 // detaching the global. Before detaching, the call succeeds and
10867 // after detaching and exception is thrown.
10869 context1->Global()->Set(v8_str("fun"), fun);
10870 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10871 CHECK_EQ(42, x_value->Int32Value());
10872 context0->DetachGlobal();
10873 v8::TryCatch catcher;
10874 x_value = CompileRun("fun('x')");
10875 CHECK(x_value.IsEmpty());
10876 CHECK(catcher.HasCaught());
10881 THREADED_TEST(CrossLazyLoad) {
10882 v8::HandleScope scope(CcTest::isolate());
10883 LocalContext other;
10884 LocalContext current;
10886 Local<String> token = v8_str("<security token>");
10887 other->SetSecurityToken(token);
10888 current->SetSecurityToken(token);
10890 // Set up reference from current to other.
10891 current->Global()->Set(v8_str("other"), other->Global());
10893 // Trigger lazy loading in other context.
10894 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10895 Local<Value> value = script->Run();
10896 CHECK_EQ(42.0, value->NumberValue());
10900 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10901 ApiTestFuzzer::Fuzz();
10902 if (args.IsConstructCall()) {
10903 if (args[0]->IsInt32()) {
10904 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10909 args.GetReturnValue().Set(args[0]);
10913 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10914 args.GetReturnValue().Set(args.This());
10918 // Test that a call handler can be set for objects which will allow
10919 // non-function objects created through the API to be called as
10921 THREADED_TEST(CallAsFunction) {
10922 LocalContext context;
10923 v8::Isolate* isolate = context->GetIsolate();
10924 v8::HandleScope scope(isolate);
10926 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10927 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10928 instance_template->SetCallAsFunctionHandler(call_as_function);
10929 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10930 context->Global()->Set(v8_str("obj"), instance);
10931 v8::TryCatch try_catch;
10932 Local<Value> value;
10933 CHECK(!try_catch.HasCaught());
10935 value = CompileRun("obj(42)");
10936 CHECK(!try_catch.HasCaught());
10937 CHECK_EQ(42, value->Int32Value());
10939 value = CompileRun("(function(o){return o(49)})(obj)");
10940 CHECK(!try_catch.HasCaught());
10941 CHECK_EQ(49, value->Int32Value());
10943 // test special case of call as function
10944 value = CompileRun("[obj]['0'](45)");
10945 CHECK(!try_catch.HasCaught());
10946 CHECK_EQ(45, value->Int32Value());
10948 value = CompileRun("obj.call = Function.prototype.call;"
10949 "obj.call(null, 87)");
10950 CHECK(!try_catch.HasCaught());
10951 CHECK_EQ(87, value->Int32Value());
10953 // Regression tests for bug #1116356: Calling call through call/apply
10954 // must work for non-function receivers.
10955 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10956 value = CompileRun(apply_99);
10957 CHECK(!try_catch.HasCaught());
10958 CHECK_EQ(99, value->Int32Value());
10960 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10961 value = CompileRun(call_17);
10962 CHECK(!try_catch.HasCaught());
10963 CHECK_EQ(17, value->Int32Value());
10965 // Check that the call-as-function handler can be called through
10967 value = CompileRun("new obj(43)");
10968 CHECK(!try_catch.HasCaught());
10969 CHECK_EQ(-43, value->Int32Value());
10971 // Check that the call-as-function handler can be called through
10973 v8::Handle<Value> args[] = { v8_num(28) };
10974 value = instance->CallAsFunction(instance, 1, args);
10975 CHECK(!try_catch.HasCaught());
10976 CHECK_EQ(28, value->Int32Value());
10979 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10980 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10981 USE(instance_template);
10982 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10983 context->Global()->Set(v8_str("obj2"), instance);
10984 v8::TryCatch try_catch;
10985 Local<Value> value;
10986 CHECK(!try_catch.HasCaught());
10988 // Call an object without call-as-function handler through the JS
10989 value = CompileRun("obj2(28)");
10990 CHECK(value.IsEmpty());
10991 CHECK(try_catch.HasCaught());
10992 String::Utf8Value exception_value1(try_catch.Exception());
10993 // TODO(verwaest): Better message
10994 CHECK_EQ("TypeError: object is not a function",
10995 *exception_value1);
10998 // Call an object without call-as-function handler through the API
10999 value = CompileRun("obj2(28)");
11000 v8::Handle<Value> args[] = { v8_num(28) };
11001 value = instance->CallAsFunction(instance, 1, args);
11002 CHECK(value.IsEmpty());
11003 CHECK(try_catch.HasCaught());
11004 String::Utf8Value exception_value2(try_catch.Exception());
11005 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11009 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11010 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11011 instance_template->SetCallAsFunctionHandler(ThrowValue);
11012 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11013 context->Global()->Set(v8_str("obj3"), instance);
11014 v8::TryCatch try_catch;
11015 Local<Value> value;
11016 CHECK(!try_catch.HasCaught());
11018 // Catch the exception which is thrown by call-as-function handler
11019 value = CompileRun("obj3(22)");
11020 CHECK(try_catch.HasCaught());
11021 String::Utf8Value exception_value1(try_catch.Exception());
11022 CHECK_EQ("22", *exception_value1);
11025 v8::Handle<Value> args[] = { v8_num(23) };
11026 value = instance->CallAsFunction(instance, 1, args);
11027 CHECK(try_catch.HasCaught());
11028 String::Utf8Value exception_value2(try_catch.Exception());
11029 CHECK_EQ("23", *exception_value2);
11033 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11034 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11035 instance_template->SetCallAsFunctionHandler(ReturnThis);
11036 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11038 Local<v8::Value> a1 =
11039 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11040 CHECK(a1->StrictEquals(instance));
11041 Local<v8::Value> a2 =
11042 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11043 CHECK(a2->StrictEquals(instance));
11044 Local<v8::Value> a3 =
11045 instance->CallAsFunction(v8_num(42), 0, NULL);
11046 CHECK(a3->StrictEquals(instance));
11047 Local<v8::Value> a4 =
11048 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11049 CHECK(a4->StrictEquals(instance));
11050 Local<v8::Value> a5 =
11051 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11052 CHECK(a5->StrictEquals(instance));
11056 "function ReturnThisSloppy() {"
11059 "function ReturnThisStrict() {"
11063 Local<Function> ReturnThisSloppy =
11064 Local<Function>::Cast(
11065 context->Global()->Get(v8_str("ReturnThisSloppy")));
11066 Local<Function> ReturnThisStrict =
11067 Local<Function>::Cast(
11068 context->Global()->Get(v8_str("ReturnThisStrict")));
11070 Local<v8::Value> a1 =
11071 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11072 CHECK(a1->StrictEquals(context->Global()));
11073 Local<v8::Value> a2 =
11074 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11075 CHECK(a2->StrictEquals(context->Global()));
11076 Local<v8::Value> a3 =
11077 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11078 CHECK(a3->IsNumberObject());
11079 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11080 Local<v8::Value> a4 =
11081 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11082 CHECK(a4->IsStringObject());
11083 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11084 Local<v8::Value> a5 =
11085 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11086 CHECK(a5->IsBooleanObject());
11087 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11089 Local<v8::Value> a6 =
11090 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11091 CHECK(a6->IsUndefined());
11092 Local<v8::Value> a7 =
11093 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11094 CHECK(a7->IsNull());
11095 Local<v8::Value> a8 =
11096 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11097 CHECK(a8->StrictEquals(v8_num(42)));
11098 Local<v8::Value> a9 =
11099 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11100 CHECK(a9->StrictEquals(v8_str("hello")));
11101 Local<v8::Value> a10 =
11102 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11103 CHECK(a10->StrictEquals(v8::True(isolate)));
11108 // Check whether a non-function object is callable.
11109 THREADED_TEST(CallableObject) {
11110 LocalContext context;
11111 v8::Isolate* isolate = context->GetIsolate();
11112 v8::HandleScope scope(isolate);
11114 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11115 instance_template->SetCallAsFunctionHandler(call_as_function);
11116 Local<Object> instance = instance_template->NewInstance();
11117 v8::TryCatch try_catch;
11119 CHECK(instance->IsCallable());
11120 CHECK(!try_catch.HasCaught());
11123 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11124 Local<Object> instance = instance_template->NewInstance();
11125 v8::TryCatch try_catch;
11127 CHECK(!instance->IsCallable());
11128 CHECK(!try_catch.HasCaught());
11131 { Local<FunctionTemplate> function_template =
11132 FunctionTemplate::New(isolate, call_as_function);
11133 Local<Function> function = function_template->GetFunction();
11134 Local<Object> instance = function;
11135 v8::TryCatch try_catch;
11137 CHECK(instance->IsCallable());
11138 CHECK(!try_catch.HasCaught());
11141 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11142 Local<Function> function = function_template->GetFunction();
11143 Local<Object> instance = function;
11144 v8::TryCatch try_catch;
11146 CHECK(instance->IsCallable());
11147 CHECK(!try_catch.HasCaught());
11152 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11153 v8::HandleScope scope(isolate);
11154 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11155 for (int i = 0; i < iterations; i++) {
11156 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11158 return Recurse(isolate, depth - 1, iterations);
11162 THREADED_TEST(HandleIteration) {
11163 static const int kIterations = 500;
11164 static const int kNesting = 200;
11165 LocalContext context;
11166 v8::Isolate* isolate = context->GetIsolate();
11167 v8::HandleScope scope0(isolate);
11168 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11170 v8::HandleScope scope1(isolate);
11171 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11172 for (int i = 0; i < kIterations; i++) {
11173 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11174 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11177 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11179 v8::HandleScope scope2(CcTest::isolate());
11180 for (int j = 0; j < kIterations; j++) {
11181 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11182 CHECK_EQ(j + 1 + kIterations,
11183 v8::HandleScope::NumberOfHandles(isolate));
11186 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11188 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11189 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11193 static void InterceptorHasOwnPropertyGetter(
11194 Local<String> name,
11195 const v8::PropertyCallbackInfo<v8::Value>& info) {
11196 ApiTestFuzzer::Fuzz();
11200 THREADED_TEST(InterceptorHasOwnProperty) {
11201 LocalContext context;
11202 v8::Isolate* isolate = context->GetIsolate();
11203 v8::HandleScope scope(isolate);
11204 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11205 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11206 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11207 Local<Function> function = fun_templ->GetFunction();
11208 context->Global()->Set(v8_str("constructor"), function);
11209 v8::Handle<Value> value = CompileRun(
11210 "var o = new constructor();"
11211 "o.hasOwnProperty('ostehaps');");
11212 CHECK_EQ(false, value->BooleanValue());
11213 value = CompileRun(
11215 "o.hasOwnProperty('ostehaps');");
11216 CHECK_EQ(true, value->BooleanValue());
11217 value = CompileRun(
11218 "var p = new constructor();"
11219 "p.hasOwnProperty('ostehaps');");
11220 CHECK_EQ(false, value->BooleanValue());
11224 static void InterceptorHasOwnPropertyGetterGC(
11225 Local<String> name,
11226 const v8::PropertyCallbackInfo<v8::Value>& info) {
11227 ApiTestFuzzer::Fuzz();
11228 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11232 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11233 LocalContext context;
11234 v8::Isolate* isolate = context->GetIsolate();
11235 v8::HandleScope scope(isolate);
11236 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11237 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11238 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11239 Local<Function> function = fun_templ->GetFunction();
11240 context->Global()->Set(v8_str("constructor"), function);
11241 // Let's first make some stuff so we can be sure to get a good GC.
11243 "function makestr(size) {"
11245 " case 1: return 'f';"
11246 " case 2: return 'fo';"
11247 " case 3: return 'foo';"
11249 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11251 "var x = makestr(12345);"
11252 "x = makestr(31415);"
11253 "x = makestr(23456);");
11254 v8::Handle<Value> value = CompileRun(
11255 "var o = new constructor();"
11256 "o.__proto__ = new String(x);"
11257 "o.hasOwnProperty('ostehaps');");
11258 CHECK_EQ(false, value->BooleanValue());
11262 typedef void (*NamedPropertyGetter)(
11263 Local<String> property,
11264 const v8::PropertyCallbackInfo<v8::Value>& info);
11267 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11268 const char* source,
11270 v8::Isolate* isolate = CcTest::isolate();
11271 v8::HandleScope scope(isolate);
11272 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11273 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11274 LocalContext context;
11275 context->Global()->Set(v8_str("o"), templ->NewInstance());
11276 v8::Handle<Value> value = CompileRun(source);
11277 CHECK_EQ(expected, value->Int32Value());
11281 static void InterceptorLoadICGetter(
11282 Local<String> name,
11283 const v8::PropertyCallbackInfo<v8::Value>& info) {
11284 ApiTestFuzzer::Fuzz();
11285 v8::Isolate* isolate = CcTest::isolate();
11286 CHECK_EQ(isolate, info.GetIsolate());
11287 CHECK_EQ(v8_str("data"), info.Data());
11288 CHECK_EQ(v8_str("x"), name);
11289 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11293 // This test should hit the load IC for the interceptor case.
11294 THREADED_TEST(InterceptorLoadIC) {
11295 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11297 "for (var i = 0; i < 1000; i++) {"
11304 // Below go several tests which verify that JITing for various
11305 // configurations of interceptor and explicit fields works fine
11306 // (those cases are special cased to get better performance).
11308 static void InterceptorLoadXICGetter(
11309 Local<String> name,
11310 const v8::PropertyCallbackInfo<v8::Value>& info) {
11311 ApiTestFuzzer::Fuzz();
11312 info.GetReturnValue().Set(
11313 v8_str("x")->Equals(name) ?
11314 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11315 v8::Handle<v8::Value>());
11319 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11320 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11323 "for (var i = 0; i < 1000; i++) {"
11330 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11331 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11333 "o.__proto__ = { 'y': 239 };"
11334 "for (var i = 0; i < 1000; i++) {"
11335 " result = o.y + o.x;"
11341 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11342 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11344 "o.__proto__.y = 239;"
11345 "for (var i = 0; i < 1000; i++) {"
11346 " result = o.y + o.x;"
11352 THREADED_TEST(InterceptorLoadICUndefined) {
11353 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11355 "for (var i = 0; i < 1000; i++) {"
11356 " result = (o.y == undefined) ? 239 : 42;"
11362 THREADED_TEST(InterceptorLoadICWithOverride) {
11363 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11364 "fst = new Object(); fst.__proto__ = o;"
11365 "snd = new Object(); snd.__proto__ = fst;"
11367 "for (var i = 0; i < 1000; i++) {"
11368 " result1 = snd.x;"
11372 "for (var i = 0; i < 1000; i++) {"
11375 "result + result1",
11380 // Test the case when we stored field into
11381 // a stub, but interceptor produced value on its own.
11382 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11383 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11384 "proto = new Object();"
11385 "o.__proto__ = proto;"
11387 "for (var i = 0; i < 1000; i++) {"
11389 // Now it should be ICed and keep a reference to x defined on proto
11392 "for (var i = 0; i < 1000; i++) {"
11400 // Test the case when we stored field into
11401 // a stub, but it got invalidated later on.
11402 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11403 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11404 "proto1 = new Object();"
11405 "proto2 = new Object();"
11406 "o.__proto__ = proto1;"
11407 "proto1.__proto__ = proto2;"
11409 "for (var i = 0; i < 1000; i++) {"
11411 // Now it should be ICed and keep a reference to y defined on proto2
11415 "for (var i = 0; i < 1000; i++) {"
11423 static int interceptor_load_not_handled_calls = 0;
11424 static void InterceptorLoadNotHandled(
11425 Local<String> name,
11426 const v8::PropertyCallbackInfo<v8::Value>& info) {
11427 ++interceptor_load_not_handled_calls;
11431 // Test how post-interceptor lookups are done in the non-cacheable
11432 // case: the interceptor should not be invoked during this lookup.
11433 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11434 interceptor_load_not_handled_calls = 0;
11435 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11436 "receiver = new Object();"
11437 "receiver.__proto__ = o;"
11438 "proto = new Object();"
11439 "/* Make proto a slow-case object. */"
11440 "for (var i = 0; i < 1000; i++) {"
11441 " proto[\"xxxxxxxx\" + i] = [];"
11444 "o.__proto__ = proto;"
11446 "for (var i = 0; i < 1000; i++) {"
11447 " result += receiver.x;"
11451 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11455 // Test the case when we stored field into
11456 // a stub, but it got invalidated later on due to override on
11457 // global object which is between interceptor and fields' holders.
11458 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11459 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11460 "o.__proto__ = this;" // set a global to be a proto of o.
11461 "this.__proto__.y = 239;"
11462 "for (var i = 0; i < 10; i++) {"
11463 " if (o.y != 239) throw 'oops: ' + o.y;"
11464 // Now it should be ICed and keep a reference to y defined on field_holder.
11466 "this.y = 42;" // Assign on a global.
11468 "for (var i = 0; i < 10; i++) {"
11476 static void SetOnThis(Local<String> name,
11477 Local<Value> value,
11478 const v8::PropertyCallbackInfo<void>& info) {
11479 Local<Object>::Cast(info.This())->ForceSet(name, value);
11483 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11484 v8::Isolate* isolate = CcTest::isolate();
11485 v8::HandleScope scope(isolate);
11486 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11487 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11488 templ->SetAccessor(v8_str("y"), Return239Callback);
11489 LocalContext context;
11490 context->Global()->Set(v8_str("o"), templ->NewInstance());
11492 // Check the case when receiver and interceptor's holder
11493 // are the same objects.
11494 v8::Handle<Value> value = CompileRun(
11496 "for (var i = 0; i < 7; i++) {"
11499 CHECK_EQ(239, value->Int32Value());
11501 // Check the case when interceptor's holder is in proto chain
11503 value = CompileRun(
11504 "r = { __proto__: o };"
11506 "for (var i = 0; i < 7; i++) {"
11509 CHECK_EQ(239, value->Int32Value());
11513 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11514 v8::Isolate* isolate = CcTest::isolate();
11515 v8::HandleScope scope(isolate);
11516 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11517 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11518 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11519 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11521 LocalContext context;
11522 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11523 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11525 // Check the case when receiver and interceptor's holder
11526 // are the same objects.
11527 v8::Handle<Value> value = CompileRun(
11530 "for (var i = 0; i < 7; i++) {"
11531 " result = o.x + o.y;"
11533 CHECK_EQ(239 + 42, value->Int32Value());
11535 // Check the case when interceptor's holder is in proto chain
11537 value = CompileRun(
11538 "r = { __proto__: o };"
11540 "for (var i = 0; i < 7; i++) {"
11541 " result = r.x + r.y;"
11543 CHECK_EQ(239 + 42, value->Int32Value());
11547 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11548 v8::Isolate* isolate = CcTest::isolate();
11549 v8::HandleScope scope(isolate);
11550 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11551 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11552 templ->SetAccessor(v8_str("y"), Return239Callback);
11554 LocalContext context;
11555 context->Global()->Set(v8_str("o"), templ->NewInstance());
11557 v8::Handle<Value> value = CompileRun(
11558 "fst = new Object(); fst.__proto__ = o;"
11559 "snd = new Object(); snd.__proto__ = fst;"
11561 "for (var i = 0; i < 7; i++) {"
11562 " result1 = snd.x;"
11566 "for (var i = 0; i < 7; i++) {"
11569 "result + result1");
11570 CHECK_EQ(239 + 42, value->Int32Value());
11574 // Test the case when we stored callback into
11575 // a stub, but interceptor produced value on its own.
11576 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11577 v8::Isolate* isolate = CcTest::isolate();
11578 v8::HandleScope scope(isolate);
11579 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11580 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11581 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11582 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11584 LocalContext context;
11585 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11586 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11588 v8::Handle<Value> value = CompileRun(
11590 "for (var i = 0; i < 7; i++) {"
11592 // Now it should be ICed and keep a reference to x defined on p
11595 "for (var i = 0; i < 7; i++) {"
11599 CHECK_EQ(42 * 7, value->Int32Value());
11603 // Test the case when we stored callback into
11604 // a stub, but it got invalidated later on.
11605 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11606 v8::Isolate* isolate = CcTest::isolate();
11607 v8::HandleScope scope(isolate);
11608 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11609 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11610 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11611 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11613 LocalContext context;
11614 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11615 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11617 v8::Handle<Value> value = CompileRun(
11618 "inbetween = new Object();"
11619 "o.__proto__ = inbetween;"
11620 "inbetween.__proto__ = p;"
11621 "for (var i = 0; i < 10; i++) {"
11623 // Now it should be ICed and keep a reference to y defined on p
11625 "inbetween.y = 42;"
11627 "for (var i = 0; i < 10; i++) {"
11631 CHECK_EQ(42 * 10, value->Int32Value());
11635 // Test the case when we stored callback into
11636 // a stub, but it got invalidated later on due to override on
11637 // global object which is between interceptor and callbacks' holders.
11638 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11639 v8::Isolate* isolate = CcTest::isolate();
11640 v8::HandleScope scope(isolate);
11641 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11642 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11643 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11644 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11646 LocalContext context;
11647 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11648 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11650 v8::Handle<Value> value = CompileRun(
11651 "o.__proto__ = this;"
11652 "this.__proto__ = p;"
11653 "for (var i = 0; i < 10; i++) {"
11654 " if (o.y != 239) throw 'oops: ' + o.y;"
11655 // Now it should be ICed and keep a reference to y defined on p
11659 "for (var i = 0; i < 10; i++) {"
11663 CHECK_EQ(42 * 10, value->Int32Value());
11667 static void InterceptorLoadICGetter0(
11668 Local<String> name,
11669 const v8::PropertyCallbackInfo<v8::Value>& info) {
11670 ApiTestFuzzer::Fuzz();
11671 CHECK(v8_str("x")->Equals(name));
11672 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11676 THREADED_TEST(InterceptorReturningZero) {
11677 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11678 "o.x == undefined ? 1 : 0",
11683 static void InterceptorStoreICSetter(
11685 Local<Value> value,
11686 const v8::PropertyCallbackInfo<v8::Value>& info) {
11687 CHECK(v8_str("x")->Equals(key));
11688 CHECK_EQ(42, value->Int32Value());
11689 info.GetReturnValue().Set(value);
11693 // This test should hit the store IC for the interceptor case.
11694 THREADED_TEST(InterceptorStoreIC) {
11695 v8::Isolate* isolate = CcTest::isolate();
11696 v8::HandleScope scope(isolate);
11697 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11698 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11699 InterceptorStoreICSetter,
11700 0, 0, 0, v8_str("data"));
11701 LocalContext context;
11702 context->Global()->Set(v8_str("o"), templ->NewInstance());
11704 "for (var i = 0; i < 1000; i++) {"
11710 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11711 v8::Isolate* isolate = CcTest::isolate();
11712 v8::HandleScope scope(isolate);
11713 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11714 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11715 LocalContext context;
11716 context->Global()->Set(v8_str("o"), templ->NewInstance());
11717 v8::Handle<Value> value = CompileRun(
11718 "for (var i = 0; i < 1000; i++) {"
11722 CHECK_EQ(239 + 42, value->Int32Value());
11728 v8::Handle<Value> call_ic_function;
11729 v8::Handle<Value> call_ic_function2;
11730 v8::Handle<Value> call_ic_function3;
11732 static void InterceptorCallICGetter(
11733 Local<String> name,
11734 const v8::PropertyCallbackInfo<v8::Value>& info) {
11735 ApiTestFuzzer::Fuzz();
11736 CHECK(v8_str("x")->Equals(name));
11737 info.GetReturnValue().Set(call_ic_function);
11741 // This test should hit the call IC for the interceptor case.
11742 THREADED_TEST(InterceptorCallIC) {
11743 v8::Isolate* isolate = CcTest::isolate();
11744 v8::HandleScope scope(isolate);
11745 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11746 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11747 LocalContext context;
11748 context->Global()->Set(v8_str("o"), templ->NewInstance());
11750 v8_compile("function f(x) { return x + 1; }; f")->Run();
11751 v8::Handle<Value> value = CompileRun(
11753 "for (var i = 0; i < 1000; i++) {"
11754 " result = o.x(41);"
11756 CHECK_EQ(42, value->Int32Value());
11760 // This test checks that if interceptor doesn't provide
11761 // a value, we can fetch regular value.
11762 THREADED_TEST(InterceptorCallICSeesOthers) {
11763 v8::Isolate* isolate = CcTest::isolate();
11764 v8::HandleScope scope(isolate);
11765 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11766 templ->SetNamedPropertyHandler(NoBlockGetterX);
11767 LocalContext context;
11768 context->Global()->Set(v8_str("o"), templ->NewInstance());
11769 v8::Handle<Value> value = CompileRun(
11770 "o.x = function f(x) { return x + 1; };"
11772 "for (var i = 0; i < 7; i++) {"
11773 " result = o.x(41);"
11775 CHECK_EQ(42, value->Int32Value());
11779 static v8::Handle<Value> call_ic_function4;
11780 static void InterceptorCallICGetter4(
11781 Local<String> name,
11782 const v8::PropertyCallbackInfo<v8::Value>& info) {
11783 ApiTestFuzzer::Fuzz();
11784 CHECK(v8_str("x")->Equals(name));
11785 info.GetReturnValue().Set(call_ic_function4);
11789 // This test checks that if interceptor provides a function,
11790 // even if we cached shadowed variant, interceptor's function
11792 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11793 v8::Isolate* isolate = CcTest::isolate();
11794 v8::HandleScope scope(isolate);
11795 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11796 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11797 LocalContext context;
11798 context->Global()->Set(v8_str("o"), templ->NewInstance());
11799 call_ic_function4 =
11800 v8_compile("function f(x) { return x - 1; }; f")->Run();
11801 v8::Handle<Value> value = CompileRun(
11802 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11804 "for (var i = 0; i < 1000; i++) {"
11805 " result = o.x(42);"
11807 CHECK_EQ(41, value->Int32Value());
11811 // Test the case when we stored cacheable lookup into
11812 // a stub, but it got invalidated later on
11813 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11814 v8::Isolate* isolate = CcTest::isolate();
11815 v8::HandleScope scope(isolate);
11816 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11817 templ->SetNamedPropertyHandler(NoBlockGetterX);
11818 LocalContext context;
11819 context->Global()->Set(v8_str("o"), templ->NewInstance());
11820 v8::Handle<Value> value = CompileRun(
11821 "proto1 = new Object();"
11822 "proto2 = new Object();"
11823 "o.__proto__ = proto1;"
11824 "proto1.__proto__ = proto2;"
11825 "proto2.y = function(x) { return x + 1; };"
11826 // Invoke it many times to compile a stub
11827 "for (var i = 0; i < 7; i++) {"
11830 "proto1.y = function(x) { return x - 1; };"
11832 "for (var i = 0; i < 7; i++) {"
11833 " result += o.y(42);"
11835 CHECK_EQ(41 * 7, value->Int32Value());
11839 // This test checks that if interceptor doesn't provide a function,
11840 // cached constant function is used
11841 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11842 v8::Isolate* isolate = CcTest::isolate();
11843 v8::HandleScope scope(isolate);
11844 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11845 templ->SetNamedPropertyHandler(NoBlockGetterX);
11846 LocalContext context;
11847 context->Global()->Set(v8_str("o"), templ->NewInstance());
11848 v8::Handle<Value> value = CompileRun(
11849 "function inc(x) { return x + 1; };"
11853 "for (var i = 0; i < 1000; i++) {"
11854 " result = o.x(42);"
11856 CHECK_EQ(43, value->Int32Value());
11860 static v8::Handle<Value> call_ic_function5;
11861 static void InterceptorCallICGetter5(
11862 Local<String> name,
11863 const v8::PropertyCallbackInfo<v8::Value>& info) {
11864 ApiTestFuzzer::Fuzz();
11865 if (v8_str("x")->Equals(name))
11866 info.GetReturnValue().Set(call_ic_function5);
11870 // This test checks that if interceptor provides a function,
11871 // even if we cached constant function, interceptor's function
11873 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11874 v8::Isolate* isolate = CcTest::isolate();
11875 v8::HandleScope scope(isolate);
11876 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11877 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11878 LocalContext context;
11879 context->Global()->Set(v8_str("o"), templ->NewInstance());
11880 call_ic_function5 =
11881 v8_compile("function f(x) { return x - 1; }; f")->Run();
11882 v8::Handle<Value> value = CompileRun(
11883 "function inc(x) { return x + 1; };"
11887 "for (var i = 0; i < 1000; i++) {"
11888 " result = o.x(42);"
11890 CHECK_EQ(41, value->Int32Value());
11894 static v8::Handle<Value> call_ic_function6;
11895 static void InterceptorCallICGetter6(
11896 Local<String> name,
11897 const v8::PropertyCallbackInfo<v8::Value>& info) {
11898 ApiTestFuzzer::Fuzz();
11899 if (v8_str("x")->Equals(name))
11900 info.GetReturnValue().Set(call_ic_function6);
11904 // Same test as above, except the code is wrapped in a function
11905 // to test the optimized compiler.
11906 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11907 i::FLAG_allow_natives_syntax = true;
11908 v8::Isolate* isolate = CcTest::isolate();
11909 v8::HandleScope scope(isolate);
11910 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11911 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11912 LocalContext context;
11913 context->Global()->Set(v8_str("o"), templ->NewInstance());
11914 call_ic_function6 =
11915 v8_compile("function f(x) { return x - 1; }; f")->Run();
11916 v8::Handle<Value> value = CompileRun(
11917 "function inc(x) { return x + 1; };"
11920 "function test() {"
11922 " for (var i = 0; i < 1000; i++) {"
11923 " result = o.x(42);"
11930 "%OptimizeFunctionOnNextCall(test);"
11932 CHECK_EQ(41, value->Int32Value());
11936 // Test the case when we stored constant function into
11937 // a stub, but it got invalidated later on
11938 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11939 v8::Isolate* isolate = CcTest::isolate();
11940 v8::HandleScope scope(isolate);
11941 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11942 templ->SetNamedPropertyHandler(NoBlockGetterX);
11943 LocalContext context;
11944 context->Global()->Set(v8_str("o"), templ->NewInstance());
11945 v8::Handle<Value> value = CompileRun(
11946 "function inc(x) { return x + 1; };"
11948 "proto1 = new Object();"
11949 "proto2 = new Object();"
11950 "o.__proto__ = proto1;"
11951 "proto1.__proto__ = proto2;"
11953 // Invoke it many times to compile a stub
11954 "for (var i = 0; i < 7; i++) {"
11957 "proto1.y = function(x) { return x - 1; };"
11959 "for (var i = 0; i < 7; i++) {"
11960 " result += o.y(42);"
11962 CHECK_EQ(41 * 7, value->Int32Value());
11966 // Test the case when we stored constant function into
11967 // a stub, but it got invalidated later on due to override on
11968 // global object which is between interceptor and constant function' holders.
11969 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11970 v8::Isolate* isolate = CcTest::isolate();
11971 v8::HandleScope scope(isolate);
11972 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11973 templ->SetNamedPropertyHandler(NoBlockGetterX);
11974 LocalContext context;
11975 context->Global()->Set(v8_str("o"), templ->NewInstance());
11976 v8::Handle<Value> value = CompileRun(
11977 "function inc(x) { return x + 1; };"
11979 "o.__proto__ = this;"
11980 "this.__proto__.y = inc;"
11981 // Invoke it many times to compile a stub
11982 "for (var i = 0; i < 7; i++) {"
11983 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11985 "this.y = function(x) { return x - 1; };"
11987 "for (var i = 0; i < 7; i++) {"
11988 " result += o.y(42);"
11990 CHECK_EQ(41 * 7, value->Int32Value());
11994 // Test the case when actual function to call sits on global object.
11995 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11996 v8::Isolate* isolate = CcTest::isolate();
11997 v8::HandleScope scope(isolate);
11998 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11999 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12001 LocalContext context;
12002 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12004 v8::Handle<Value> value = CompileRun(
12006 " o.__proto__ = this;"
12007 " for (var i = 0; i < 10; i++) {"
12008 " var v = o.parseFloat('239');"
12009 " if (v != 239) throw v;"
12010 // Now it should be ICed and keep a reference to parseFloat.
12013 " for (var i = 0; i < 10; i++) {"
12014 " result += o.parseFloat('239');"
12020 CHECK_EQ(239 * 10, value->Int32Value());
12023 static void InterceptorCallICFastApi(
12024 Local<String> name,
12025 const v8::PropertyCallbackInfo<v8::Value>& info) {
12026 ApiTestFuzzer::Fuzz();
12027 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12029 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12031 if ((*call_count) % 20 == 0) {
12032 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12036 static void FastApiCallback_TrivialSignature(
12037 const v8::FunctionCallbackInfo<v8::Value>& args) {
12038 ApiTestFuzzer::Fuzz();
12039 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12040 v8::Isolate* isolate = CcTest::isolate();
12041 CHECK_EQ(isolate, args.GetIsolate());
12042 CHECK_EQ(args.This(), args.Holder());
12043 CHECK(args.Data()->Equals(v8_str("method_data")));
12044 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12047 static void FastApiCallback_SimpleSignature(
12048 const v8::FunctionCallbackInfo<v8::Value>& args) {
12049 ApiTestFuzzer::Fuzz();
12050 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12051 v8::Isolate* isolate = CcTest::isolate();
12052 CHECK_EQ(isolate, args.GetIsolate());
12053 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12054 CHECK(args.Data()->Equals(v8_str("method_data")));
12055 // Note, we're using HasRealNamedProperty instead of Has to avoid
12056 // invoking the interceptor again.
12057 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12058 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12062 // Helper to maximize the odds of object moving.
12063 static void GenerateSomeGarbage() {
12066 "for (var i = 0; i < 1000; i++) {"
12067 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12069 "garbage = undefined;");
12073 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12074 static int count = 0;
12075 if (count++ % 3 == 0) {
12076 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12077 // This should move the stub
12078 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12083 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12084 LocalContext context;
12085 v8::Isolate* isolate = context->GetIsolate();
12086 v8::HandleScope scope(isolate);
12087 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12088 v8::ObjectTemplate::New(isolate);
12089 nativeobject_templ->Set(isolate, "callback",
12090 v8::FunctionTemplate::New(isolate,
12091 DirectApiCallback));
12092 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12093 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12094 // call the api function multiple times to ensure direct call stub creation.
12097 " for (var i = 1; i <= 30; i++) {"
12098 " nativeobject.callback();"
12105 void ThrowingDirectApiCallback(
12106 const v8::FunctionCallbackInfo<v8::Value>& args) {
12107 args.GetIsolate()->ThrowException(v8_str("g"));
12111 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12112 LocalContext context;
12113 v8::Isolate* isolate = context->GetIsolate();
12114 v8::HandleScope scope(isolate);
12115 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12116 v8::ObjectTemplate::New(isolate);
12117 nativeobject_templ->Set(isolate, "callback",
12118 v8::FunctionTemplate::New(isolate,
12119 ThrowingDirectApiCallback));
12120 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12121 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12122 // call the api function multiple times to ensure direct call stub creation.
12123 v8::Handle<Value> result = CompileRun(
12126 " for (var i = 1; i <= 5; i++) {"
12127 " try { nativeobject.callback(); } catch (e) { result += e; }"
12131 CHECK_EQ(v8_str("ggggg"), result);
12135 static Handle<Value> DoDirectGetter() {
12136 if (++p_getter_count % 3 == 0) {
12137 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12138 GenerateSomeGarbage();
12140 return v8_str("Direct Getter Result");
12143 static void DirectGetterCallback(
12144 Local<String> name,
12145 const v8::PropertyCallbackInfo<v8::Value>& info) {
12146 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12147 info.GetReturnValue().Set(DoDirectGetter());
12151 template<typename Accessor>
12152 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12153 LocalContext context;
12154 v8::Isolate* isolate = context->GetIsolate();
12155 v8::HandleScope scope(isolate);
12156 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12157 obj->SetAccessor(v8_str("p1"), accessor);
12158 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12159 p_getter_count = 0;
12160 v8::Handle<v8::Value> result = CompileRun(
12162 " for (var i = 0; i < 30; i++) o1.p1;"
12166 CHECK_EQ(v8_str("Direct Getter Result"), result);
12167 CHECK_EQ(31, p_getter_count);
12171 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12172 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12176 void ThrowingDirectGetterCallback(
12177 Local<String> name,
12178 const v8::PropertyCallbackInfo<v8::Value>& info) {
12179 info.GetIsolate()->ThrowException(v8_str("g"));
12183 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12184 LocalContext context;
12185 v8::Isolate* isolate = context->GetIsolate();
12186 v8::HandleScope scope(isolate);
12187 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12188 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12189 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12190 v8::Handle<Value> result = CompileRun(
12192 "for (var i = 0; i < 5; i++) {"
12193 " try { o1.p1; } catch (e) { result += e; }"
12196 CHECK_EQ(v8_str("ggggg"), result);
12200 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12201 int interceptor_call_count = 0;
12202 v8::Isolate* isolate = CcTest::isolate();
12203 v8::HandleScope scope(isolate);
12204 v8::Handle<v8::FunctionTemplate> fun_templ =
12205 v8::FunctionTemplate::New(isolate);
12206 v8::Handle<v8::FunctionTemplate> method_templ =
12207 v8::FunctionTemplate::New(isolate,
12208 FastApiCallback_TrivialSignature,
12209 v8_str("method_data"),
12210 v8::Handle<v8::Signature>());
12211 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12212 proto_templ->Set(v8_str("method"), method_templ);
12213 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12214 templ->SetNamedPropertyHandler(
12215 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12216 v8::External::New(isolate, &interceptor_call_count));
12217 LocalContext context;
12218 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12219 GenerateSomeGarbage();
12220 context->Global()->Set(v8_str("o"), fun->NewInstance());
12223 "for (var i = 0; i < 100; i++) {"
12224 " result = o.method(41);"
12226 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12227 CHECK_EQ(100, interceptor_call_count);
12231 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12232 int interceptor_call_count = 0;
12233 v8::Isolate* isolate = CcTest::isolate();
12234 v8::HandleScope scope(isolate);
12235 v8::Handle<v8::FunctionTemplate> fun_templ =
12236 v8::FunctionTemplate::New(isolate);
12237 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12238 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12239 v8::Signature::New(isolate, fun_templ));
12240 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12241 proto_templ->Set(v8_str("method"), method_templ);
12242 fun_templ->SetHiddenPrototype(true);
12243 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12244 templ->SetNamedPropertyHandler(
12245 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12246 v8::External::New(isolate, &interceptor_call_count));
12247 LocalContext context;
12248 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12249 GenerateSomeGarbage();
12250 context->Global()->Set(v8_str("o"), fun->NewInstance());
12253 "var receiver = {};"
12254 "receiver.__proto__ = o;"
12256 "for (var i = 0; i < 100; i++) {"
12257 " result = receiver.method(41);"
12259 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12260 CHECK_EQ(100, interceptor_call_count);
12264 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12265 int interceptor_call_count = 0;
12266 v8::Isolate* isolate = CcTest::isolate();
12267 v8::HandleScope scope(isolate);
12268 v8::Handle<v8::FunctionTemplate> fun_templ =
12269 v8::FunctionTemplate::New(isolate);
12270 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12271 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12272 v8::Signature::New(isolate, fun_templ));
12273 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12274 proto_templ->Set(v8_str("method"), method_templ);
12275 fun_templ->SetHiddenPrototype(true);
12276 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12277 templ->SetNamedPropertyHandler(
12278 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12279 v8::External::New(isolate, &interceptor_call_count));
12280 LocalContext context;
12281 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12282 GenerateSomeGarbage();
12283 context->Global()->Set(v8_str("o"), fun->NewInstance());
12286 "var receiver = {};"
12287 "receiver.__proto__ = o;"
12289 "var saved_result = 0;"
12290 "for (var i = 0; i < 100; i++) {"
12291 " result = receiver.method(41);"
12293 " saved_result = result;"
12294 " receiver = {method: function(x) { return x - 1 }};"
12297 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12298 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12299 CHECK_GE(interceptor_call_count, 50);
12303 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12304 int interceptor_call_count = 0;
12305 v8::Isolate* isolate = CcTest::isolate();
12306 v8::HandleScope scope(isolate);
12307 v8::Handle<v8::FunctionTemplate> fun_templ =
12308 v8::FunctionTemplate::New(isolate);
12309 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12310 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12311 v8::Signature::New(isolate, fun_templ));
12312 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12313 proto_templ->Set(v8_str("method"), method_templ);
12314 fun_templ->SetHiddenPrototype(true);
12315 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12316 templ->SetNamedPropertyHandler(
12317 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12318 v8::External::New(isolate, &interceptor_call_count));
12319 LocalContext context;
12320 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12321 GenerateSomeGarbage();
12322 context->Global()->Set(v8_str("o"), fun->NewInstance());
12325 "var receiver = {};"
12326 "receiver.__proto__ = o;"
12328 "var saved_result = 0;"
12329 "for (var i = 0; i < 100; i++) {"
12330 " result = receiver.method(41);"
12332 " saved_result = result;"
12333 " o.method = function(x) { return x - 1 };"
12336 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12337 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12338 CHECK_GE(interceptor_call_count, 50);
12342 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12343 int interceptor_call_count = 0;
12344 v8::Isolate* isolate = CcTest::isolate();
12345 v8::HandleScope scope(isolate);
12346 v8::Handle<v8::FunctionTemplate> fun_templ =
12347 v8::FunctionTemplate::New(isolate);
12348 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12349 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12350 v8::Signature::New(isolate, fun_templ));
12351 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12352 proto_templ->Set(v8_str("method"), method_templ);
12353 fun_templ->SetHiddenPrototype(true);
12354 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12355 templ->SetNamedPropertyHandler(
12356 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12357 v8::External::New(isolate, &interceptor_call_count));
12358 LocalContext context;
12359 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12360 GenerateSomeGarbage();
12361 context->Global()->Set(v8_str("o"), fun->NewInstance());
12362 v8::TryCatch try_catch;
12365 "var receiver = {};"
12366 "receiver.__proto__ = o;"
12368 "var saved_result = 0;"
12369 "for (var i = 0; i < 100; i++) {"
12370 " result = receiver.method(41);"
12372 " saved_result = result;"
12376 CHECK(try_catch.HasCaught());
12377 // TODO(verwaest): Adjust message.
12378 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12379 try_catch.Exception()->ToString());
12380 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12381 CHECK_GE(interceptor_call_count, 50);
12385 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12386 int interceptor_call_count = 0;
12387 v8::Isolate* isolate = CcTest::isolate();
12388 v8::HandleScope scope(isolate);
12389 v8::Handle<v8::FunctionTemplate> fun_templ =
12390 v8::FunctionTemplate::New(isolate);
12391 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12392 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12393 v8::Signature::New(isolate, fun_templ));
12394 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12395 proto_templ->Set(v8_str("method"), method_templ);
12396 fun_templ->SetHiddenPrototype(true);
12397 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12398 templ->SetNamedPropertyHandler(
12399 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12400 v8::External::New(isolate, &interceptor_call_count));
12401 LocalContext context;
12402 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12403 GenerateSomeGarbage();
12404 context->Global()->Set(v8_str("o"), fun->NewInstance());
12405 v8::TryCatch try_catch;
12408 "var receiver = {};"
12409 "receiver.__proto__ = o;"
12411 "var saved_result = 0;"
12412 "for (var i = 0; i < 100; i++) {"
12413 " result = receiver.method(41);"
12415 " saved_result = result;"
12416 " receiver = {method: receiver.method};"
12419 CHECK(try_catch.HasCaught());
12420 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12421 try_catch.Exception()->ToString());
12422 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12423 CHECK_GE(interceptor_call_count, 50);
12427 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12428 v8::Isolate* isolate = CcTest::isolate();
12429 v8::HandleScope scope(isolate);
12430 v8::Handle<v8::FunctionTemplate> fun_templ =
12431 v8::FunctionTemplate::New(isolate);
12432 v8::Handle<v8::FunctionTemplate> method_templ =
12433 v8::FunctionTemplate::New(isolate,
12434 FastApiCallback_TrivialSignature,
12435 v8_str("method_data"),
12436 v8::Handle<v8::Signature>());
12437 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12438 proto_templ->Set(v8_str("method"), method_templ);
12439 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12441 LocalContext context;
12442 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12443 GenerateSomeGarbage();
12444 context->Global()->Set(v8_str("o"), fun->NewInstance());
12447 "for (var i = 0; i < 100; i++) {"
12448 " result = o.method(41);"
12451 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12455 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12456 v8::Isolate* isolate = CcTest::isolate();
12457 v8::HandleScope scope(isolate);
12458 v8::Handle<v8::FunctionTemplate> fun_templ =
12459 v8::FunctionTemplate::New(isolate);
12460 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12461 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12462 v8::Signature::New(isolate, fun_templ));
12463 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12464 proto_templ->Set(v8_str("method"), method_templ);
12465 fun_templ->SetHiddenPrototype(true);
12466 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12467 CHECK(!templ.IsEmpty());
12468 LocalContext context;
12469 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12470 GenerateSomeGarbage();
12471 context->Global()->Set(v8_str("o"), fun->NewInstance());
12474 "var receiver = {};"
12475 "receiver.__proto__ = o;"
12477 "for (var i = 0; i < 100; i++) {"
12478 " result = receiver.method(41);"
12481 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12485 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12486 v8::Isolate* isolate = CcTest::isolate();
12487 v8::HandleScope scope(isolate);
12488 v8::Handle<v8::FunctionTemplate> fun_templ =
12489 v8::FunctionTemplate::New(isolate);
12490 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12491 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12492 v8::Signature::New(isolate, fun_templ));
12493 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12494 proto_templ->Set(v8_str("method"), method_templ);
12495 fun_templ->SetHiddenPrototype(true);
12496 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12497 CHECK(!templ.IsEmpty());
12498 LocalContext context;
12499 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12500 GenerateSomeGarbage();
12501 context->Global()->Set(v8_str("o"), fun->NewInstance());
12504 "var receiver = {};"
12505 "receiver.__proto__ = o;"
12507 "var saved_result = 0;"
12508 "for (var i = 0; i < 100; i++) {"
12509 " result = receiver.method(41);"
12511 " saved_result = result;"
12512 " receiver = {method: function(x) { return x - 1 }};"
12515 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12516 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12520 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12521 v8::Isolate* isolate = CcTest::isolate();
12522 v8::HandleScope scope(isolate);
12523 v8::Handle<v8::FunctionTemplate> fun_templ =
12524 v8::FunctionTemplate::New(isolate);
12525 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12526 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12527 v8::Signature::New(isolate, fun_templ));
12528 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12529 proto_templ->Set(v8_str("method"), method_templ);
12530 fun_templ->SetHiddenPrototype(true);
12531 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12532 CHECK(!templ.IsEmpty());
12533 LocalContext context;
12534 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12535 GenerateSomeGarbage();
12536 context->Global()->Set(v8_str("o"), fun->NewInstance());
12537 v8::TryCatch try_catch;
12540 "var receiver = {};"
12541 "receiver.__proto__ = o;"
12543 "var saved_result = 0;"
12544 "for (var i = 0; i < 100; i++) {"
12545 " result = receiver.method(41);"
12547 " saved_result = result;"
12551 CHECK(try_catch.HasCaught());
12552 // TODO(verwaest): Adjust message.
12553 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12554 try_catch.Exception()->ToString());
12555 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12559 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12560 v8::Isolate* isolate = CcTest::isolate();
12561 v8::HandleScope scope(isolate);
12562 v8::Handle<v8::FunctionTemplate> fun_templ =
12563 v8::FunctionTemplate::New(isolate);
12564 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12565 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12566 v8::Signature::New(isolate, fun_templ));
12567 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12568 proto_templ->Set(v8_str("method"), method_templ);
12569 fun_templ->SetHiddenPrototype(true);
12570 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12571 CHECK(!templ.IsEmpty());
12572 LocalContext context;
12573 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12574 GenerateSomeGarbage();
12575 context->Global()->Set(v8_str("o"), fun->NewInstance());
12576 v8::TryCatch try_catch;
12579 "var receiver = {};"
12580 "receiver.__proto__ = o;"
12582 "var saved_result = 0;"
12583 "for (var i = 0; i < 100; i++) {"
12584 " result = receiver.method(41);"
12586 " saved_result = result;"
12587 " receiver = Object.create(receiver);"
12590 CHECK(try_catch.HasCaught());
12591 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12592 try_catch.Exception()->ToString());
12593 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12597 v8::Handle<Value> keyed_call_ic_function;
12599 static void InterceptorKeyedCallICGetter(
12600 Local<String> name,
12601 const v8::PropertyCallbackInfo<v8::Value>& info) {
12602 ApiTestFuzzer::Fuzz();
12603 if (v8_str("x")->Equals(name)) {
12604 info.GetReturnValue().Set(keyed_call_ic_function);
12609 // Test the case when we stored cacheable lookup into
12610 // a stub, but the function name changed (to another cacheable function).
12611 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12612 v8::Isolate* isolate = CcTest::isolate();
12613 v8::HandleScope scope(isolate);
12614 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12615 templ->SetNamedPropertyHandler(NoBlockGetterX);
12616 LocalContext context;
12617 context->Global()->Set(v8_str("o"), templ->NewInstance());
12619 "proto = new Object();"
12620 "proto.y = function(x) { return x + 1; };"
12621 "proto.z = function(x) { return x - 1; };"
12622 "o.__proto__ = proto;"
12624 "var method = 'y';"
12625 "for (var i = 0; i < 10; i++) {"
12626 " if (i == 5) { method = 'z'; };"
12627 " result += o[method](41);"
12629 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12633 // Test the case when we stored cacheable lookup into
12634 // a stub, but the function name changed (and the new function is present
12635 // both before and after the interceptor in the prototype chain).
12636 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12637 v8::Isolate* isolate = CcTest::isolate();
12638 v8::HandleScope scope(isolate);
12639 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12640 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12641 LocalContext context;
12642 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12643 keyed_call_ic_function =
12644 v8_compile("function f(x) { return x - 1; }; f")->Run();
12646 "o = new Object();"
12647 "proto2 = new Object();"
12648 "o.y = function(x) { return x + 1; };"
12649 "proto2.y = function(x) { return x + 2; };"
12650 "o.__proto__ = proto1;"
12651 "proto1.__proto__ = proto2;"
12653 "var method = 'x';"
12654 "for (var i = 0; i < 10; i++) {"
12655 " if (i == 5) { method = 'y'; };"
12656 " result += o[method](41);"
12658 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12662 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12663 // on the global object.
12664 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12665 v8::Isolate* isolate = CcTest::isolate();
12666 v8::HandleScope scope(isolate);
12667 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12668 templ->SetNamedPropertyHandler(NoBlockGetterX);
12669 LocalContext context;
12670 context->Global()->Set(v8_str("o"), templ->NewInstance());
12672 "function inc(x) { return x + 1; };"
12674 "function dec(x) { return x - 1; };"
12676 "o.__proto__ = this;"
12677 "this.__proto__.x = inc;"
12678 "this.__proto__.y = dec;"
12680 "var method = 'x';"
12681 "for (var i = 0; i < 10; i++) {"
12682 " if (i == 5) { method = 'y'; };"
12683 " result += o[method](41);"
12685 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12689 // Test the case when actual function to call sits on global object.
12690 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12691 v8::Isolate* isolate = CcTest::isolate();
12692 v8::HandleScope scope(isolate);
12693 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12694 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12695 LocalContext context;
12696 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12699 "function len(x) { return x.length; };"
12700 "o.__proto__ = this;"
12701 "var m = 'parseFloat';"
12703 "for (var i = 0; i < 10; i++) {"
12706 " saved_result = result;"
12708 " result = o[m]('239');"
12710 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12711 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12715 // Test the map transition before the interceptor.
12716 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12717 v8::Isolate* isolate = CcTest::isolate();
12718 v8::HandleScope scope(isolate);
12719 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12720 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12721 LocalContext context;
12722 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12725 "var o = new Object();"
12726 "o.__proto__ = proto;"
12727 "o.method = function(x) { return x + 1; };"
12728 "var m = 'method';"
12730 "for (var i = 0; i < 10; i++) {"
12731 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12732 " result += o[m](41);"
12734 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12738 // Test the map transition after the interceptor.
12739 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12740 v8::Isolate* isolate = CcTest::isolate();
12741 v8::HandleScope scope(isolate);
12742 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12743 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12744 LocalContext context;
12745 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12748 "var proto = new Object();"
12749 "o.__proto__ = proto;"
12750 "proto.method = function(x) { return x + 1; };"
12751 "var m = 'method';"
12753 "for (var i = 0; i < 10; i++) {"
12754 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12755 " result += o[m](41);"
12757 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12761 static int interceptor_call_count = 0;
12763 static void InterceptorICRefErrorGetter(
12764 Local<String> name,
12765 const v8::PropertyCallbackInfo<v8::Value>& info) {
12766 ApiTestFuzzer::Fuzz();
12767 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12768 info.GetReturnValue().Set(call_ic_function2);
12773 // This test should hit load and call ICs for the interceptor case.
12774 // Once in a while, the interceptor will reply that a property was not
12775 // found in which case we should get a reference error.
12776 THREADED_TEST(InterceptorICReferenceErrors) {
12777 v8::Isolate* isolate = CcTest::isolate();
12778 v8::HandleScope scope(isolate);
12779 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12780 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12781 LocalContext context(0, templ, v8::Handle<Value>());
12782 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12783 v8::Handle<Value> value = CompileRun(
12785 " for (var i = 0; i < 1000; i++) {"
12786 " try { x; } catch(e) { return true; }"
12791 CHECK_EQ(true, value->BooleanValue());
12792 interceptor_call_count = 0;
12793 value = CompileRun(
12795 " for (var i = 0; i < 1000; i++) {"
12796 " try { x(42); } catch(e) { return true; }"
12801 CHECK_EQ(true, value->BooleanValue());
12805 static int interceptor_ic_exception_get_count = 0;
12807 static void InterceptorICExceptionGetter(
12808 Local<String> name,
12809 const v8::PropertyCallbackInfo<v8::Value>& info) {
12810 ApiTestFuzzer::Fuzz();
12811 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12812 info.GetReturnValue().Set(call_ic_function3);
12814 if (interceptor_ic_exception_get_count == 20) {
12815 info.GetIsolate()->ThrowException(v8_num(42));
12821 // Test interceptor load/call IC where the interceptor throws an
12822 // exception once in a while.
12823 THREADED_TEST(InterceptorICGetterExceptions) {
12824 interceptor_ic_exception_get_count = 0;
12825 v8::Isolate* isolate = CcTest::isolate();
12826 v8::HandleScope scope(isolate);
12827 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12828 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12829 LocalContext context(0, templ, v8::Handle<Value>());
12830 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12831 v8::Handle<Value> value = CompileRun(
12833 " for (var i = 0; i < 100; i++) {"
12834 " try { x; } catch(e) { return true; }"
12839 CHECK_EQ(true, value->BooleanValue());
12840 interceptor_ic_exception_get_count = 0;
12841 value = CompileRun(
12843 " for (var i = 0; i < 100; i++) {"
12844 " try { x(42); } catch(e) { return true; }"
12849 CHECK_EQ(true, value->BooleanValue());
12853 static int interceptor_ic_exception_set_count = 0;
12855 static void InterceptorICExceptionSetter(
12857 Local<Value> value,
12858 const v8::PropertyCallbackInfo<v8::Value>& info) {
12859 ApiTestFuzzer::Fuzz();
12860 if (++interceptor_ic_exception_set_count > 20) {
12861 info.GetIsolate()->ThrowException(v8_num(42));
12866 // Test interceptor store IC where the interceptor throws an exception
12867 // once in a while.
12868 THREADED_TEST(InterceptorICSetterExceptions) {
12869 interceptor_ic_exception_set_count = 0;
12870 v8::Isolate* isolate = CcTest::isolate();
12871 v8::HandleScope scope(isolate);
12872 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12873 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12874 LocalContext context(0, templ, v8::Handle<Value>());
12875 v8::Handle<Value> value = CompileRun(
12877 " for (var i = 0; i < 100; i++) {"
12878 " try { x = 42; } catch(e) { return true; }"
12883 CHECK_EQ(true, value->BooleanValue());
12887 // Test that we ignore null interceptors.
12888 THREADED_TEST(NullNamedInterceptor) {
12889 v8::Isolate* isolate = CcTest::isolate();
12890 v8::HandleScope scope(isolate);
12891 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12892 templ->SetNamedPropertyHandler(
12893 static_cast<v8::NamedPropertyGetterCallback>(0));
12894 LocalContext context;
12895 templ->Set(CcTest::isolate(), "x", v8_num(42));
12896 v8::Handle<v8::Object> obj = templ->NewInstance();
12897 context->Global()->Set(v8_str("obj"), obj);
12898 v8::Handle<Value> value = CompileRun("obj.x");
12899 CHECK(value->IsInt32());
12900 CHECK_EQ(42, value->Int32Value());
12904 // Test that we ignore null interceptors.
12905 THREADED_TEST(NullIndexedInterceptor) {
12906 v8::Isolate* isolate = CcTest::isolate();
12907 v8::HandleScope scope(isolate);
12908 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12909 templ->SetIndexedPropertyHandler(
12910 static_cast<v8::IndexedPropertyGetterCallback>(0));
12911 LocalContext context;
12912 templ->Set(CcTest::isolate(), "42", v8_num(42));
12913 v8::Handle<v8::Object> obj = templ->NewInstance();
12914 context->Global()->Set(v8_str("obj"), obj);
12915 v8::Handle<Value> value = CompileRun("obj[42]");
12916 CHECK(value->IsInt32());
12917 CHECK_EQ(42, value->Int32Value());
12921 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12922 v8::Isolate* isolate = CcTest::isolate();
12923 v8::HandleScope scope(isolate);
12924 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12925 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12927 env->Global()->Set(v8_str("obj"),
12928 templ->GetFunction()->NewInstance());
12929 ExpectTrue("obj.x === 42");
12930 ExpectTrue("!obj.propertyIsEnumerable('x')");
12934 static void ThrowingGetter(Local<String> name,
12935 const v8::PropertyCallbackInfo<v8::Value>& info) {
12936 ApiTestFuzzer::Fuzz();
12937 info.GetIsolate()->ThrowException(Handle<Value>());
12938 info.GetReturnValue().SetUndefined();
12942 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12943 LocalContext context;
12944 HandleScope scope(context->GetIsolate());
12946 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12947 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12948 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12950 Local<Object> instance = templ->GetFunction()->NewInstance();
12952 Local<Object> another = Object::New(context->GetIsolate());
12953 another->SetPrototype(instance);
12955 Local<Object> with_js_getter = CompileRun(
12957 "o.__defineGetter__('f', function() { throw undefined; });\n"
12958 "o\n").As<Object>();
12959 CHECK(!with_js_getter.IsEmpty());
12961 TryCatch try_catch;
12963 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12964 CHECK(try_catch.HasCaught());
12966 CHECK(result.IsEmpty());
12968 result = another->GetRealNamedProperty(v8_str("f"));
12969 CHECK(try_catch.HasCaught());
12971 CHECK(result.IsEmpty());
12973 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12974 CHECK(try_catch.HasCaught());
12976 CHECK(result.IsEmpty());
12978 result = another->Get(v8_str("f"));
12979 CHECK(try_catch.HasCaught());
12981 CHECK(result.IsEmpty());
12983 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12984 CHECK(try_catch.HasCaught());
12986 CHECK(result.IsEmpty());
12988 result = with_js_getter->Get(v8_str("f"));
12989 CHECK(try_catch.HasCaught());
12991 CHECK(result.IsEmpty());
12995 static void ThrowingCallbackWithTryCatch(
12996 const v8::FunctionCallbackInfo<v8::Value>& args) {
12997 TryCatch try_catch;
12998 // Verboseness is important: it triggers message delivery which can call into
13000 try_catch.SetVerbose(true);
13001 CompileRun("throw 'from JS';");
13002 CHECK(try_catch.HasCaught());
13003 CHECK(!CcTest::i_isolate()->has_pending_exception());
13004 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13008 static int call_depth;
13011 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13012 TryCatch try_catch;
13016 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13017 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13021 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13022 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13026 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13027 Handle<String> errorMessageString = message->Get();
13028 CHECK(!errorMessageString.IsEmpty());
13029 message->GetStackTrace();
13030 message->GetScriptResourceName();
13034 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13035 LocalContext context;
13036 v8::Isolate* isolate = context->GetIsolate();
13037 HandleScope scope(isolate);
13039 Local<Function> func =
13040 FunctionTemplate::New(isolate,
13041 ThrowingCallbackWithTryCatch)->GetFunction();
13042 context->Global()->Set(v8_str("func"), func);
13044 MessageCallback callbacks[] =
13045 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13046 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13047 MessageCallback callback = callbacks[i];
13048 if (callback != NULL) {
13049 V8::AddMessageListener(callback);
13051 // Some small number to control number of times message handler should
13052 // throw an exception.
13055 "var thrown = false;\n"
13056 "try { func(); } catch(e) { thrown = true; }\n"
13058 if (callback != NULL) {
13059 V8::RemoveMessageListeners(callback);
13065 static void ParentGetter(Local<String> name,
13066 const v8::PropertyCallbackInfo<v8::Value>& info) {
13067 ApiTestFuzzer::Fuzz();
13068 info.GetReturnValue().Set(v8_num(1));
13072 static void ChildGetter(Local<String> name,
13073 const v8::PropertyCallbackInfo<v8::Value>& info) {
13074 ApiTestFuzzer::Fuzz();
13075 info.GetReturnValue().Set(v8_num(42));
13079 THREADED_TEST(Overriding) {
13080 LocalContext context;
13081 v8::Isolate* isolate = context->GetIsolate();
13082 v8::HandleScope scope(isolate);
13084 // Parent template.
13085 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13086 Local<ObjectTemplate> parent_instance_templ =
13087 parent_templ->InstanceTemplate();
13088 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13090 // Template that inherits from the parent template.
13091 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13092 Local<ObjectTemplate> child_instance_templ =
13093 child_templ->InstanceTemplate();
13094 child_templ->Inherit(parent_templ);
13095 // Override 'f'. The child version of 'f' should get called for child
13097 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13098 // Add 'g' twice. The 'g' added last should get called for instances.
13099 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13100 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13102 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13103 // so 'h' can be shadowed on the instance object.
13104 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13105 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13106 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13108 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13109 // but the attribute does not have effect because it is duplicated with
13111 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13112 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13116 // Instantiate the child template.
13117 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13119 // Check that the child function overrides the parent one.
13120 context->Global()->Set(v8_str("o"), instance);
13121 Local<Value> value = v8_compile("o.f")->Run();
13122 // Check that the 'g' that was added last is hit.
13123 CHECK_EQ(42, value->Int32Value());
13124 value = v8_compile("o.g")->Run();
13125 CHECK_EQ(42, value->Int32Value());
13127 // Check that 'h' cannot be shadowed.
13128 value = v8_compile("o.h = 3; o.h")->Run();
13129 CHECK_EQ(1, value->Int32Value());
13131 // Check that 'i' cannot be shadowed or changed.
13132 value = v8_compile("o.i = 3; o.i")->Run();
13133 CHECK_EQ(42, value->Int32Value());
13137 static void IsConstructHandler(
13138 const v8::FunctionCallbackInfo<v8::Value>& args) {
13139 ApiTestFuzzer::Fuzz();
13140 args.GetReturnValue().Set(args.IsConstructCall());
13144 THREADED_TEST(IsConstructCall) {
13145 v8::Isolate* isolate = CcTest::isolate();
13146 v8::HandleScope scope(isolate);
13148 // Function template with call handler.
13149 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13150 templ->SetCallHandler(IsConstructHandler);
13152 LocalContext context;
13154 context->Global()->Set(v8_str("f"), templ->GetFunction());
13155 Local<Value> value = v8_compile("f()")->Run();
13156 CHECK(!value->BooleanValue());
13157 value = v8_compile("new f()")->Run();
13158 CHECK(value->BooleanValue());
13162 THREADED_TEST(ObjectProtoToString) {
13163 v8::Isolate* isolate = CcTest::isolate();
13164 v8::HandleScope scope(isolate);
13165 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13166 templ->SetClassName(v8_str("MyClass"));
13168 LocalContext context;
13170 Local<String> customized_tostring = v8_str("customized toString");
13172 // Replace Object.prototype.toString
13173 v8_compile("Object.prototype.toString = function() {"
13174 " return 'customized toString';"
13177 // Normal ToString call should call replaced Object.prototype.toString
13178 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13179 Local<String> value = instance->ToString();
13180 CHECK(value->IsString() && value->Equals(customized_tostring));
13182 // ObjectProtoToString should not call replace toString function.
13183 value = instance->ObjectProtoToString();
13184 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13187 value = context->Global()->ObjectProtoToString();
13188 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13190 // Check ordinary object
13191 Local<Value> object = v8_compile("new Object()")->Run();
13192 value = object.As<v8::Object>()->ObjectProtoToString();
13193 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13197 THREADED_TEST(ObjectGetConstructorName) {
13198 LocalContext context;
13199 v8::HandleScope scope(context->GetIsolate());
13200 v8_compile("function Parent() {};"
13201 "function Child() {};"
13202 "Child.prototype = new Parent();"
13203 "var outer = { inner: function() { } };"
13204 "var p = new Parent();"
13205 "var c = new Child();"
13206 "var x = new outer.inner();")->Run();
13208 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13209 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13210 v8_str("Parent")));
13212 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13213 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13216 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13217 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13218 v8_str("outer.inner")));
13222 bool ApiTestFuzzer::fuzzing_ = false;
13223 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13224 int ApiTestFuzzer::active_tests_;
13225 int ApiTestFuzzer::tests_being_run_;
13226 int ApiTestFuzzer::current_;
13229 // We are in a callback and want to switch to another thread (if we
13230 // are currently running the thread fuzzing test).
13231 void ApiTestFuzzer::Fuzz() {
13232 if (!fuzzing_) return;
13233 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13234 test->ContextSwitch();
13238 // Let the next thread go. Since it is also waiting on the V8 lock it may
13239 // not start immediately.
13240 bool ApiTestFuzzer::NextThread() {
13241 int test_position = GetNextTestNumber();
13242 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13243 if (test_position == current_) {
13245 printf("Stay with %s\n", test_name);
13248 if (kLogThreading) {
13249 printf("Switch from %s to %s\n",
13251 RegisterThreadedTest::nth(test_position)->name());
13253 current_ = test_position;
13254 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13259 void ApiTestFuzzer::Run() {
13260 // When it is our turn...
13263 // ... get the V8 lock and start running the test.
13264 v8::Locker locker(CcTest::isolate());
13267 // This test finished.
13270 // If it was the last then signal that fact.
13271 if (active_tests_ == 0) {
13272 all_tests_done_.Signal();
13274 // Otherwise select a new test and start that.
13280 static unsigned linear_congruential_generator;
13283 void ApiTestFuzzer::SetUp(PartOfTest part) {
13284 linear_congruential_generator = i::FLAG_testing_prng_seed;
13286 int count = RegisterThreadedTest::count();
13287 int start = count * part / (LAST_PART + 1);
13288 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13289 active_tests_ = tests_being_run_ = end - start + 1;
13290 for (int i = 0; i < tests_being_run_; i++) {
13291 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13293 for (int i = 0; i < active_tests_; i++) {
13294 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13299 static void CallTestNumber(int test_number) {
13300 (RegisterThreadedTest::nth(test_number)->callback())();
13304 void ApiTestFuzzer::RunAllTests() {
13305 // Set off the first test.
13308 // Wait till they are all done.
13309 all_tests_done_.Wait();
13313 int ApiTestFuzzer::GetNextTestNumber() {
13316 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13317 linear_congruential_generator *= 1664525u;
13318 linear_congruential_generator += 1013904223u;
13319 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13324 void ApiTestFuzzer::ContextSwitch() {
13325 // If the new thread is the same as the current thread there is nothing to do.
13326 if (NextThread()) {
13327 // Now it can start.
13328 v8::Unlocker unlocker(CcTest::isolate());
13329 // Wait till someone starts us again.
13336 void ApiTestFuzzer::TearDown() {
13338 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13339 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13340 if (fuzzer != NULL) fuzzer->Join();
13345 // Lets not be needlessly self-referential.
13347 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13348 ApiTestFuzzer::RunAllTests();
13349 ApiTestFuzzer::TearDown();
13354 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13355 ApiTestFuzzer::RunAllTests();
13356 ApiTestFuzzer::TearDown();
13361 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13362 ApiTestFuzzer::RunAllTests();
13363 ApiTestFuzzer::TearDown();
13368 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13369 ApiTestFuzzer::RunAllTests();
13370 ApiTestFuzzer::TearDown();
13374 void ApiTestFuzzer::CallTest() {
13375 v8::Isolate::Scope scope(CcTest::isolate());
13377 printf("Start test %d\n", test_number_);
13378 CallTestNumber(test_number_);
13380 printf("End test %d\n", test_number_);
13384 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13385 v8::Isolate* isolate = args.GetIsolate();
13386 CHECK(v8::Locker::IsLocked(isolate));
13387 ApiTestFuzzer::Fuzz();
13388 v8::Unlocker unlocker(isolate);
13389 const char* code = "throw 7;";
13391 v8::Locker nested_locker(isolate);
13392 v8::HandleScope scope(isolate);
13393 v8::Handle<Value> exception;
13394 { v8::TryCatch try_catch;
13395 v8::Handle<Value> value = CompileRun(code);
13396 CHECK(value.IsEmpty());
13397 CHECK(try_catch.HasCaught());
13398 // Make sure to wrap the exception in a new handle because
13399 // the handle returned from the TryCatch is destroyed
13400 // when the TryCatch is destroyed.
13401 exception = Local<Value>::New(isolate, try_catch.Exception());
13403 args.GetIsolate()->ThrowException(exception);
13408 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13409 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13410 ApiTestFuzzer::Fuzz();
13411 v8::Unlocker unlocker(CcTest::isolate());
13412 const char* code = "throw 7;";
13414 v8::Locker nested_locker(CcTest::isolate());
13415 v8::HandleScope scope(args.GetIsolate());
13416 v8::Handle<Value> value = CompileRun(code);
13417 CHECK(value.IsEmpty());
13418 args.GetReturnValue().Set(v8_str("foo"));
13423 // These are locking tests that don't need to be run again
13424 // as part of the locking aggregation tests.
13425 TEST(NestedLockers) {
13426 v8::Isolate* isolate = CcTest::isolate();
13427 v8::Locker locker(isolate);
13428 CHECK(v8::Locker::IsLocked(isolate));
13430 v8::HandleScope scope(env->GetIsolate());
13431 Local<v8::FunctionTemplate> fun_templ =
13432 v8::FunctionTemplate::New(isolate, ThrowInJS);
13433 Local<Function> fun = fun_templ->GetFunction();
13434 env->Global()->Set(v8_str("throw_in_js"), fun);
13435 Local<Script> script = v8_compile("(function () {"
13443 CHECK_EQ(91, script->Run()->Int32Value());
13447 // These are locking tests that don't need to be run again
13448 // as part of the locking aggregation tests.
13449 TEST(NestedLockersNoTryCatch) {
13450 v8::Locker locker(CcTest::isolate());
13452 v8::HandleScope scope(env->GetIsolate());
13453 Local<v8::FunctionTemplate> fun_templ =
13454 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13455 Local<Function> fun = fun_templ->GetFunction();
13456 env->Global()->Set(v8_str("throw_in_js"), fun);
13457 Local<Script> script = v8_compile("(function () {"
13465 CHECK_EQ(91, script->Run()->Int32Value());
13469 THREADED_TEST(RecursiveLocking) {
13470 v8::Locker locker(CcTest::isolate());
13472 v8::Locker locker2(CcTest::isolate());
13473 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13478 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13479 ApiTestFuzzer::Fuzz();
13480 v8::Unlocker unlocker(CcTest::isolate());
13484 THREADED_TEST(LockUnlockLock) {
13486 v8::Locker locker(CcTest::isolate());
13487 v8::HandleScope scope(CcTest::isolate());
13489 Local<v8::FunctionTemplate> fun_templ =
13490 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13491 Local<Function> fun = fun_templ->GetFunction();
13492 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13493 Local<Script> script = v8_compile("(function () {"
13494 " unlock_for_a_moment();"
13497 CHECK_EQ(42, script->Run()->Int32Value());
13500 v8::Locker locker(CcTest::isolate());
13501 v8::HandleScope scope(CcTest::isolate());
13503 Local<v8::FunctionTemplate> fun_templ =
13504 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13505 Local<Function> fun = fun_templ->GetFunction();
13506 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13507 Local<Script> script = v8_compile("(function () {"
13508 " unlock_for_a_moment();"
13511 CHECK_EQ(42, script->Run()->Int32Value());
13516 static int GetGlobalObjectsCount() {
13517 CcTest::heap()->EnsureHeapIsIterable();
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::OS::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());
15835 i::USE(no_failure);
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());
15841 i::USE(no_failure);
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());
15847 i::USE(no_failure);
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::OS::SNPrintF(test_buf,
16322 result = CompileRun(test_buf.start());
16323 CHECK_EQ(low, result->IntegerValue());
16325 i::OS::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::OS::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::OS::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::OS::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::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17545 CHECK(CompileRun(code.start())->IsUndefined());
17546 i::OS::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->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::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17628 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17629 i::OS::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::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17674 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17675 i::OS::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::OS::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::OS::MemCopy(&target, &value, sizeof(target));
18101 static uint64_t DoubleToBits(double value) {
18103 i::OS::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->GetId(), foo->ScriptId());
18515 CHECK_EQ(script->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("
19255 // HasLocalElement.
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(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19273 CHECK(current_isolate != isolate);
19274 CHECK(current_isolate == CcTest::isolate());
19276 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19277 last_location = last_message = NULL;
19278 isolate->Dispose();
19279 CHECK_EQ(last_location, NULL);
19280 CHECK_EQ(last_message, NULL);
19284 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19285 v8::Isolate* isolate = v8::Isolate::New();
19287 v8::Isolate::Scope i_scope(isolate);
19288 v8::HandleScope scope(isolate);
19289 LocalContext context(isolate);
19290 // Run something in this isolate.
19291 ExpectTrue("true");
19292 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19293 last_location = last_message = NULL;
19294 // Still entered, should fail.
19295 isolate->Dispose();
19296 CHECK_NE(last_location, NULL);
19297 CHECK_NE(last_message, NULL);
19299 isolate->Dispose();
19303 TEST(RunTwoIsolatesOnSingleThread) {
19305 v8::Isolate* isolate1 = v8::Isolate::New();
19307 v8::Persistent<v8::Context> context1;
19309 v8::HandleScope scope(isolate1);
19310 context1.Reset(isolate1, Context::New(isolate1));
19314 v8::HandleScope scope(isolate1);
19315 v8::Local<v8::Context> context =
19316 v8::Local<v8::Context>::New(isolate1, context1);
19317 v8::Context::Scope context_scope(context);
19318 // Run something in new isolate.
19319 CompileRun("var foo = 'isolate 1';");
19320 ExpectString("function f() { return foo; }; f()", "isolate 1");
19324 v8::Isolate* isolate2 = v8::Isolate::New();
19325 v8::Persistent<v8::Context> context2;
19328 v8::Isolate::Scope iscope(isolate2);
19329 v8::HandleScope scope(isolate2);
19330 context2.Reset(isolate2, Context::New(isolate2));
19331 v8::Local<v8::Context> context =
19332 v8::Local<v8::Context>::New(isolate2, context2);
19333 v8::Context::Scope context_scope(context);
19335 // Run something in new isolate.
19336 CompileRun("var foo = 'isolate 2';");
19337 ExpectString("function f() { return foo; }; f()", "isolate 2");
19341 v8::HandleScope scope(isolate1);
19342 v8::Local<v8::Context> context =
19343 v8::Local<v8::Context>::New(isolate1, context1);
19344 v8::Context::Scope context_scope(context);
19345 // Now again in isolate 1
19346 ExpectString("function f() { return foo; }; f()", "isolate 1");
19351 // Run some stuff in default isolate.
19352 v8::Persistent<v8::Context> context_default;
19354 v8::Isolate* isolate = CcTest::isolate();
19355 v8::Isolate::Scope iscope(isolate);
19356 v8::HandleScope scope(isolate);
19357 context_default.Reset(isolate, Context::New(isolate));
19361 v8::HandleScope scope(CcTest::isolate());
19362 v8::Local<v8::Context> context =
19363 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19364 v8::Context::Scope context_scope(context);
19365 // Variables in other isolates should be not available, verify there
19366 // is an exception.
19367 ExpectTrue("function f() {"
19375 "var isDefaultIsolate = true;"
19382 v8::Isolate::Scope iscope(isolate2);
19383 v8::HandleScope scope(isolate2);
19384 v8::Local<v8::Context> context =
19385 v8::Local<v8::Context>::New(isolate2, context2);
19386 v8::Context::Scope context_scope(context);
19387 ExpectString("function f() { return foo; }; f()", "isolate 2");
19391 v8::HandleScope scope(v8::Isolate::GetCurrent());
19392 v8::Local<v8::Context> context =
19393 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19394 v8::Context::Scope context_scope(context);
19395 ExpectString("function f() { return foo; }; f()", "isolate 1");
19399 v8::Isolate::Scope iscope(isolate2);
19406 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19407 last_location = last_message = NULL;
19409 isolate1->Dispose();
19410 CHECK_EQ(last_location, NULL);
19411 CHECK_EQ(last_message, NULL);
19413 isolate2->Dispose();
19414 CHECK_EQ(last_location, NULL);
19415 CHECK_EQ(last_message, NULL);
19417 // Check that default isolate still runs.
19419 v8::HandleScope scope(CcTest::isolate());
19420 v8::Local<v8::Context> context =
19421 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19422 v8::Context::Scope context_scope(context);
19423 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19428 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19429 v8::Isolate::Scope isolate_scope(isolate);
19430 v8::HandleScope scope(isolate);
19431 LocalContext context(isolate);
19432 i::ScopedVector<char> code(1024);
19433 i::OS::SNPrintF(code, "function fib(n) {"
19434 " if (n <= 2) return 1;"
19435 " return fib(n-1) + fib(n-2);"
19438 Local<Value> value = CompileRun(code.start());
19439 CHECK(value->IsNumber());
19440 return static_cast<int>(value->NumberValue());
19443 class IsolateThread : public v8::internal::Thread {
19445 IsolateThread(v8::Isolate* isolate, int fib_limit)
19446 : Thread("IsolateThread"),
19448 fib_limit_(fib_limit),
19452 result_ = CalcFibonacci(isolate_, fib_limit_);
19455 int result() { return result_; }
19458 v8::Isolate* isolate_;
19464 TEST(MultipleIsolatesOnIndividualThreads) {
19465 v8::Isolate* isolate1 = v8::Isolate::New();
19466 v8::Isolate* isolate2 = v8::Isolate::New();
19468 IsolateThread thread1(isolate1, 21);
19469 IsolateThread thread2(isolate2, 12);
19471 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19475 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19476 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19481 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19482 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19483 CHECK_EQ(result1, 10946);
19484 CHECK_EQ(result2, 144);
19485 CHECK_EQ(result1, thread1.result());
19486 CHECK_EQ(result2, thread2.result());
19488 isolate1->Dispose();
19489 isolate2->Dispose();
19493 TEST(IsolateDifferentContexts) {
19494 v8::Isolate* isolate = v8::Isolate::New();
19495 Local<v8::Context> context;
19497 v8::Isolate::Scope isolate_scope(isolate);
19498 v8::HandleScope handle_scope(isolate);
19499 context = v8::Context::New(isolate);
19500 v8::Context::Scope context_scope(context);
19501 Local<Value> v = CompileRun("2");
19502 CHECK(v->IsNumber());
19503 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19506 v8::Isolate::Scope isolate_scope(isolate);
19507 v8::HandleScope handle_scope(isolate);
19508 context = v8::Context::New(isolate);
19509 v8::Context::Scope context_scope(context);
19510 Local<Value> v = CompileRun("22");
19511 CHECK(v->IsNumber());
19512 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19514 isolate->Dispose();
19517 class InitDefaultIsolateThread : public v8::internal::Thread {
19520 SetResourceConstraints,
19522 SetCounterFunction,
19523 SetCreateHistogramFunction,
19524 SetAddHistogramSampleFunction
19527 explicit InitDefaultIsolateThread(TestCase testCase)
19528 : Thread("InitDefaultIsolateThread"),
19529 testCase_(testCase),
19533 v8::Isolate* isolate = v8::Isolate::New();
19535 switch (testCase_) {
19536 case SetResourceConstraints: {
19537 static const int K = 1024;
19538 v8::ResourceConstraints constraints;
19539 constraints.set_max_new_space_size(2 * K * K);
19540 constraints.set_max_old_space_size(4 * K * K);
19541 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19545 case SetFatalHandler:
19546 v8::V8::SetFatalErrorHandler(NULL);
19549 case SetCounterFunction:
19550 v8::V8::SetCounterFunction(NULL);
19553 case SetCreateHistogramFunction:
19554 v8::V8::SetCreateHistogramFunction(NULL);
19557 case SetAddHistogramSampleFunction:
19558 v8::V8::SetAddHistogramSampleFunction(NULL);
19562 isolate->Dispose();
19566 bool result() { return result_; }
19569 TestCase testCase_;
19574 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19575 InitDefaultIsolateThread thread(testCase);
19578 CHECK_EQ(thread.result(), true);
19582 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19583 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19587 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19588 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19592 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19593 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19597 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19598 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19602 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19603 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19607 TEST(StringCheckMultipleContexts) {
19609 "(function() { return \"a\".charAt(0); })()";
19612 // Run the code twice in the first context to initialize the call IC.
19613 LocalContext context1;
19614 v8::HandleScope scope(context1->GetIsolate());
19615 ExpectString(code, "a");
19616 ExpectString(code, "a");
19620 // Change the String.prototype in the second context and check
19621 // that the right function gets called.
19622 LocalContext context2;
19623 v8::HandleScope scope(context2->GetIsolate());
19624 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19625 ExpectString(code, "not a");
19630 TEST(NumberCheckMultipleContexts) {
19632 "(function() { return (42).toString(); })()";
19635 // Run the code twice in the first context to initialize the call IC.
19636 LocalContext context1;
19637 v8::HandleScope scope(context1->GetIsolate());
19638 ExpectString(code, "42");
19639 ExpectString(code, "42");
19643 // Change the Number.prototype in the second context and check
19644 // that the right function gets called.
19645 LocalContext context2;
19646 v8::HandleScope scope(context2->GetIsolate());
19647 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19648 ExpectString(code, "not 42");
19653 TEST(BooleanCheckMultipleContexts) {
19655 "(function() { return true.toString(); })()";
19658 // Run the code twice in the first context to initialize the call IC.
19659 LocalContext context1;
19660 v8::HandleScope scope(context1->GetIsolate());
19661 ExpectString(code, "true");
19662 ExpectString(code, "true");
19666 // Change the Boolean.prototype in the second context and check
19667 // that the right function gets called.
19668 LocalContext context2;
19669 v8::HandleScope scope(context2->GetIsolate());
19670 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19671 ExpectString(code, "");
19676 TEST(DontDeleteCellLoadIC) {
19677 const char* function_code =
19678 "function readCell() { while (true) { return cell; } }";
19681 // Run the code twice in the first context to initialize the load
19682 // IC for a don't delete cell.
19683 LocalContext context1;
19684 v8::HandleScope scope(context1->GetIsolate());
19685 CompileRun("var cell = \"first\";");
19686 ExpectBoolean("delete cell", false);
19687 CompileRun(function_code);
19688 ExpectString("readCell()", "first");
19689 ExpectString("readCell()", "first");
19693 // Use a deletable cell in the second context.
19694 LocalContext context2;
19695 v8::HandleScope scope(context2->GetIsolate());
19696 CompileRun("cell = \"second\";");
19697 CompileRun(function_code);
19698 ExpectString("readCell()", "second");
19699 ExpectBoolean("delete cell", true);
19700 ExpectString("(function() {"
19702 " return readCell();"
19704 " return e.toString();"
19707 "ReferenceError: cell is not defined");
19708 CompileRun("cell = \"new_second\";");
19709 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19710 ExpectString("readCell()", "new_second");
19711 ExpectString("readCell()", "new_second");
19716 TEST(DontDeleteCellLoadICForceDelete) {
19717 const char* function_code =
19718 "function readCell() { while (true) { return cell; } }";
19720 // Run the code twice to initialize the load IC for a don't delete
19722 LocalContext context;
19723 v8::HandleScope scope(context->GetIsolate());
19724 CompileRun("var cell = \"value\";");
19725 ExpectBoolean("delete cell", false);
19726 CompileRun(function_code);
19727 ExpectString("readCell()", "value");
19728 ExpectString("readCell()", "value");
19730 // Delete the cell using the API and check the inlined code works
19732 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19733 ExpectString("(function() {"
19735 " return readCell();"
19737 " return e.toString();"
19740 "ReferenceError: cell is not defined");
19744 TEST(DontDeleteCellLoadICAPI) {
19745 const char* function_code =
19746 "function readCell() { while (true) { return cell; } }";
19748 // Run the code twice to initialize the load IC for a don't delete
19749 // cell created using the API.
19750 LocalContext context;
19751 v8::HandleScope scope(context->GetIsolate());
19752 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19753 ExpectBoolean("delete cell", false);
19754 CompileRun(function_code);
19755 ExpectString("readCell()", "value");
19756 ExpectString("readCell()", "value");
19758 // Delete the cell using the API and check the inlined code works
19760 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19761 ExpectString("(function() {"
19763 " return readCell();"
19765 " return e.toString();"
19768 "ReferenceError: cell is not defined");
19772 class Visitor42 : public v8::PersistentHandleVisitor {
19774 explicit Visitor42(v8::Persistent<v8::Object>* object)
19775 : counter_(0), object_(object) { }
19777 virtual void VisitPersistentHandle(Persistent<Value>* value,
19778 uint16_t class_id) {
19779 if (class_id != 42) return;
19780 CHECK_EQ(42, value->WrapperClassId());
19781 v8::Isolate* isolate = CcTest::isolate();
19782 v8::HandleScope handle_scope(isolate);
19783 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19784 v8::Handle<v8::Value> object =
19785 v8::Local<v8::Object>::New(isolate, *object_);
19786 CHECK(handle->IsObject());
19787 CHECK_EQ(Handle<Object>::Cast(handle), object);
19792 v8::Persistent<v8::Object>* object_;
19796 TEST(PersistentHandleVisitor) {
19797 LocalContext context;
19798 v8::Isolate* isolate = context->GetIsolate();
19799 v8::HandleScope scope(isolate);
19800 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19801 CHECK_EQ(0, object.WrapperClassId());
19802 object.SetWrapperClassId(42);
19803 CHECK_EQ(42, object.WrapperClassId());
19805 Visitor42 visitor(&object);
19806 v8::V8::VisitHandlesWithClassIds(&visitor);
19807 CHECK_EQ(1, visitor.counter_);
19813 TEST(WrapperClassId) {
19814 LocalContext context;
19815 v8::Isolate* isolate = context->GetIsolate();
19816 v8::HandleScope scope(isolate);
19817 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19818 CHECK_EQ(0, object.WrapperClassId());
19819 object.SetWrapperClassId(65535);
19820 CHECK_EQ(65535, object.WrapperClassId());
19825 TEST(PersistentHandleInNewSpaceVisitor) {
19826 LocalContext context;
19827 v8::Isolate* isolate = context->GetIsolate();
19828 v8::HandleScope scope(isolate);
19829 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19830 CHECK_EQ(0, object1.WrapperClassId());
19831 object1.SetWrapperClassId(42);
19832 CHECK_EQ(42, object1.WrapperClassId());
19834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19836 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19837 CHECK_EQ(0, object2.WrapperClassId());
19838 object2.SetWrapperClassId(42);
19839 CHECK_EQ(42, object2.WrapperClassId());
19841 Visitor42 visitor(&object2);
19842 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19843 CHECK_EQ(1, visitor.counter_);
19851 LocalContext context;
19852 v8::HandleScope scope(context->GetIsolate());
19854 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19855 CHECK(re->IsRegExp());
19856 CHECK(re->GetSource()->Equals(v8_str("foo")));
19857 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19859 re = v8::RegExp::New(v8_str("bar"),
19860 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19861 v8::RegExp::kGlobal));
19862 CHECK(re->IsRegExp());
19863 CHECK(re->GetSource()->Equals(v8_str("bar")));
19864 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19865 static_cast<int>(re->GetFlags()));
19867 re = v8::RegExp::New(v8_str("baz"),
19868 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19869 v8::RegExp::kMultiline));
19870 CHECK(re->IsRegExp());
19871 CHECK(re->GetSource()->Equals(v8_str("baz")));
19872 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19873 static_cast<int>(re->GetFlags()));
19875 re = CompileRun("/quux/").As<v8::RegExp>();
19876 CHECK(re->IsRegExp());
19877 CHECK(re->GetSource()->Equals(v8_str("quux")));
19878 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19880 re = CompileRun("/quux/gm").As<v8::RegExp>();
19881 CHECK(re->IsRegExp());
19882 CHECK(re->GetSource()->Equals(v8_str("quux")));
19883 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19884 static_cast<int>(re->GetFlags()));
19886 // Override the RegExp constructor and check the API constructor
19888 CompileRun("RegExp = function() {}");
19890 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19891 CHECK(re->IsRegExp());
19892 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19893 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19895 re = v8::RegExp::New(v8_str("foobarbaz"),
19896 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19897 v8::RegExp::kMultiline));
19898 CHECK(re->IsRegExp());
19899 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19900 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19901 static_cast<int>(re->GetFlags()));
19903 context->Global()->Set(v8_str("re"), re);
19904 ExpectTrue("re.test('FoobarbaZ')");
19906 // RegExps are objects on which you can set properties.
19907 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19908 v8::Handle<v8::Value> value(CompileRun("re.property"));
19909 CHECK_EQ(32, value->Int32Value());
19911 v8::TryCatch try_catch;
19912 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19913 CHECK(re.IsEmpty());
19914 CHECK(try_catch.HasCaught());
19915 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19916 ExpectTrue("ex instanceof SyntaxError");
19920 THREADED_TEST(Equals) {
19921 LocalContext localContext;
19922 v8::HandleScope handleScope(localContext->GetIsolate());
19924 v8::Handle<v8::Object> globalProxy = localContext->Global();
19925 v8::Handle<Value> global = globalProxy->GetPrototype();
19927 CHECK(global->StrictEquals(global));
19928 CHECK(!global->StrictEquals(globalProxy));
19929 CHECK(!globalProxy->StrictEquals(global));
19930 CHECK(globalProxy->StrictEquals(globalProxy));
19932 CHECK(global->Equals(global));
19933 CHECK(!global->Equals(globalProxy));
19934 CHECK(!globalProxy->Equals(global));
19935 CHECK(globalProxy->Equals(globalProxy));
19939 static void Getter(v8::Local<v8::String> property,
19940 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19941 info.GetReturnValue().Set(v8_str("42!"));
19945 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19946 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19947 result->Set(0, v8_str("universalAnswer"));
19948 info.GetReturnValue().Set(result);
19952 TEST(NamedEnumeratorAndForIn) {
19953 LocalContext context;
19954 v8::Isolate* isolate = context->GetIsolate();
19955 v8::HandleScope handle_scope(isolate);
19956 v8::Context::Scope context_scope(context.local());
19958 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19959 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19960 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19961 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19962 "var result = []; for (var k in o) result.push(k); result"));
19963 CHECK_EQ(1, result->Length());
19964 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19968 TEST(DefinePropertyPostDetach) {
19969 LocalContext context;
19970 v8::HandleScope scope(context->GetIsolate());
19971 v8::Handle<v8::Object> proxy = context->Global();
19972 v8::Handle<v8::Function> define_property =
19973 CompileRun("(function() {"
19974 " Object.defineProperty("
19977 " { configurable: true, enumerable: true, value: 3 });"
19978 "})").As<Function>();
19979 context->DetachGlobal();
19980 define_property->Call(proxy, 0, NULL);
19984 static void InstallContextId(v8::Handle<Context> context, int id) {
19985 Context::Scope scope(context);
19986 CompileRun("Object.prototype").As<Object>()->
19987 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19991 static void CheckContextId(v8::Handle<Object> object, int expected) {
19992 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19996 THREADED_TEST(CreationContext) {
19997 v8::Isolate* isolate = CcTest::isolate();
19998 HandleScope handle_scope(isolate);
19999 Handle<Context> context1 = Context::New(isolate);
20000 InstallContextId(context1, 1);
20001 Handle<Context> context2 = Context::New(isolate);
20002 InstallContextId(context2, 2);
20003 Handle<Context> context3 = Context::New(isolate);
20004 InstallContextId(context3, 3);
20006 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20008 Local<Object> object1;
20009 Local<Function> func1;
20011 Context::Scope scope(context1);
20012 object1 = Object::New(isolate);
20013 func1 = tmpl->GetFunction();
20016 Local<Object> object2;
20017 Local<Function> func2;
20019 Context::Scope scope(context2);
20020 object2 = Object::New(isolate);
20021 func2 = tmpl->GetFunction();
20024 Local<Object> instance1;
20025 Local<Object> instance2;
20028 Context::Scope scope(context3);
20029 instance1 = func1->NewInstance();
20030 instance2 = func2->NewInstance();
20033 CHECK(object1->CreationContext() == context1);
20034 CheckContextId(object1, 1);
20035 CHECK(func1->CreationContext() == context1);
20036 CheckContextId(func1, 1);
20037 CHECK(instance1->CreationContext() == context1);
20038 CheckContextId(instance1, 1);
20039 CHECK(object2->CreationContext() == context2);
20040 CheckContextId(object2, 2);
20041 CHECK(func2->CreationContext() == context2);
20042 CheckContextId(func2, 2);
20043 CHECK(instance2->CreationContext() == context2);
20044 CheckContextId(instance2, 2);
20047 Context::Scope scope(context1);
20048 CHECK(object1->CreationContext() == context1);
20049 CheckContextId(object1, 1);
20050 CHECK(func1->CreationContext() == context1);
20051 CheckContextId(func1, 1);
20052 CHECK(instance1->CreationContext() == context1);
20053 CheckContextId(instance1, 1);
20054 CHECK(object2->CreationContext() == context2);
20055 CheckContextId(object2, 2);
20056 CHECK(func2->CreationContext() == context2);
20057 CheckContextId(func2, 2);
20058 CHECK(instance2->CreationContext() == context2);
20059 CheckContextId(instance2, 2);
20063 Context::Scope scope(context2);
20064 CHECK(object1->CreationContext() == context1);
20065 CheckContextId(object1, 1);
20066 CHECK(func1->CreationContext() == context1);
20067 CheckContextId(func1, 1);
20068 CHECK(instance1->CreationContext() == context1);
20069 CheckContextId(instance1, 1);
20070 CHECK(object2->CreationContext() == context2);
20071 CheckContextId(object2, 2);
20072 CHECK(func2->CreationContext() == context2);
20073 CheckContextId(func2, 2);
20074 CHECK(instance2->CreationContext() == context2);
20075 CheckContextId(instance2, 2);
20080 THREADED_TEST(CreationContextOfJsFunction) {
20081 HandleScope handle_scope(CcTest::isolate());
20082 Handle<Context> context = Context::New(CcTest::isolate());
20083 InstallContextId(context, 1);
20085 Local<Object> function;
20087 Context::Scope scope(context);
20088 function = CompileRun("function foo() {}; foo").As<Object>();
20091 CHECK(function->CreationContext() == context);
20092 CheckContextId(function, 1);
20096 void HasOwnPropertyIndexedPropertyGetter(
20098 const v8::PropertyCallbackInfo<v8::Value>& info) {
20099 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20103 void HasOwnPropertyNamedPropertyGetter(
20104 Local<String> property,
20105 const v8::PropertyCallbackInfo<v8::Value>& info) {
20106 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20110 void HasOwnPropertyIndexedPropertyQuery(
20111 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20112 if (index == 42) info.GetReturnValue().Set(1);
20116 void HasOwnPropertyNamedPropertyQuery(
20117 Local<String> property,
20118 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20119 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20123 void HasOwnPropertyNamedPropertyQuery2(
20124 Local<String> property,
20125 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20126 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20130 void HasOwnPropertyAccessorGetter(
20131 Local<String> property,
20132 const v8::PropertyCallbackInfo<v8::Value>& info) {
20133 info.GetReturnValue().Set(v8_str("yes"));
20137 TEST(HasOwnProperty) {
20139 v8::Isolate* isolate = env->GetIsolate();
20140 v8::HandleScope scope(isolate);
20141 { // Check normal properties and defined getters.
20142 Handle<Value> value = CompileRun(
20145 " this.__defineGetter__('baz', function() { return 1; });"
20147 "function Bar() { "
20149 " this.__defineGetter__('bla', function() { return 2; });"
20151 "Bar.prototype = new Foo();"
20153 CHECK(value->IsObject());
20154 Handle<Object> object = value->ToObject();
20155 CHECK(object->Has(v8_str("foo")));
20156 CHECK(!object->HasOwnProperty(v8_str("foo")));
20157 CHECK(object->HasOwnProperty(v8_str("bar")));
20158 CHECK(object->Has(v8_str("baz")));
20159 CHECK(!object->HasOwnProperty(v8_str("baz")));
20160 CHECK(object->HasOwnProperty(v8_str("bla")));
20162 { // Check named getter interceptors.
20163 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20164 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20165 Handle<Object> instance = templ->NewInstance();
20166 CHECK(!instance->HasOwnProperty(v8_str("42")));
20167 CHECK(instance->HasOwnProperty(v8_str("foo")));
20168 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20170 { // Check indexed getter interceptors.
20171 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20172 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20173 Handle<Object> instance = templ->NewInstance();
20174 CHECK(instance->HasOwnProperty(v8_str("42")));
20175 CHECK(!instance->HasOwnProperty(v8_str("43")));
20176 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20178 { // Check named query interceptors.
20179 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20180 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20181 Handle<Object> instance = templ->NewInstance();
20182 CHECK(instance->HasOwnProperty(v8_str("foo")));
20183 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20185 { // Check indexed query interceptors.
20186 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20187 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20188 Handle<Object> instance = templ->NewInstance();
20189 CHECK(instance->HasOwnProperty(v8_str("42")));
20190 CHECK(!instance->HasOwnProperty(v8_str("41")));
20192 { // Check callbacks.
20193 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20194 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20195 Handle<Object> instance = templ->NewInstance();
20196 CHECK(instance->HasOwnProperty(v8_str("foo")));
20197 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20199 { // Check that query wins on disagreement.
20200 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20201 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20203 HasOwnPropertyNamedPropertyQuery2);
20204 Handle<Object> instance = templ->NewInstance();
20205 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20206 CHECK(instance->HasOwnProperty(v8_str("bar")));
20211 TEST(IndexedInterceptorWithStringProto) {
20212 v8::Isolate* isolate = CcTest::isolate();
20213 v8::HandleScope scope(isolate);
20214 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20215 templ->SetIndexedPropertyHandler(NULL,
20217 HasOwnPropertyIndexedPropertyQuery);
20218 LocalContext context;
20219 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20220 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20221 // These should be intercepted.
20222 CHECK(CompileRun("42 in obj")->BooleanValue());
20223 CHECK(CompileRun("'42' in obj")->BooleanValue());
20224 // These should fall through to the String prototype.
20225 CHECK(CompileRun("0 in obj")->BooleanValue());
20226 CHECK(CompileRun("'0' in obj")->BooleanValue());
20227 // And these should both fail.
20228 CHECK(!CompileRun("32 in obj")->BooleanValue());
20229 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20233 void CheckCodeGenerationAllowed() {
20234 Handle<Value> result = CompileRun("eval('42')");
20235 CHECK_EQ(42, result->Int32Value());
20236 result = CompileRun("(function(e) { return e('42'); })(eval)");
20237 CHECK_EQ(42, result->Int32Value());
20238 result = CompileRun("var f = new Function('return 42'); f()");
20239 CHECK_EQ(42, result->Int32Value());
20243 void CheckCodeGenerationDisallowed() {
20244 TryCatch try_catch;
20246 Handle<Value> result = CompileRun("eval('42')");
20247 CHECK(result.IsEmpty());
20248 CHECK(try_catch.HasCaught());
20251 result = CompileRun("(function(e) { return e('42'); })(eval)");
20252 CHECK(result.IsEmpty());
20253 CHECK(try_catch.HasCaught());
20256 result = CompileRun("var f = new Function('return 42'); f()");
20257 CHECK(result.IsEmpty());
20258 CHECK(try_catch.HasCaught());
20262 bool CodeGenerationAllowed(Local<Context> context) {
20263 ApiTestFuzzer::Fuzz();
20268 bool CodeGenerationDisallowed(Local<Context> context) {
20269 ApiTestFuzzer::Fuzz();
20274 THREADED_TEST(AllowCodeGenFromStrings) {
20275 LocalContext context;
20276 v8::HandleScope scope(context->GetIsolate());
20278 // eval and the Function constructor allowed by default.
20279 CHECK(context->IsCodeGenerationFromStringsAllowed());
20280 CheckCodeGenerationAllowed();
20282 // Disallow eval and the Function constructor.
20283 context->AllowCodeGenerationFromStrings(false);
20284 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20285 CheckCodeGenerationDisallowed();
20288 context->AllowCodeGenerationFromStrings(true);
20289 CheckCodeGenerationAllowed();
20291 // Disallow but setting a global callback that will allow the calls.
20292 context->AllowCodeGenerationFromStrings(false);
20293 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20294 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20295 CheckCodeGenerationAllowed();
20297 // Set a callback that disallows the code generation.
20298 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20299 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20300 CheckCodeGenerationDisallowed();
20304 TEST(SetErrorMessageForCodeGenFromStrings) {
20305 LocalContext context;
20306 v8::HandleScope scope(context->GetIsolate());
20307 TryCatch try_catch;
20309 Handle<String> message = v8_str("Message") ;
20310 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20311 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20312 context->AllowCodeGenerationFromStrings(false);
20313 context->SetErrorMessageForCodeGenerationFromStrings(message);
20314 Handle<Value> result = CompileRun("eval('42')");
20315 CHECK(result.IsEmpty());
20316 CHECK(try_catch.HasCaught());
20317 Handle<String> actual_message = try_catch.Message()->Get();
20318 CHECK(expected_message->Equals(actual_message));
20322 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20326 THREADED_TEST(CallAPIFunctionOnNonObject) {
20327 LocalContext context;
20328 v8::Isolate* isolate = context->GetIsolate();
20329 v8::HandleScope scope(isolate);
20330 Handle<FunctionTemplate> templ =
20331 v8::FunctionTemplate::New(isolate, NonObjectThis);
20332 Handle<Function> function = templ->GetFunction();
20333 context->Global()->Set(v8_str("f"), function);
20334 TryCatch try_catch;
20335 CompileRun("f.call(2)");
20339 // Regression test for issue 1470.
20340 THREADED_TEST(ReadOnlyIndexedProperties) {
20341 v8::Isolate* isolate = CcTest::isolate();
20342 v8::HandleScope scope(isolate);
20343 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20345 LocalContext context;
20346 Local<v8::Object> obj = templ->NewInstance();
20347 context->Global()->Set(v8_str("obj"), obj);
20348 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20349 obj->Set(v8_str("1"), v8_str("foobar"));
20350 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20351 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20352 obj->Set(v8_num(2), v8_str("foobar"));
20353 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20355 // Test non-smi case.
20356 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20357 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20358 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20362 THREADED_TEST(Regress1516) {
20363 LocalContext context;
20364 v8::HandleScope scope(context->GetIsolate());
20366 { v8::HandleScope temp_scope(context->GetIsolate());
20367 CompileRun("({'a': 0})");
20371 { i::MapCache* map_cache =
20372 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20373 elements = map_cache->NumberOfElements();
20374 CHECK_LE(1, elements);
20377 CcTest::heap()->CollectAllGarbage(
20378 i::Heap::kAbortIncrementalMarkingMask);
20379 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20380 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20381 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20382 CHECK_GT(elements, map_cache->NumberOfElements());
20388 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20390 v8::AccessType type,
20391 Local<Value> data) {
20392 // Only block read access to __proto__.
20393 if (type == v8::ACCESS_GET &&
20394 name->IsString() &&
20395 name->ToString()->Length() == 9 &&
20396 name->ToString()->Utf8Length() == 9) {
20398 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20399 return strncmp(buffer, "__proto__", 9) != 0;
20406 THREADED_TEST(Regress93759) {
20407 v8::Isolate* isolate = CcTest::isolate();
20408 HandleScope scope(isolate);
20410 // Template for object with security check.
20411 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20412 // We don't do indexing, so any callback can be used for that.
20413 no_proto_template->SetAccessCheckCallbacks(
20414 BlockProtoNamedSecurityTestCallback,
20415 IndexedSecurityTestCallback);
20417 // Templates for objects with hidden prototypes and possibly security check.
20418 Local<FunctionTemplate> hidden_proto_template =
20419 v8::FunctionTemplate::New(isolate);
20420 hidden_proto_template->SetHiddenPrototype(true);
20422 Local<FunctionTemplate> protected_hidden_proto_template =
20423 v8::FunctionTemplate::New(isolate);
20424 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20425 BlockProtoNamedSecurityTestCallback,
20426 IndexedSecurityTestCallback);
20427 protected_hidden_proto_template->SetHiddenPrototype(true);
20429 // Context for "foreign" objects used in test.
20430 Local<Context> context = v8::Context::New(isolate);
20433 // Plain object, no security check.
20434 Local<Object> simple_object = Object::New(isolate);
20436 // Object with explicit security check.
20437 Local<Object> protected_object =
20438 no_proto_template->NewInstance();
20440 // JSGlobalProxy object, always have security check.
20441 Local<Object> proxy_object =
20444 // Global object, the prototype of proxy_object. No security checks.
20445 Local<Object> global_object =
20446 proxy_object->GetPrototype()->ToObject();
20448 // Hidden prototype without security check.
20449 Local<Object> hidden_prototype =
20450 hidden_proto_template->GetFunction()->NewInstance();
20451 Local<Object> object_with_hidden =
20452 Object::New(isolate);
20453 object_with_hidden->SetPrototype(hidden_prototype);
20455 // Hidden prototype with security check on the hidden prototype.
20456 Local<Object> protected_hidden_prototype =
20457 protected_hidden_proto_template->GetFunction()->NewInstance();
20458 Local<Object> object_with_protected_hidden =
20459 Object::New(isolate);
20460 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20464 // Template for object for second context. Values to test are put on it as
20466 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20467 global_template->Set(v8_str("simple"), simple_object);
20468 global_template->Set(v8_str("protected"), protected_object);
20469 global_template->Set(v8_str("global"), global_object);
20470 global_template->Set(v8_str("proxy"), proxy_object);
20471 global_template->Set(v8_str("hidden"), object_with_hidden);
20472 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20474 LocalContext context2(NULL, global_template);
20476 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20477 CHECK(result1->Equals(simple_object->GetPrototype()));
20479 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20480 CHECK(result2->Equals(Undefined(isolate)));
20482 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20483 CHECK(result3->Equals(global_object->GetPrototype()));
20485 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20486 CHECK(result4->Equals(Undefined(isolate)));
20488 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20489 CHECK(result5->Equals(
20490 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20492 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20493 CHECK(result6->Equals(Undefined(isolate)));
20497 THREADED_TEST(Regress125988) {
20498 v8::HandleScope scope(CcTest::isolate());
20499 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20500 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20502 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20503 CompileRun("var a = new Object();"
20504 "var b = new Intercept();"
20505 "var c = new Object();"
20509 "for (var i = 0; i < 3; i++) c.x;");
20510 ExpectBoolean("c.hasOwnProperty('x')", false);
20511 ExpectInt32("c.x", 23);
20512 CompileRun("a.y = 42;"
20513 "for (var i = 0; i < 3; i++) c.x;");
20514 ExpectBoolean("c.hasOwnProperty('x')", false);
20515 ExpectInt32("c.x", 23);
20516 ExpectBoolean("c.hasOwnProperty('y')", false);
20517 ExpectInt32("c.y", 42);
20521 static void TestReceiver(Local<Value> expected_result,
20522 Local<Value> expected_receiver,
20523 const char* code) {
20524 Local<Value> result = CompileRun(code);
20525 CHECK(result->IsObject());
20526 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20527 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20531 THREADED_TEST(ForeignFunctionReceiver) {
20532 v8::Isolate* isolate = CcTest::isolate();
20533 HandleScope scope(isolate);
20535 // Create two contexts with different "id" properties ('i' and 'o').
20536 // Call a function both from its own context and from a the foreign
20537 // context, and see what "this" is bound to (returning both "this"
20538 // and "this.id" for comparison).
20540 Local<Context> foreign_context = v8::Context::New(isolate);
20541 foreign_context->Enter();
20542 Local<Value> foreign_function =
20543 CompileRun("function func() { return { 0: this.id, "
20545 " toString: function() { "
20552 CHECK(foreign_function->IsFunction());
20553 foreign_context->Exit();
20555 LocalContext context;
20557 Local<String> password = v8_str("Password");
20558 // Don't get hit by security checks when accessing foreign_context's
20559 // global receiver (aka. global proxy).
20560 context->SetSecurityToken(password);
20561 foreign_context->SetSecurityToken(password);
20563 Local<String> i = v8_str("i");
20564 Local<String> o = v8_str("o");
20565 Local<String> id = v8_str("id");
20567 CompileRun("function ownfunc() { return { 0: this.id, "
20569 " toString: function() { "
20576 context->Global()->Set(v8_str("func"), foreign_function);
20578 // Sanity check the contexts.
20579 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20580 CHECK(o->Equals(context->Global()->Get(id)));
20582 // Checking local function's receiver.
20583 // Calling function using its call/apply methods.
20584 TestReceiver(o, context->Global(), "ownfunc.call()");
20585 TestReceiver(o, context->Global(), "ownfunc.apply()");
20586 // Making calls through built-in functions.
20587 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20588 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20589 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20590 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20591 // Calling with environment record as base.
20592 TestReceiver(o, context->Global(), "ownfunc()");
20593 // Calling with no base.
20594 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20596 // Checking foreign function return value.
20597 // Calling function using its call/apply methods.
20598 TestReceiver(i, foreign_context->Global(), "func.call()");
20599 TestReceiver(i, foreign_context->Global(), "func.apply()");
20600 // Calling function using another context's call/apply methods.
20601 TestReceiver(i, foreign_context->Global(),
20602 "Function.prototype.call.call(func)");
20603 TestReceiver(i, foreign_context->Global(),
20604 "Function.prototype.call.apply(func)");
20605 TestReceiver(i, foreign_context->Global(),
20606 "Function.prototype.apply.call(func)");
20607 TestReceiver(i, foreign_context->Global(),
20608 "Function.prototype.apply.apply(func)");
20609 // Making calls through built-in functions.
20610 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20611 // ToString(func()) is func()[0], i.e., the returned this.id.
20612 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20613 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20614 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20616 // Calling with environment record as base.
20617 TestReceiver(i, foreign_context->Global(), "func()");
20618 // Calling with no base.
20619 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20623 uint8_t callback_fired = 0;
20626 void CallCompletedCallback1() {
20627 i::OS::Print("Firing callback 1.\n");
20628 callback_fired ^= 1; // Toggle first bit.
20632 void CallCompletedCallback2() {
20633 i::OS::Print("Firing callback 2.\n");
20634 callback_fired ^= 2; // Toggle second bit.
20638 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20639 int32_t level = args[0]->Int32Value();
20642 i::OS::Print("Entering recursion level %d.\n", level);
20644 i::Vector<char> script_vector(script, sizeof(script));
20645 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20646 CompileRun(script_vector.start());
20647 i::OS::Print("Leaving recursion level %d.\n", level);
20648 CHECK_EQ(0, callback_fired);
20650 i::OS::Print("Recursion ends.\n");
20651 CHECK_EQ(0, callback_fired);
20656 TEST(CallCompletedCallback) {
20658 v8::HandleScope scope(env->GetIsolate());
20659 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20660 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20661 env->Global()->Set(v8_str("recursion"),
20662 recursive_runtime->GetFunction());
20663 // Adding the same callback a second time has no effect.
20664 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20665 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20666 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20667 i::OS::Print("--- Script (1) ---\n");
20668 Local<Script> script = v8::Script::Compile(
20669 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20671 CHECK_EQ(3, callback_fired);
20673 i::OS::Print("\n--- Script (2) ---\n");
20674 callback_fired = 0;
20675 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20677 CHECK_EQ(2, callback_fired);
20679 i::OS::Print("\n--- Function ---\n");
20680 callback_fired = 0;
20681 Local<Function> recursive_function =
20682 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20683 v8::Handle<Value> args[] = { v8_num(0) };
20684 recursive_function->Call(env->Global(), 1, args);
20685 CHECK_EQ(2, callback_fired);
20689 void CallCompletedCallbackNoException() {
20690 v8::HandleScope scope(CcTest::isolate());
20691 CompileRun("1+1;");
20695 void CallCompletedCallbackException() {
20696 v8::HandleScope scope(CcTest::isolate());
20697 CompileRun("throw 'second exception';");
20701 TEST(CallCompletedCallbackOneException) {
20703 v8::HandleScope scope(env->GetIsolate());
20704 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20705 CompileRun("throw 'exception';");
20709 TEST(CallCompletedCallbackTwoExceptions) {
20711 v8::HandleScope scope(env->GetIsolate());
20712 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20713 CompileRun("throw 'first exception';");
20717 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20718 v8::HandleScope scope(info.GetIsolate());
20719 CompileRun("ext1Calls++;");
20723 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20724 v8::HandleScope scope(info.GetIsolate());
20725 CompileRun("ext2Calls++;");
20729 TEST(EnqueueMicrotask) {
20731 v8::HandleScope scope(env->GetIsolate());
20733 "var ext1Calls = 0;"
20734 "var ext2Calls = 0;");
20735 CompileRun("1+1;");
20736 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20737 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20739 env->GetIsolate()->EnqueueMicrotask(
20740 Function::New(env->GetIsolate(), MicrotaskOne));
20741 CompileRun("1+1;");
20742 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20743 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20745 env->GetIsolate()->EnqueueMicrotask(
20746 Function::New(env->GetIsolate(), MicrotaskOne));
20747 env->GetIsolate()->EnqueueMicrotask(
20748 Function::New(env->GetIsolate(), MicrotaskTwo));
20749 CompileRun("1+1;");
20750 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20751 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20753 env->GetIsolate()->EnqueueMicrotask(
20754 Function::New(env->GetIsolate(), MicrotaskTwo));
20755 CompileRun("1+1;");
20756 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20757 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20759 CompileRun("1+1;");
20760 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20761 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20765 TEST(SetAutorunMicrotasks) {
20767 v8::HandleScope scope(env->GetIsolate());
20769 "var ext1Calls = 0;"
20770 "var ext2Calls = 0;");
20771 CompileRun("1+1;");
20772 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20773 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20775 env->GetIsolate()->EnqueueMicrotask(
20776 Function::New(env->GetIsolate(), MicrotaskOne));
20777 CompileRun("1+1;");
20778 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20779 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20781 env->GetIsolate()->SetAutorunMicrotasks(false);
20782 env->GetIsolate()->EnqueueMicrotask(
20783 Function::New(env->GetIsolate(), MicrotaskOne));
20784 env->GetIsolate()->EnqueueMicrotask(
20785 Function::New(env->GetIsolate(), MicrotaskTwo));
20786 CompileRun("1+1;");
20787 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20788 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20790 env->GetIsolate()->RunMicrotasks();
20791 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20792 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20794 env->GetIsolate()->EnqueueMicrotask(
20795 Function::New(env->GetIsolate(), MicrotaskTwo));
20796 CompileRun("1+1;");
20797 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20800 env->GetIsolate()->RunMicrotasks();
20801 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20802 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20804 env->GetIsolate()->SetAutorunMicrotasks(true);
20805 env->GetIsolate()->EnqueueMicrotask(
20806 Function::New(env->GetIsolate(), MicrotaskTwo));
20807 CompileRun("1+1;");
20808 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20809 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20811 env->GetIsolate()->EnqueueMicrotask(
20812 Function::New(env->GetIsolate(), MicrotaskTwo));
20814 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20815 CompileRun("1+1;");
20816 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20817 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20820 CompileRun("1+1;");
20821 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20822 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20826 static int probes_counter = 0;
20827 static int misses_counter = 0;
20828 static int updates_counter = 0;
20831 static int* LookupCounter(const char* name) {
20832 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20833 return &probes_counter;
20834 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20835 return &misses_counter;
20836 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20837 return &updates_counter;
20843 static const char* kMegamorphicTestProgram =
20844 "function ClassA() { };"
20845 "function ClassB() { };"
20846 "ClassA.prototype.foo = function() { };"
20847 "ClassB.prototype.foo = function() { };"
20848 "function fooify(obj) { obj.foo(); };"
20849 "var a = new ClassA();"
20850 "var b = new ClassB();"
20851 "for (var i = 0; i < 10000; i++) {"
20857 static void StubCacheHelper(bool primary) {
20858 V8::SetCounterFunction(LookupCounter);
20859 USE(kMegamorphicTestProgram);
20861 i::FLAG_native_code_counters = true;
20863 i::FLAG_test_primary_stub_cache = true;
20865 i::FLAG_test_secondary_stub_cache = true;
20867 i::FLAG_crankshaft = false;
20869 v8::HandleScope scope(env->GetIsolate());
20870 int initial_probes = probes_counter;
20871 int initial_misses = misses_counter;
20872 int initial_updates = updates_counter;
20873 CompileRun(kMegamorphicTestProgram);
20874 int probes = probes_counter - initial_probes;
20875 int misses = misses_counter - initial_misses;
20876 int updates = updates_counter - initial_updates;
20877 CHECK_LT(updates, 10);
20878 CHECK_LT(misses, 10);
20879 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20880 // before megamorphism. The number of probes will only work once we teach the
20881 // serializer to embed references to counters in the stubs, given that the
20882 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20883 CHECK_GE(probes, 0);
20888 TEST(SecondaryStubCache) {
20889 StubCacheHelper(true);
20893 TEST(PrimaryStubCache) {
20894 StubCacheHelper(false);
20898 static int cow_arrays_created_runtime = 0;
20901 static int* LookupCounterCOWArrays(const char* name) {
20902 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20903 return &cow_arrays_created_runtime;
20909 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20910 V8::SetCounterFunction(LookupCounterCOWArrays);
20912 i::FLAG_native_code_counters = true;
20914 v8::HandleScope scope(env->GetIsolate());
20915 int initial_cow_arrays = cow_arrays_created_runtime;
20916 CompileRun("var o = [1, 2, 3];");
20917 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20918 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20919 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20920 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20921 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20926 TEST(StaticGetters) {
20927 LocalContext context;
20928 i::Factory* factory = CcTest::i_isolate()->factory();
20929 v8::Isolate* isolate = CcTest::isolate();
20930 v8::HandleScope scope(isolate);
20931 i::Handle<i::Object> undefined_value = factory->undefined_value();
20932 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20933 i::Handle<i::Object> null_value = factory->null_value();
20934 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20935 i::Handle<i::Object> true_value = factory->true_value();
20936 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20937 i::Handle<i::Object> false_value = factory->false_value();
20938 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20942 UNINITIALIZED_TEST(IsolateEmbedderData) {
20943 CcTest::DisableAutomaticDispose();
20944 v8::Isolate* isolate = v8::Isolate::New();
20946 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20947 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20948 CHECK_EQ(NULL, isolate->GetData(slot));
20949 CHECK_EQ(NULL, i_isolate->GetData(slot));
20951 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20952 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20953 isolate->SetData(slot, data);
20955 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20956 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20957 CHECK_EQ(data, isolate->GetData(slot));
20958 CHECK_EQ(data, i_isolate->GetData(slot));
20960 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20961 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20962 isolate->SetData(slot, data);
20964 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20965 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20966 CHECK_EQ(data, isolate->GetData(slot));
20967 CHECK_EQ(data, i_isolate->GetData(slot));
20970 isolate->Dispose();
20974 TEST(StringEmpty) {
20975 LocalContext context;
20976 i::Factory* factory = CcTest::i_isolate()->factory();
20977 v8::Isolate* isolate = CcTest::isolate();
20978 v8::HandleScope scope(isolate);
20979 i::Handle<i::Object> empty_string = factory->empty_string();
20980 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20984 static int instance_checked_getter_count = 0;
20985 static void InstanceCheckedGetter(
20986 Local<String> name,
20987 const v8::PropertyCallbackInfo<v8::Value>& info) {
20988 CHECK_EQ(name, v8_str("foo"));
20989 instance_checked_getter_count++;
20990 info.GetReturnValue().Set(v8_num(11));
20994 static int instance_checked_setter_count = 0;
20995 static void InstanceCheckedSetter(Local<String> name,
20996 Local<Value> value,
20997 const v8::PropertyCallbackInfo<void>& info) {
20998 CHECK_EQ(name, v8_str("foo"));
20999 CHECK_EQ(value, v8_num(23));
21000 instance_checked_setter_count++;
21004 static void CheckInstanceCheckedResult(int getters,
21006 bool expects_callbacks,
21007 TryCatch* try_catch) {
21008 if (expects_callbacks) {
21009 CHECK(!try_catch->HasCaught());
21010 CHECK_EQ(getters, instance_checked_getter_count);
21011 CHECK_EQ(setters, instance_checked_setter_count);
21013 CHECK(try_catch->HasCaught());
21014 CHECK_EQ(0, instance_checked_getter_count);
21015 CHECK_EQ(0, instance_checked_setter_count);
21017 try_catch->Reset();
21021 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21022 instance_checked_getter_count = 0;
21023 instance_checked_setter_count = 0;
21024 TryCatch try_catch;
21026 // Test path through generic runtime code.
21027 CompileRun("obj.foo");
21028 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21029 CompileRun("obj.foo = 23");
21030 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21032 // Test path through generated LoadIC and StoredIC.
21033 CompileRun("function test_get(o) { o.foo; }"
21035 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21036 CompileRun("test_get(obj);");
21037 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21038 CompileRun("test_get(obj);");
21039 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21040 CompileRun("function test_set(o) { o.foo = 23; }"
21042 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21043 CompileRun("test_set(obj);");
21044 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21045 CompileRun("test_set(obj);");
21046 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21048 // Test path through optimized code.
21049 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21051 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21052 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21054 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21056 // Cleanup so that closures start out fresh in next check.
21057 CompileRun("%DeoptimizeFunction(test_get);"
21058 "%ClearFunctionTypeFeedback(test_get);"
21059 "%DeoptimizeFunction(test_set);"
21060 "%ClearFunctionTypeFeedback(test_set);");
21064 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21065 v8::internal::FLAG_allow_natives_syntax = true;
21066 LocalContext context;
21067 v8::HandleScope scope(context->GetIsolate());
21069 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21070 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21071 inst->SetAccessor(v8_str("foo"),
21072 InstanceCheckedGetter, InstanceCheckedSetter,
21076 v8::AccessorSignature::New(context->GetIsolate(), templ));
21077 context->Global()->Set(v8_str("f"), templ->GetFunction());
21079 printf("Testing positive ...\n");
21080 CompileRun("var obj = new f();");
21081 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21082 CheckInstanceCheckedAccessors(true);
21084 printf("Testing negative ...\n");
21085 CompileRun("var obj = {};"
21086 "obj.__proto__ = new f();");
21087 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21088 CheckInstanceCheckedAccessors(false);
21092 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21093 v8::internal::FLAG_allow_natives_syntax = true;
21094 LocalContext context;
21095 v8::HandleScope scope(context->GetIsolate());
21097 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21098 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21099 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21100 inst->SetAccessor(v8_str("foo"),
21101 InstanceCheckedGetter, InstanceCheckedSetter,
21105 v8::AccessorSignature::New(context->GetIsolate(), templ));
21106 context->Global()->Set(v8_str("f"), templ->GetFunction());
21108 printf("Testing positive ...\n");
21109 CompileRun("var obj = new f();");
21110 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21111 CheckInstanceCheckedAccessors(true);
21113 printf("Testing negative ...\n");
21114 CompileRun("var obj = {};"
21115 "obj.__proto__ = new f();");
21116 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21117 CheckInstanceCheckedAccessors(false);
21121 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21122 v8::internal::FLAG_allow_natives_syntax = true;
21123 LocalContext context;
21124 v8::HandleScope scope(context->GetIsolate());
21126 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21127 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21128 proto->SetAccessor(v8_str("foo"),
21129 InstanceCheckedGetter, InstanceCheckedSetter,
21133 v8::AccessorSignature::New(context->GetIsolate(), templ));
21134 context->Global()->Set(v8_str("f"), templ->GetFunction());
21136 printf("Testing positive ...\n");
21137 CompileRun("var obj = new f();");
21138 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21139 CheckInstanceCheckedAccessors(true);
21141 printf("Testing negative ...\n");
21142 CompileRun("var obj = {};"
21143 "obj.__proto__ = new f();");
21144 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21145 CheckInstanceCheckedAccessors(false);
21147 printf("Testing positive with modified prototype chain ...\n");
21148 CompileRun("var obj = new f();"
21150 "pro.__proto__ = obj.__proto__;"
21151 "obj.__proto__ = pro;");
21152 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21153 CheckInstanceCheckedAccessors(true);
21157 TEST(TryFinallyMessage) {
21158 LocalContext context;
21159 v8::HandleScope scope(context->GetIsolate());
21161 // Test that the original error message is not lost if there is a
21162 // recursive call into Javascript is done in the finally block, e.g. to
21163 // initialize an IC. (crbug.com/129171)
21164 TryCatch try_catch;
21165 const char* trigger_ic =
21167 " throw new Error('test'); \n"
21170 " x++; \n" // Trigger an IC initialization here.
21172 CompileRun(trigger_ic);
21173 CHECK(try_catch.HasCaught());
21174 Local<Message> message = try_catch.Message();
21175 CHECK(!message.IsEmpty());
21176 CHECK_EQ(2, message->GetLineNumber());
21180 // Test that the original exception message is indeed overwritten if
21181 // a new error is thrown in the finally block.
21182 TryCatch try_catch;
21183 const char* throw_again =
21185 " throw new Error('test'); \n"
21189 " throw new Error('again'); \n" // This is the new uncaught error.
21191 CompileRun(throw_again);
21192 CHECK(try_catch.HasCaught());
21193 Local<Message> message = try_catch.Message();
21194 CHECK(!message.IsEmpty());
21195 CHECK_EQ(6, message->GetLineNumber());
21200 static void Helper137002(bool do_store,
21202 bool remove_accessor,
21203 bool interceptor) {
21204 LocalContext context;
21205 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21207 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21209 templ->SetAccessor(v8_str("foo"),
21210 GetterWhichReturns42,
21211 SetterWhichSetsYOnThisTo23);
21213 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21215 // Turn monomorphic on slow object with native accessor, then turn
21216 // polymorphic, finally optimize to create negative lookup and fail.
21217 CompileRun(do_store ?
21218 "function f(x) { x.foo = void 0; }" :
21219 "function f(x) { return x.foo; }");
21220 CompileRun("obj.y = void 0;");
21221 if (!interceptor) {
21222 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21224 CompileRun("obj.__proto__ = null;"
21225 "f(obj); f(obj); f(obj);");
21227 CompileRun("f({});");
21229 CompileRun("obj.y = void 0;"
21230 "%OptimizeFunctionOnNextCall(f);");
21231 if (remove_accessor) {
21232 CompileRun("delete obj.foo;");
21234 CompileRun("var result = f(obj);");
21236 CompileRun("result = obj.y;");
21238 if (remove_accessor && !interceptor) {
21239 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21241 CHECK_EQ(do_store ? 23 : 42,
21242 context->Global()->Get(v8_str("result"))->Int32Value());
21247 THREADED_TEST(Regress137002a) {
21248 i::FLAG_allow_natives_syntax = true;
21249 i::FLAG_compilation_cache = false;
21250 v8::HandleScope scope(CcTest::isolate());
21251 for (int i = 0; i < 16; i++) {
21252 Helper137002(i & 8, i & 4, i & 2, i & 1);
21257 THREADED_TEST(Regress137002b) {
21258 i::FLAG_allow_natives_syntax = true;
21259 LocalContext context;
21260 v8::Isolate* isolate = context->GetIsolate();
21261 v8::HandleScope scope(isolate);
21262 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21263 templ->SetAccessor(v8_str("foo"),
21264 GetterWhichReturns42,
21265 SetterWhichSetsYOnThisTo23);
21266 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21268 // Turn monomorphic on slow object with native accessor, then just
21269 // delete the property and fail.
21270 CompileRun("function load(x) { return x.foo; }"
21271 "function store(x) { x.foo = void 0; }"
21272 "function keyed_load(x, key) { return x[key]; }"
21273 // Second version of function has a different source (add void 0)
21274 // so that it does not share code with the first version. This
21275 // ensures that the ICs are monomorphic.
21276 "function load2(x) { void 0; return x.foo; }"
21277 "function store2(x) { void 0; x.foo = void 0; }"
21278 "function keyed_load2(x, key) { void 0; return x[key]; }"
21281 "obj.__proto__ = null;"
21283 "subobj.y = void 0;"
21284 "subobj.__proto__ = obj;"
21285 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21287 // Make the ICs monomorphic.
21288 "load(obj); load(obj);"
21289 "load2(subobj); load2(subobj);"
21290 "store(obj); store(obj);"
21291 "store2(subobj); store2(subobj);"
21292 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21293 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21295 // Actually test the shiny new ICs and better not crash. This
21296 // serves as a regression test for issue 142088 as well.
21301 "keyed_load(obj, 'foo');"
21302 "keyed_load2(subobj, 'foo');"
21304 // Delete the accessor. It better not be called any more now.
21307 "subobj.y = void 0;"
21309 "var load_result = load(obj);"
21310 "var load_result2 = load2(subobj);"
21311 "var keyed_load_result = keyed_load(obj, 'foo');"
21312 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21315 "var y_from_obj = obj.y;"
21316 "var y_from_subobj = subobj.y;");
21317 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21318 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21319 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21320 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21321 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21322 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21326 THREADED_TEST(Regress142088) {
21327 i::FLAG_allow_natives_syntax = true;
21328 LocalContext context;
21329 v8::Isolate* isolate = context->GetIsolate();
21330 v8::HandleScope scope(isolate);
21331 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21332 templ->SetAccessor(v8_str("foo"),
21333 GetterWhichReturns42,
21334 SetterWhichSetsYOnThisTo23);
21335 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21337 CompileRun("function load(x) { return x.foo; }"
21338 "var o = Object.create(obj);"
21339 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21340 "load(o); load(o); load(o); load(o);");
21344 THREADED_TEST(Regress137496) {
21345 i::FLAG_expose_gc = true;
21346 LocalContext context;
21347 v8::HandleScope scope(context->GetIsolate());
21349 // Compile a try-finally clause where the finally block causes a GC
21350 // while there still is a message pending for external reporting.
21351 TryCatch try_catch;
21352 try_catch.SetVerbose(true);
21353 CompileRun("try { throw new Error(); } finally { gc(); }");
21354 CHECK(try_catch.HasCaught());
21358 THREADED_TEST(Regress149912) {
21359 LocalContext context;
21360 v8::HandleScope scope(context->GetIsolate());
21361 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21362 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21363 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21364 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21368 THREADED_TEST(Regress157124) {
21369 LocalContext context;
21370 v8::Isolate* isolate = context->GetIsolate();
21371 v8::HandleScope scope(isolate);
21372 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21373 Local<Object> obj = templ->NewInstance();
21374 obj->GetIdentityHash();
21375 obj->DeleteHiddenValue(v8_str("Bug"));
21379 THREADED_TEST(Regress2535) {
21380 i::FLAG_harmony_collections = true;
21381 LocalContext context;
21382 v8::HandleScope scope(context->GetIsolate());
21383 Local<Value> set_value = CompileRun("new Set();");
21384 Local<Object> set_object(Local<Object>::Cast(set_value));
21385 CHECK_EQ(0, set_object->InternalFieldCount());
21386 Local<Value> map_value = CompileRun("new Map();");
21387 Local<Object> map_object(Local<Object>::Cast(map_value));
21388 CHECK_EQ(0, map_object->InternalFieldCount());
21392 THREADED_TEST(Regress2746) {
21393 LocalContext context;
21394 v8::Isolate* isolate = context->GetIsolate();
21395 v8::HandleScope scope(isolate);
21396 Local<Object> obj = Object::New(isolate);
21397 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21398 obj->SetHiddenValue(key, v8::Undefined(isolate));
21399 Local<Value> value = obj->GetHiddenValue(key);
21400 CHECK(!value.IsEmpty());
21401 CHECK(value->IsUndefined());
21405 THREADED_TEST(Regress260106) {
21406 LocalContext context;
21407 v8::Isolate* isolate = context->GetIsolate();
21408 v8::HandleScope scope(isolate);
21409 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21411 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21412 Local<Function> function = templ->GetFunction();
21413 CHECK(!function.IsEmpty());
21414 CHECK(function->IsFunction());
21418 THREADED_TEST(JSONParseObject) {
21419 LocalContext context;
21420 HandleScope scope(context->GetIsolate());
21421 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21422 Handle<Object> global = context->Global();
21423 global->Set(v8_str("obj"), obj);
21424 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21428 THREADED_TEST(JSONParseNumber) {
21429 LocalContext context;
21430 HandleScope scope(context->GetIsolate());
21431 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21432 Handle<Object> global = context->Global();
21433 global->Set(v8_str("obj"), obj);
21434 ExpectString("JSON.stringify(obj)", "42");
21439 class ThreadInterruptTest {
21441 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21442 ~ThreadInterruptTest() {}
21445 InterruptThread i_thread(this);
21449 CHECK_EQ(kExpectedValue, sem_value_);
21453 static const int kExpectedValue = 1;
21455 class InterruptThread : public i::Thread {
21457 explicit InterruptThread(ThreadInterruptTest* test)
21458 : Thread("InterruptThread"), test_(test) {}
21460 virtual void Run() {
21461 struct sigaction action;
21463 // Ensure that we'll enter waiting condition
21466 // Setup signal handler
21467 memset(&action, 0, sizeof(action));
21468 action.sa_handler = SignalHandler;
21469 sigaction(SIGCHLD, &action, NULL);
21472 kill(getpid(), SIGCHLD);
21474 // Ensure that if wait has returned because of error
21477 // Set value and signal semaphore
21478 test_->sem_value_ = 1;
21479 test_->sem_.Signal();
21482 static void SignalHandler(int signal) {
21486 ThreadInterruptTest* test_;
21490 volatile int sem_value_;
21494 THREADED_TEST(SemaphoreInterruption) {
21495 ThreadInterruptTest().RunTest();
21499 #endif // V8_OS_POSIX
21502 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21504 v8::AccessType type,
21505 Local<Value> data) {
21506 i::PrintF("Named access blocked.\n");
21511 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21513 v8::AccessType type,
21514 Local<Value> data) {
21515 i::PrintF("Indexed access blocked.\n");
21520 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21525 TEST(JSONStringifyAccessCheck) {
21526 v8::V8::Initialize();
21527 v8::Isolate* isolate = CcTest::isolate();
21528 v8::HandleScope scope(isolate);
21530 // Create an ObjectTemplate for global objects and install access
21531 // check callbacks that will block access.
21532 v8::Handle<v8::ObjectTemplate> global_template =
21533 v8::ObjectTemplate::New(isolate);
21534 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21535 IndexAccessAlwaysBlocked);
21537 // Create a context and set an x property on it's global object.
21538 LocalContext context0(NULL, global_template);
21539 v8::Handle<v8::Object> global0 = context0->Global();
21540 global0->Set(v8_str("x"), v8_num(42));
21541 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21543 for (int i = 0; i < 2; i++) {
21545 // Install a toJSON function on the second run.
21546 v8::Handle<v8::FunctionTemplate> toJSON =
21547 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21549 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21551 // Create a context with a different security token so that the
21552 // failed access check callback will be called on each access.
21553 LocalContext context1(NULL, global_template);
21554 context1->Global()->Set(v8_str("other"), global0);
21556 ExpectString("JSON.stringify(other)", "{}");
21557 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21558 "{\"a\":{},\"b\":[\"c\"]}");
21559 ExpectString("JSON.stringify([other, 'b', 'c'])",
21560 "[{},\"b\",\"c\"]");
21562 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21563 array->Set(0, v8_str("a"));
21564 array->Set(1, v8_str("b"));
21565 context1->Global()->Set(v8_str("array"), array);
21566 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21567 array->TurnOnAccessCheck();
21568 ExpectString("JSON.stringify(array)", "[]");
21569 ExpectString("JSON.stringify([array])", "[[]]");
21570 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21575 bool access_check_fail_thrown = false;
21576 bool catch_callback_called = false;
21579 // Failed access check callback that performs a GC on each invocation.
21580 void FailedAccessCheckThrows(Local<v8::Object> target,
21581 v8::AccessType type,
21582 Local<v8::Value> data) {
21583 access_check_fail_thrown = true;
21584 i::PrintF("Access check failed. Error thrown.\n");
21585 CcTest::isolate()->ThrowException(
21586 v8::Exception::Error(v8_str("cross context")));
21590 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21591 for (int i = 0; i < args.Length(); i++) {
21592 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21594 catch_callback_called = true;
21598 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21599 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21603 void CheckCorrectThrow(const char* script) {
21604 // Test that the script, when wrapped into a try-catch, triggers the catch
21605 // clause due to failed access check throwing an exception.
21606 // The subsequent try-catch should run without any exception.
21607 access_check_fail_thrown = false;
21608 catch_callback_called = false;
21609 i::ScopedVector<char> source(1024);
21610 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21611 CompileRun(source.start());
21612 CHECK(access_check_fail_thrown);
21613 CHECK(catch_callback_called);
21615 access_check_fail_thrown = false;
21616 catch_callback_called = false;
21617 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21618 CHECK(!access_check_fail_thrown);
21619 CHECK(!catch_callback_called);
21623 TEST(AccessCheckThrows) {
21624 i::FLAG_allow_natives_syntax = true;
21625 v8::V8::Initialize();
21626 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21627 v8::Isolate* isolate = CcTest::isolate();
21628 v8::HandleScope scope(isolate);
21630 // Create an ObjectTemplate for global objects and install access
21631 // check callbacks that will block access.
21632 v8::Handle<v8::ObjectTemplate> global_template =
21633 v8::ObjectTemplate::New(isolate);
21634 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21635 IndexAccessAlwaysBlocked);
21637 // Create a context and set an x property on it's global object.
21638 LocalContext context0(NULL, global_template);
21639 context0->Global()->Set(v8_str("x"), v8_num(42));
21640 v8::Handle<v8::Object> global0 = context0->Global();
21642 // Create a context with a different security token so that the
21643 // failed access check callback will be called on each access.
21644 LocalContext context1(NULL, global_template);
21645 context1->Global()->Set(v8_str("other"), global0);
21647 v8::Handle<v8::FunctionTemplate> catcher_fun =
21648 v8::FunctionTemplate::New(isolate, CatcherCallback);
21649 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21651 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21652 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21653 context1->Global()->Set(v8_str("has_own_property"),
21654 has_own_property_fun->GetFunction());
21656 { v8::TryCatch try_catch;
21657 access_check_fail_thrown = false;
21658 CompileRun("other.x;");
21659 CHECK(access_check_fail_thrown);
21660 CHECK(try_catch.HasCaught());
21663 CheckCorrectThrow("other.x");
21664 CheckCorrectThrow("other[1]");
21665 CheckCorrectThrow("JSON.stringify(other)");
21666 CheckCorrectThrow("has_own_property(other, 'x')");
21667 CheckCorrectThrow("%GetProperty(other, 'x')");
21668 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21669 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21670 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21671 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21672 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21673 CheckCorrectThrow("%HasProperty(other, 'x')");
21674 CheckCorrectThrow("%HasElement(other, 1)");
21675 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21676 CheckCorrectThrow("%GetPropertyNames(other)");
21677 // PROPERTY_ATTRIBUTES_NONE = 0
21678 CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21679 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21680 "other, 'x', null, null, 1)");
21682 // Reset the failed access check callback so it does not influence
21683 // the other tests.
21684 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21688 THREADED_TEST(Regress256330) {
21689 i::FLAG_allow_natives_syntax = true;
21690 LocalContext context;
21691 v8::HandleScope scope(context->GetIsolate());
21692 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21693 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21694 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21695 CompileRun("\"use strict\"; var o = new Bug;"
21696 "function f(o) { o.x = 10; };"
21697 "f(o); f(o); f(o);"
21698 "%OptimizeFunctionOnNextCall(f);"
21700 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21704 THREADED_TEST(CrankshaftInterceptorSetter) {
21705 i::FLAG_allow_natives_syntax = true;
21706 v8::HandleScope scope(CcTest::isolate());
21707 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21708 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21710 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21711 CompileRun("var obj = new Obj;"
21712 // Initialize fields to avoid transitions later.
21714 "obj.accessor_age = 42;"
21715 "function setter(i) { this.accessor_age = i; };"
21716 "function getter() { return this.accessor_age; };"
21717 "function setAge(i) { obj.age = i; };"
21718 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21722 "%OptimizeFunctionOnNextCall(setAge);"
21724 // All stores went through the interceptor.
21725 ExpectInt32("obj.interceptor_age", 4);
21726 ExpectInt32("obj.accessor_age", 42);
21730 THREADED_TEST(CrankshaftInterceptorGetter) {
21731 i::FLAG_allow_natives_syntax = true;
21732 v8::HandleScope scope(CcTest::isolate());
21733 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21734 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21736 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21737 CompileRun("var obj = new Obj;"
21738 // Initialize fields to avoid transitions later.
21740 "obj.accessor_age = 42;"
21741 "function getter() { return this.accessor_age; };"
21742 "function getAge() { return obj.interceptor_age; };"
21743 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21747 "%OptimizeFunctionOnNextCall(getAge);");
21748 // Access through interceptor.
21749 ExpectInt32("getAge()", 1);
21753 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21754 i::FLAG_allow_natives_syntax = true;
21755 v8::HandleScope scope(CcTest::isolate());
21756 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21757 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21759 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21760 CompileRun("var obj = new Obj;"
21761 "obj.__proto__.interceptor_age = 42;"
21763 "function getAge() { return obj.interceptor_age; };");
21764 ExpectInt32("getAge();", 100);
21765 ExpectInt32("getAge();", 100);
21766 ExpectInt32("getAge();", 100);
21767 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21768 // Access through interceptor.
21769 ExpectInt32("getAge();", 100);
21773 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21774 i::FLAG_allow_natives_syntax = true;
21775 v8::HandleScope scope(CcTest::isolate());
21776 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21777 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21779 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21780 CompileRun("var obj = new Obj;"
21781 "obj.age = 100000;"
21782 "function setAge(i) { obj.age = i };"
21786 "%OptimizeFunctionOnNextCall(setAge);"
21788 ExpectInt32("obj.age", 100000);
21789 ExpectInt32("obj.interceptor_age", 103);
21793 class RequestInterruptTestBase {
21795 RequestInterruptTestBase()
21797 isolate_(env_->GetIsolate()),
21800 should_continue_(true) {
21803 virtual ~RequestInterruptTestBase() { }
21805 virtual void TestBody() = 0;
21808 InterruptThread i_thread(this);
21811 v8::HandleScope handle_scope(isolate_);
21815 isolate_->ClearInterrupt();
21817 // Verify we arrived here because interruptor was called
21818 // not due to a bug causing us to exit the loop too early.
21819 CHECK(!should_continue());
21822 void WakeUpInterruptor() {
21826 bool should_continue() const { return should_continue_; }
21828 bool ShouldContinue() {
21830 if (--warmup_ == 0) {
21831 WakeUpInterruptor();
21835 return should_continue_;
21839 static void ShouldContinueCallback(
21840 const v8::FunctionCallbackInfo<Value>& info) {
21841 RequestInterruptTestBase* test =
21842 reinterpret_cast<RequestInterruptTestBase*>(
21843 info.Data().As<v8::External>()->Value());
21844 info.GetReturnValue().Set(test->ShouldContinue());
21847 class InterruptThread : public i::Thread {
21849 explicit InterruptThread(RequestInterruptTestBase* test)
21850 : Thread("RequestInterruptTest"), test_(test) {}
21852 virtual void Run() {
21853 test_->sem_.Wait();
21854 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21857 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21858 reinterpret_cast<RequestInterruptTestBase*>(data)->
21859 should_continue_ = false;
21863 RequestInterruptTestBase* test_;
21867 v8::Isolate* isolate_;
21870 bool should_continue_;
21874 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21876 virtual void TestBody() {
21877 Local<Function> func = Function::New(
21878 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21879 env_->Global()->Set(v8_str("ShouldContinue"), func);
21881 CompileRun("while (ShouldContinue()) { }");
21886 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21888 virtual void TestBody() {
21889 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21890 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21891 proto->Set(v8_str("shouldContinue"), Function::New(
21892 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21893 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21895 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21900 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21902 virtual void TestBody() {
21903 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21904 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21905 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21906 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21907 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21909 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21914 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21916 virtual void TestBody() {
21917 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21918 t->InstanceTemplate()->SetNativeDataProperty(
21919 v8_str("shouldContinue"),
21920 &ShouldContinueNativeGetter,
21922 v8::External::New(isolate_, this));
21923 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21925 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21929 static void ShouldContinueNativeGetter(
21930 Local<String> property,
21931 const v8::PropertyCallbackInfo<v8::Value>& info) {
21932 RequestInterruptTestBase* test =
21933 reinterpret_cast<RequestInterruptTestBase*>(
21934 info.Data().As<v8::External>()->Value());
21935 info.GetReturnValue().Set(test->ShouldContinue());
21940 class RequestInterruptTestWithMethodCallAndInterceptor
21941 : public RequestInterruptTestBase {
21943 virtual void TestBody() {
21944 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21945 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21946 proto->Set(v8_str("shouldContinue"), Function::New(
21947 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21948 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21949 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21951 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21953 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21957 static void EmptyInterceptor(
21958 Local<String> property,
21959 const v8::PropertyCallbackInfo<v8::Value>& info) {
21964 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21966 virtual void TestBody() {
21967 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21969 WakeUpInterruptorCallback,
21970 v8::External::New(isolate_, this)));
21972 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21974 ShouldContinueCallback,
21975 v8::External::New(isolate_, this)));
21977 i::FLAG_allow_natives_syntax = true;
21978 CompileRun("function loopish(o) {"
21980 " while (o.abs(1) > 0) {"
21981 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21983 " if (--pre === 0) WakeUpInterruptor(o === Math);"
21988 "var obj = {abs: function () { return i-- }, x: null};"
21991 "%OptimizeFunctionOnNextCall(loopish);"
21994 i::FLAG_allow_natives_syntax = false;
21998 static void WakeUpInterruptorCallback(
21999 const v8::FunctionCallbackInfo<Value>& info) {
22000 if (!info[0]->BooleanValue()) return;
22002 RequestInterruptTestBase* test =
22003 reinterpret_cast<RequestInterruptTestBase*>(
22004 info.Data().As<v8::External>()->Value());
22005 test->WakeUpInterruptor();
22008 static void ShouldContinueCallback(
22009 const v8::FunctionCallbackInfo<Value>& info) {
22010 RequestInterruptTestBase* test =
22011 reinterpret_cast<RequestInterruptTestBase*>(
22012 info.Data().As<v8::External>()->Value());
22013 info.GetReturnValue().Set(test->should_continue());
22018 TEST(RequestInterruptTestWithFunctionCall) {
22019 RequestInterruptTestWithFunctionCall().RunTest();
22023 TEST(RequestInterruptTestWithMethodCall) {
22024 RequestInterruptTestWithMethodCall().RunTest();
22028 TEST(RequestInterruptTestWithAccessor) {
22029 RequestInterruptTestWithAccessor().RunTest();
22033 TEST(RequestInterruptTestWithNativeAccessor) {
22034 RequestInterruptTestWithNativeAccessor().RunTest();
22038 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22039 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22043 TEST(RequestInterruptTestWithMathAbs) {
22044 RequestInterruptTestWithMathAbs().RunTest();
22048 static Local<Value> function_new_expected_env;
22049 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22050 CHECK_EQ(function_new_expected_env, info.Data());
22051 info.GetReturnValue().Set(17);
22055 THREADED_TEST(FunctionNew) {
22057 v8::Isolate* isolate = env->GetIsolate();
22058 v8::HandleScope scope(isolate);
22059 Local<Object> data = v8::Object::New(isolate);
22060 function_new_expected_env = data;
22061 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22062 env->Global()->Set(v8_str("func"), func);
22063 Local<Value> result = CompileRun("func();");
22064 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22065 // Verify function not cached
22066 int serial_number =
22067 i::Smi::cast(v8::Utils::OpenHandle(*func)
22068 ->shared()->get_api_func_data()->serial_number())->value();
22069 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22070 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22071 i::Handle<i::Object> elm =
22072 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22073 CHECK(elm->IsUndefined());
22074 // Verify that each Function::New creates a new function instance
22075 Local<Object> data2 = v8::Object::New(isolate);
22076 function_new_expected_env = data2;
22077 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22078 CHECK(!func2->IsNull());
22079 CHECK_NE(func, func2);
22080 env->Global()->Set(v8_str("func2"), func2);
22081 Local<Value> result2 = CompileRun("func2();");
22082 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22086 TEST(EscapeableHandleScope) {
22087 HandleScope outer_scope(CcTest::isolate());
22088 LocalContext context;
22089 const int runs = 10;
22090 Local<String> values[runs];
22091 for (int i = 0; i < runs; i++) {
22092 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22093 Local<String> value;
22094 if (i != 0) value = v8_str("escape value");
22095 values[i] = inner_scope.Escape(value);
22097 for (int i = 0; i < runs; i++) {
22098 Local<String> expected;
22100 CHECK_EQ(v8_str("escape value"), values[i]);
22102 CHECK(values[i].IsEmpty());
22108 static void SetterWhichExpectsThisAndHolderToDiffer(
22109 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22110 CHECK(info.Holder() != info.This());
22114 TEST(Regress239669) {
22115 LocalContext context;
22116 v8::Isolate* isolate = context->GetIsolate();
22117 v8::HandleScope scope(isolate);
22118 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22119 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22120 context->Global()->Set(v8_str("P"), templ->NewInstance());
22125 "C1.prototype = P;"
22126 "for (var i = 0; i < 4; i++ ) {"
22132 class ApiCallOptimizationChecker {
22134 static Local<Object> data;
22135 static Local<Object> receiver;
22136 static Local<Object> holder;
22137 static Local<Object> callee;
22140 static void OptimizationCallback(
22141 const v8::FunctionCallbackInfo<v8::Value>& info) {
22142 CHECK(callee == info.Callee());
22143 CHECK(data == info.Data());
22144 CHECK(receiver == info.This());
22145 if (info.Length() == 1) {
22146 CHECK_EQ(v8_num(1), info[0]);
22148 CHECK(holder == info.Holder());
22150 info.GetReturnValue().Set(v8_str("returned"));
22154 enum SignatureType {
22156 kSignatureOnReceiver,
22157 kSignatureOnPrototype
22161 SignatureType signature_types[] =
22162 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22163 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22164 SignatureType signature_type = signature_types[i];
22165 for (int j = 0; j < 2; j++) {
22166 bool global = j == 0;
22167 int key = signature_type +
22168 ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22169 Run(signature_type, global, key);
22174 void Run(SignatureType signature_type, bool global, int key) {
22175 v8::Isolate* isolate = CcTest::isolate();
22176 v8::HandleScope scope(isolate);
22177 // Build a template for signature checks.
22178 Local<v8::ObjectTemplate> signature_template;
22179 Local<v8::Signature> signature;
22181 Local<v8::FunctionTemplate> parent_template =
22182 FunctionTemplate::New(isolate);
22183 parent_template->SetHiddenPrototype(true);
22184 Local<v8::FunctionTemplate> function_template
22185 = FunctionTemplate::New(isolate);
22186 function_template->Inherit(parent_template);
22187 switch (signature_type) {
22190 case kSignatureOnReceiver:
22191 signature = v8::Signature::New(isolate, function_template);
22193 case kSignatureOnPrototype:
22194 signature = v8::Signature::New(isolate, parent_template);
22197 signature_template = function_template->InstanceTemplate();
22199 // Global object must pass checks.
22200 Local<v8::Context> context =
22201 v8::Context::New(isolate, NULL, signature_template);
22202 v8::Context::Scope context_scope(context);
22203 // Install regular object that can pass signature checks.
22204 Local<Object> function_receiver = signature_template->NewInstance();
22205 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22206 // Get the holder objects.
22207 Local<Object> inner_global =
22208 Local<Object>::Cast(context->Global()->GetPrototype());
22209 // Install functions on hidden prototype object if there is one.
22210 data = Object::New(isolate);
22211 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22212 isolate, OptimizationCallback, data, signature);
22213 Local<Function> function = function_template->GetFunction();
22214 Local<Object> global_holder = inner_global;
22215 Local<Object> function_holder = function_receiver;
22216 if (signature_type == kSignatureOnPrototype) {
22217 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22218 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22220 global_holder->Set(v8_str("g_f"), function);
22221 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22222 function_holder->Set(v8_str("f"), function);
22223 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22224 // Initialize expected values.
22228 receiver = context->Global();
22229 holder = inner_global;
22231 holder = function_receiver;
22232 // If not using a signature, add something else to the prototype chain
22233 // to test the case that holder != receiver
22234 if (signature_type == kNoSignature) {
22235 receiver = Local<Object>::Cast(CompileRun(
22236 "var receiver_subclass = {};\n"
22237 "receiver_subclass.__proto__ = function_receiver;\n"
22238 "receiver_subclass"));
22240 receiver = Local<Object>::Cast(CompileRun(
22241 "var receiver_subclass = function_receiver;\n"
22242 "receiver_subclass"));
22245 // With no signature, the holder is not set.
22246 if (signature_type == kNoSignature) holder = receiver;
22247 // build wrap_function
22248 i::ScopedVector<char> wrap_function(200);
22252 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22253 "function wrap_get_%d() { return this.g_acc; }\n"
22254 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22259 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22260 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22261 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22264 // build source string
22265 i::ScopedVector<char> source(1000);
22268 "%s\n" // wrap functions
22269 "function wrap_f() { return wrap_f_%d(); }\n"
22270 "function wrap_get() { return wrap_get_%d(); }\n"
22271 "function wrap_set() { return wrap_set_%d(); }\n"
22272 "check = function(returned) {\n"
22273 " if (returned !== 'returned') { throw returned; }\n"
22276 "check(wrap_f());\n"
22277 "check(wrap_f());\n"
22278 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22279 "check(wrap_f());\n"
22281 "check(wrap_get());\n"
22282 "check(wrap_get());\n"
22283 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22284 "check(wrap_get());\n"
22286 "check = function(returned) {\n"
22287 " if (returned !== 1) { throw returned; }\n"
22289 "check(wrap_set());\n"
22290 "check(wrap_set());\n"
22291 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22292 "check(wrap_set());\n",
22293 wrap_function.start(), key, key, key, key, key, key);
22294 v8::TryCatch try_catch;
22295 CompileRun(source.start());
22296 ASSERT(!try_catch.HasCaught());
22297 CHECK_EQ(9, count);
22302 Local<Object> ApiCallOptimizationChecker::data;
22303 Local<Object> ApiCallOptimizationChecker::receiver;
22304 Local<Object> ApiCallOptimizationChecker::holder;
22305 Local<Object> ApiCallOptimizationChecker::callee;
22306 int ApiCallOptimizationChecker::count = 0;
22309 TEST(TestFunctionCallOptimization) {
22310 i::FLAG_allow_natives_syntax = true;
22311 ApiCallOptimizationChecker checker;
22316 static const char* last_event_message;
22317 static int last_event_status;
22318 void StoringEventLoggerCallback(const char* message, int status) {
22319 last_event_message = message;
22320 last_event_status = status;
22324 TEST(EventLogging) {
22325 v8::Isolate* isolate = CcTest::isolate();
22326 isolate->SetEventLogger(StoringEventLoggerCallback);
22327 v8::internal::HistogramTimer* histogramTimer =
22328 new v8::internal::HistogramTimer(
22329 "V8.Test", 0, 10000, 50,
22330 reinterpret_cast<v8::internal::Isolate*>(isolate));
22331 histogramTimer->Start();
22332 CHECK_EQ("V8.Test", last_event_message);
22333 CHECK_EQ(0, last_event_status);
22334 histogramTimer->Stop();
22335 CHECK_EQ("V8.Test", last_event_message);
22336 CHECK_EQ(1, last_event_status);
22341 LocalContext context;
22342 v8::Isolate* isolate = context->GetIsolate();
22343 v8::HandleScope scope(isolate);
22344 Handle<Object> global = context->Global();
22347 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22348 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22349 Handle<v8::Promise> p = pr->GetPromise();
22350 Handle<v8::Promise> r = rr->GetPromise();
22352 // IsPromise predicate.
22353 CHECK(p->IsPromise());
22354 CHECK(r->IsPromise());
22355 Handle<Value> o = v8::Object::New(isolate);
22356 CHECK(!o->IsPromise());
22358 // Resolution and rejection.
22359 pr->Resolve(v8::Integer::New(isolate, 1));
22360 CHECK(p->IsPromise());
22361 rr->Reject(v8::Integer::New(isolate, 2));
22362 CHECK(r->IsPromise());
22364 // Chaining non-pending promises.
22368 "function f1(x) { x1 = x; return x+1 };\n"
22369 "function f2(x) { x2 = x; return x+1 };\n");
22370 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22371 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22374 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22375 isolate->RunMicrotasks();
22376 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22379 isolate->RunMicrotasks();
22380 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22383 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22384 isolate->RunMicrotasks();
22385 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22388 isolate->RunMicrotasks();
22389 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22391 // Chaining pending promises.
22392 CompileRun("x1 = x2 = 0;");
22393 pr = v8::Promise::Resolver::New(isolate);
22394 rr = v8::Promise::Resolver::New(isolate);
22396 pr->GetPromise()->Chain(f1);
22397 rr->GetPromise()->Catch(f2);
22398 isolate->RunMicrotasks();
22399 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22400 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22402 pr->Resolve(v8::Integer::New(isolate, 1));
22403 rr->Reject(v8::Integer::New(isolate, 2));
22404 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22405 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22407 isolate->RunMicrotasks();
22408 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22409 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22412 CompileRun("x1 = x2 = 0;");
22413 pr = v8::Promise::Resolver::New(isolate);
22414 pr->GetPromise()->Chain(f1)->Chain(f2);
22415 pr->Resolve(v8::Integer::New(isolate, 3));
22416 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22417 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22418 isolate->RunMicrotasks();
22419 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22420 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22422 CompileRun("x1 = x2 = 0;");
22423 rr = v8::Promise::Resolver::New(isolate);
22424 rr->GetPromise()->Catch(f1)->Chain(f2);
22425 rr->Reject(v8::Integer::New(isolate, 3));
22426 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22427 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22428 isolate->RunMicrotasks();
22429 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22430 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22434 TEST(DisallowJavascriptExecutionScope) {
22435 LocalContext context;
22436 v8::Isolate* isolate = context->GetIsolate();
22437 v8::HandleScope scope(isolate);
22438 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22439 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22444 TEST(AllowJavascriptExecutionScope) {
22445 LocalContext context;
22446 v8::Isolate* isolate = context->GetIsolate();
22447 v8::HandleScope scope(isolate);
22448 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22449 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22450 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22451 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22452 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22458 TEST(ThrowOnJavascriptExecution) {
22459 LocalContext context;
22460 v8::Isolate* isolate = context->GetIsolate();
22461 v8::HandleScope scope(isolate);
22462 v8::TryCatch try_catch;
22463 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22464 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22466 CHECK(try_catch.HasCaught());
22470 TEST(Regress354123) {
22471 LocalContext current;
22472 v8::Isolate* isolate = current->GetIsolate();
22473 v8::HandleScope scope(isolate);
22475 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22476 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22477 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22479 // Test access using __proto__ from the prototype chain.
22480 named_access_count = 0;
22481 CompileRun("friend.__proto__ = {};");
22482 CHECK_EQ(2, named_access_count);
22483 CompileRun("friend.__proto__;");
22484 CHECK_EQ(4, named_access_count);
22486 // Test access using __proto__ as a hijacked function (A).
22487 named_access_count = 0;
22488 CompileRun("var p = Object.prototype;"
22489 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22490 "f.call(friend, {});");
22491 CHECK_EQ(1, named_access_count);
22492 CompileRun("var p = Object.prototype;"
22493 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22494 "f.call(friend);");
22495 CHECK_EQ(2, named_access_count);
22497 // Test access using __proto__ as a hijacked function (B).
22498 named_access_count = 0;
22499 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22500 "f.call(friend, {});");
22501 CHECK_EQ(1, named_access_count);
22502 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22503 "f.call(friend);");
22504 CHECK_EQ(2, named_access_count);
22506 // Test access using Object.setPrototypeOf reflective method.
22507 named_access_count = 0;
22508 CompileRun("Object.setPrototypeOf(friend, {});");
22509 CHECK_EQ(1, named_access_count);
22510 CompileRun("Object.getPrototypeOf(friend);");
22511 CHECK_EQ(2, named_access_count);
22515 TEST(CaptureStackTraceForStackOverflow) {
22516 v8::internal::FLAG_stack_size = 150;
22517 LocalContext current;
22518 v8::Isolate* isolate = current->GetIsolate();
22519 v8::HandleScope scope(isolate);
22520 V8::SetCaptureStackTraceForUncaughtExceptions(
22521 true, 10, v8::StackTrace::kDetailed);
22522 v8::TryCatch try_catch;
22523 CompileRun("(function f(x) { f(x+1); })(0)");
22524 CHECK(try_catch.HasCaught());