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(SymbolProperties) {
2752 i::FLAG_harmony_symbols = true;
2755 v8::Isolate* isolate = env->GetIsolate();
2756 v8::HandleScope scope(isolate);
2758 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2759 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2760 v8::Local<v8::Symbol> sym2 =
2761 v8::Symbol::New(isolate, v8_str("my-symbol"));
2763 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2765 // Check basic symbol functionality.
2766 CHECK(sym1->IsSymbol());
2767 CHECK(sym2->IsSymbol());
2768 CHECK(!obj->IsSymbol());
2770 CHECK(sym1->Equals(sym1));
2771 CHECK(sym2->Equals(sym2));
2772 CHECK(!sym1->Equals(sym2));
2773 CHECK(!sym2->Equals(sym1));
2774 CHECK(sym1->StrictEquals(sym1));
2775 CHECK(sym2->StrictEquals(sym2));
2776 CHECK(!sym1->StrictEquals(sym2));
2777 CHECK(!sym2->StrictEquals(sym1));
2779 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2781 v8::Local<v8::Value> sym_val = sym2;
2782 CHECK(sym_val->IsSymbol());
2783 CHECK(sym_val->Equals(sym2));
2784 CHECK(sym_val->StrictEquals(sym2));
2785 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2787 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2788 CHECK(sym_obj->IsSymbolObject());
2789 CHECK(!sym2->IsSymbolObject());
2790 CHECK(!obj->IsSymbolObject());
2791 CHECK(!sym_obj->Equals(sym2));
2792 CHECK(!sym_obj->StrictEquals(sym2));
2793 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2794 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2796 // Make sure delete of a non-existent symbol property works.
2797 CHECK(obj->Delete(sym1));
2798 CHECK(!obj->Has(sym1));
2800 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2801 CHECK(obj->Has(sym1));
2802 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2803 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2804 CHECK(obj->Has(sym1));
2805 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2806 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2808 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2809 int num_props = obj->GetPropertyNames()->Length();
2810 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2811 v8::Integer::New(isolate, 20)));
2812 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2813 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2815 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2817 // Add another property and delete it afterwards to force the object in
2819 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2820 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2821 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2822 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2823 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2825 CHECK(obj->Has(sym1));
2826 CHECK(obj->Has(sym2));
2827 CHECK(obj->Delete(sym2));
2828 CHECK(obj->Has(sym1));
2829 CHECK(!obj->Has(sym2));
2830 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2831 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2833 // Symbol properties are inherited.
2834 v8::Local<v8::Object> child = v8::Object::New(isolate);
2835 child->SetPrototype(obj);
2836 CHECK(child->Has(sym1));
2837 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2838 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2842 THREADED_TEST(PrivateProperties) {
2844 v8::Isolate* isolate = env->GetIsolate();
2845 v8::HandleScope scope(isolate);
2847 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2848 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2849 v8::Local<v8::Private> priv2 =
2850 v8::Private::New(isolate, v8_str("my-private"));
2852 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2854 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2856 // Make sure delete of a non-existent private symbol property works.
2857 CHECK(obj->DeletePrivate(priv1));
2858 CHECK(!obj->HasPrivate(priv1));
2860 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2861 CHECK(obj->HasPrivate(priv1));
2862 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2863 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2864 CHECK(obj->HasPrivate(priv1));
2865 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2867 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2868 int num_props = obj->GetPropertyNames()->Length();
2869 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2870 v8::Integer::New(isolate, 20)));
2871 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2872 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2874 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2876 // Add another property and delete it afterwards to force the object in
2878 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2879 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2880 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2881 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2882 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2884 CHECK(obj->HasPrivate(priv1));
2885 CHECK(obj->HasPrivate(priv2));
2886 CHECK(obj->DeletePrivate(priv2));
2887 CHECK(obj->HasPrivate(priv1));
2888 CHECK(!obj->HasPrivate(priv2));
2889 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2890 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2892 // Private properties are inherited (for the time being).
2893 v8::Local<v8::Object> child = v8::Object::New(isolate);
2894 child->SetPrototype(obj);
2895 CHECK(child->HasPrivate(priv1));
2896 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2897 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2901 THREADED_TEST(GlobalSymbols) {
2902 i::FLAG_harmony_symbols = true;
2905 v8::Isolate* isolate = env->GetIsolate();
2906 v8::HandleScope scope(isolate);
2908 v8::Local<String> name = v8_str("my-symbol");
2909 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2910 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2911 CHECK(glob2->SameValue(glob));
2913 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2914 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2915 CHECK(glob_api2->SameValue(glob_api));
2916 CHECK(!glob_api->SameValue(glob));
2918 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2919 CHECK(!sym->SameValue(glob));
2921 CompileRun("var sym2 = Symbol.for('my-symbol')");
2922 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2923 CHECK(sym2->SameValue(glob));
2924 CHECK(!sym2->SameValue(glob_api));
2928 THREADED_TEST(GlobalPrivates) {
2930 v8::Isolate* isolate = env->GetIsolate();
2931 v8::HandleScope scope(isolate);
2933 v8::Local<String> name = v8_str("my-private");
2934 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2935 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2936 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2938 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2939 CHECK(obj->HasPrivate(glob2));
2941 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2942 CHECK(!obj->HasPrivate(priv));
2944 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2945 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2946 CHECK(!obj->Has(intern));
2950 class ScopedArrayBufferContents {
2952 explicit ScopedArrayBufferContents(
2953 const v8::ArrayBuffer::Contents& contents)
2954 : contents_(contents) {}
2955 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2956 void* Data() const { return contents_.Data(); }
2957 size_t ByteLength() const { return contents_.ByteLength(); }
2959 const v8::ArrayBuffer::Contents contents_;
2962 template <typename T>
2963 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2964 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2965 for (int i = 0; i < value->InternalFieldCount(); i++) {
2966 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2971 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2973 v8::Isolate* isolate = env->GetIsolate();
2974 v8::HandleScope handle_scope(isolate);
2976 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2977 CheckInternalFieldsAreZero(ab);
2978 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2979 CHECK(!ab->IsExternal());
2980 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2982 ScopedArrayBufferContents ab_contents(ab->Externalize());
2983 CHECK(ab->IsExternal());
2985 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2986 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2987 ASSERT(data != NULL);
2988 env->Global()->Set(v8_str("ab"), ab);
2990 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2991 CHECK_EQ(1024, result->Int32Value());
2993 result = CompileRun("var u8 = new Uint8Array(ab);"
2997 CHECK_EQ(1024, result->Int32Value());
2998 CHECK_EQ(0xFF, data[0]);
2999 CHECK_EQ(0xAA, data[1]);
3002 result = CompileRun("u8[0] + u8[1]");
3003 CHECK_EQ(0xDD, result->Int32Value());
3007 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3009 v8::Isolate* isolate = env->GetIsolate();
3010 v8::HandleScope handle_scope(isolate);
3013 v8::Local<v8::Value> result =
3014 CompileRun("var ab1 = new ArrayBuffer(2);"
3015 "var u8_a = new Uint8Array(ab1);"
3017 "u8_a[1] = 0xFF; u8_a.buffer");
3018 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3019 CheckInternalFieldsAreZero(ab1);
3020 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3021 CHECK(!ab1->IsExternal());
3022 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3023 CHECK(ab1->IsExternal());
3025 result = CompileRun("ab1.byteLength");
3026 CHECK_EQ(2, result->Int32Value());
3027 result = CompileRun("u8_a[0]");
3028 CHECK_EQ(0xAA, result->Int32Value());
3029 result = CompileRun("u8_a[1]");
3030 CHECK_EQ(0xFF, result->Int32Value());
3031 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3034 CHECK_EQ(0xBB, result->Int32Value());
3035 result = CompileRun("u8_b[1]");
3036 CHECK_EQ(0xFF, result->Int32Value());
3038 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3039 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3040 CHECK_EQ(0xBB, ab1_data[0]);
3041 CHECK_EQ(0xFF, ab1_data[1]);
3044 result = CompileRun("u8_a[0] + u8_a[1]");
3045 CHECK_EQ(0xDD, result->Int32Value());
3049 THREADED_TEST(ArrayBuffer_External) {
3051 v8::Isolate* isolate = env->GetIsolate();
3052 v8::HandleScope handle_scope(isolate);
3054 i::ScopedVector<uint8_t> my_data(100);
3055 memset(my_data.start(), 0, 100);
3056 Local<v8::ArrayBuffer> ab3 =
3057 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3058 CheckInternalFieldsAreZero(ab3);
3059 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3060 CHECK(ab3->IsExternal());
3062 env->Global()->Set(v8_str("ab3"), ab3);
3064 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3065 CHECK_EQ(100, result->Int32Value());
3067 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3071 CHECK_EQ(100, result->Int32Value());
3072 CHECK_EQ(0xBB, my_data[0]);
3073 CHECK_EQ(0xCC, my_data[1]);
3076 result = CompileRun("u8_b[0] + u8_b[1]");
3077 CHECK_EQ(0xDD, result->Int32Value());
3081 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3082 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3083 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3087 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3088 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3089 CHECK_EQ(0, static_cast<int>(ta->Length()));
3090 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3094 static void CheckIsTypedArrayVarNeutered(const char* name) {
3095 i::ScopedVector<char> source(1024);
3096 i::OS::SNPrintF(source,
3097 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3099 CHECK(CompileRun(source.start())->IsTrue());
3100 v8::Handle<v8::TypedArray> ta =
3101 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3102 CheckIsNeutered(ta);
3106 template <typename TypedArray, int kElementSize>
3107 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3110 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3111 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3112 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3113 CHECK_EQ(length, static_cast<int>(ta->Length()));
3114 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3119 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3121 v8::Isolate* isolate = env->GetIsolate();
3122 v8::HandleScope handle_scope(isolate);
3124 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3126 v8::Handle<v8::Uint8Array> u8a =
3127 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3128 v8::Handle<v8::Uint8ClampedArray> u8c =
3129 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3130 v8::Handle<v8::Int8Array> i8a =
3131 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3133 v8::Handle<v8::Uint16Array> u16a =
3134 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3135 v8::Handle<v8::Int16Array> i16a =
3136 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3138 v8::Handle<v8::Uint32Array> u32a =
3139 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3140 v8::Handle<v8::Int32Array> i32a =
3141 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3143 v8::Handle<v8::Float32Array> f32a =
3144 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3145 v8::Handle<v8::Float64Array> f64a =
3146 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3148 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3149 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3150 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3151 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3153 ScopedArrayBufferContents contents(buffer->Externalize());
3155 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3156 CheckIsNeutered(u8a);
3157 CheckIsNeutered(u8c);
3158 CheckIsNeutered(i8a);
3159 CheckIsNeutered(u16a);
3160 CheckIsNeutered(i16a);
3161 CheckIsNeutered(u32a);
3162 CheckIsNeutered(i32a);
3163 CheckIsNeutered(f32a);
3164 CheckIsNeutered(f64a);
3165 CheckDataViewIsNeutered(dv);
3169 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3171 v8::Isolate* isolate = env->GetIsolate();
3172 v8::HandleScope handle_scope(isolate);
3175 "var ab = new ArrayBuffer(1024);"
3176 "var u8a = new Uint8Array(ab, 1, 1023);"
3177 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3178 "var i8a = new Int8Array(ab, 1, 1023);"
3179 "var u16a = new Uint16Array(ab, 2, 511);"
3180 "var i16a = new Int16Array(ab, 2, 511);"
3181 "var u32a = new Uint32Array(ab, 4, 255);"
3182 "var i32a = new Int32Array(ab, 4, 255);"
3183 "var f32a = new Float32Array(ab, 4, 255);"
3184 "var f64a = new Float64Array(ab, 8, 127);"
3185 "var dv = new DataView(ab, 1, 1023);");
3187 v8::Handle<v8::ArrayBuffer> ab =
3188 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3190 v8::Handle<v8::DataView> dv =
3191 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3193 ScopedArrayBufferContents contents(ab->Externalize());
3195 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3196 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3198 CheckIsTypedArrayVarNeutered("u8a");
3199 CheckIsTypedArrayVarNeutered("u8c");
3200 CheckIsTypedArrayVarNeutered("i8a");
3201 CheckIsTypedArrayVarNeutered("u16a");
3202 CheckIsTypedArrayVarNeutered("i16a");
3203 CheckIsTypedArrayVarNeutered("u32a");
3204 CheckIsTypedArrayVarNeutered("i32a");
3205 CheckIsTypedArrayVarNeutered("f32a");
3206 CheckIsTypedArrayVarNeutered("f64a");
3208 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3209 CheckDataViewIsNeutered(dv);
3214 THREADED_TEST(HiddenProperties) {
3216 v8::Isolate* isolate = env->GetIsolate();
3217 v8::HandleScope scope(isolate);
3219 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3220 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3221 v8::Local<v8::String> empty = v8_str("");
3222 v8::Local<v8::String> prop_name = v8_str("prop_name");
3224 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3226 // Make sure delete of a non-existent hidden value works
3227 CHECK(obj->DeleteHiddenValue(key));
3229 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3230 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3231 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3232 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3234 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3236 // Make sure we do not find the hidden property.
3237 CHECK(!obj->Has(empty));
3238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239 CHECK(obj->Get(empty)->IsUndefined());
3240 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3242 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3243 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3245 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3247 // Add another property and delete it afterwards to force the object in
3249 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3250 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3251 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3252 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3253 CHECK(obj->Delete(prop_name));
3254 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3256 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3258 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3259 CHECK(obj->GetHiddenValue(key).IsEmpty());
3261 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3262 CHECK(obj->DeleteHiddenValue(key));
3263 CHECK(obj->GetHiddenValue(key).IsEmpty());
3267 THREADED_TEST(Regress97784) {
3268 // Regression test for crbug.com/97784
3269 // Messing with the Object.prototype should not have effect on
3270 // hidden properties.
3272 v8::HandleScope scope(env->GetIsolate());
3274 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3275 v8::Local<v8::String> key = v8_str("hidden");
3278 "set_called = false;"
3279 "Object.defineProperty("
3280 " Object.prototype,"
3282 " {get: function() { return 45; },"
3283 " set: function() { set_called = true; }})");
3285 CHECK(obj->GetHiddenValue(key).IsEmpty());
3286 // Make sure that the getter and setter from Object.prototype is not invoked.
3287 // If it did we would have full access to the hidden properties in
3289 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3290 ExpectFalse("set_called");
3291 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3295 static bool interceptor_for_hidden_properties_called;
3296 static void InterceptorForHiddenProperties(
3297 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3298 interceptor_for_hidden_properties_called = true;
3302 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3303 LocalContext context;
3304 v8::Isolate* isolate = context->GetIsolate();
3305 v8::HandleScope scope(isolate);
3307 interceptor_for_hidden_properties_called = false;
3309 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3311 // Associate an interceptor with an object and start setting hidden values.
3312 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3313 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3314 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3315 Local<v8::Function> function = fun_templ->GetFunction();
3316 Local<v8::Object> obj = function->NewInstance();
3317 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3318 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3319 CHECK(!interceptor_for_hidden_properties_called);
3323 THREADED_TEST(External) {
3324 v8::HandleScope scope(CcTest::isolate());
3326 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3328 env->Global()->Set(v8_str("ext"), ext);
3329 Local<Value> reext_obj = CompileRun("this.ext");
3330 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3331 int* ptr = static_cast<int*>(reext->Value());
3336 // Make sure unaligned pointers are wrapped properly.
3337 char* data = i::StrDup("0123456789");
3338 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3339 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3340 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3341 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3343 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3344 CHECK_EQ('0', *char_ptr);
3345 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3346 CHECK_EQ('1', *char_ptr);
3347 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3348 CHECK_EQ('2', *char_ptr);
3349 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3350 CHECK_EQ('3', *char_ptr);
3351 i::DeleteArray(data);
3355 THREADED_TEST(GlobalHandle) {
3356 v8::Isolate* isolate = CcTest::isolate();
3357 v8::Persistent<String> global;
3359 v8::HandleScope scope(isolate);
3360 global.Reset(isolate, v8_str("str"));
3363 v8::HandleScope scope(isolate);
3364 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3368 v8::HandleScope scope(isolate);
3369 global.Reset(isolate, v8_str("str"));
3372 v8::HandleScope scope(isolate);
3373 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3379 THREADED_TEST(ResettingGlobalHandle) {
3380 v8::Isolate* isolate = CcTest::isolate();
3381 v8::Persistent<String> global;
3383 v8::HandleScope scope(isolate);
3384 global.Reset(isolate, v8_str("str"));
3386 v8::internal::GlobalHandles* global_handles =
3387 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3388 int initial_handle_count = global_handles->global_handles_count();
3390 v8::HandleScope scope(isolate);
3391 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3394 v8::HandleScope scope(isolate);
3395 global.Reset(isolate, v8_str("longer"));
3397 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3399 v8::HandleScope scope(isolate);
3400 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3403 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3407 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3408 v8::Isolate* isolate = CcTest::isolate();
3409 v8::Persistent<String> global;
3411 v8::HandleScope scope(isolate);
3412 global.Reset(isolate, v8_str("str"));
3414 v8::internal::GlobalHandles* global_handles =
3415 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3416 int initial_handle_count = global_handles->global_handles_count();
3418 v8::HandleScope scope(isolate);
3419 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3422 v8::HandleScope scope(isolate);
3423 Local<String> empty;
3424 global.Reset(isolate, empty);
3426 CHECK(global.IsEmpty());
3427 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3432 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3433 return unique.Pass();
3438 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3439 const v8::Persistent<T> & global) {
3440 v8::UniquePersistent<String> unique(isolate, global);
3441 return unique.Pass();
3445 THREADED_TEST(UniquePersistent) {
3446 v8::Isolate* isolate = CcTest::isolate();
3447 v8::Persistent<String> global;
3449 v8::HandleScope scope(isolate);
3450 global.Reset(isolate, v8_str("str"));
3452 v8::internal::GlobalHandles* global_handles =
3453 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3454 int initial_handle_count = global_handles->global_handles_count();
3456 v8::UniquePersistent<String> unique(isolate, global);
3457 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3458 // Test assignment via Pass
3460 v8::UniquePersistent<String> copy = unique.Pass();
3461 CHECK(unique.IsEmpty());
3462 CHECK(copy == global);
3463 CHECK_EQ(initial_handle_count + 1,
3464 global_handles->global_handles_count());
3465 unique = copy.Pass();
3467 // Test ctor via Pass
3469 v8::UniquePersistent<String> copy(unique.Pass());
3470 CHECK(unique.IsEmpty());
3471 CHECK(copy == global);
3472 CHECK_EQ(initial_handle_count + 1,
3473 global_handles->global_handles_count());
3474 unique = copy.Pass();
3476 // Test pass through function call
3478 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3479 CHECK(unique.IsEmpty());
3480 CHECK(copy == global);
3481 CHECK_EQ(initial_handle_count + 1,
3482 global_handles->global_handles_count());
3483 unique = copy.Pass();
3485 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3487 // Test pass from function call
3489 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3490 CHECK(unique == global);
3491 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3493 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3498 template<typename K, typename V>
3499 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3501 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3503 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3504 struct WeakCallbackDataType {
3508 static WeakCallbackDataType* WeakCallbackParameter(
3509 MapType* map, const K& key, Local<V> value) {
3510 WeakCallbackDataType* data = new WeakCallbackDataType;
3515 static MapType* MapFromWeakCallbackData(
3516 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3517 return data.GetParameter()->map;
3519 static K KeyFromWeakCallbackData(
3520 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3521 return data.GetParameter()->key;
3523 static void DisposeCallbackData(WeakCallbackDataType* data) {
3526 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3531 template<typename Map>
3532 static void TestPersistentValueMap() {
3534 v8::Isolate* isolate = env->GetIsolate();
3536 v8::internal::GlobalHandles* global_handles =
3537 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3538 int initial_handle_count = global_handles->global_handles_count();
3539 CHECK_EQ(0, static_cast<int>(map.Size()));
3541 HandleScope scope(isolate);
3542 Local<v8::Object> obj = map.Get(7);
3543 CHECK(obj.IsEmpty());
3544 Local<v8::Object> expected = v8::Object::New(isolate);
3545 map.Set(7, expected);
3546 CHECK_EQ(1, static_cast<int>(map.Size()));
3548 CHECK_EQ(expected, obj);
3550 typename Map::PersistentValueReference ref = map.GetReference(7);
3551 CHECK_EQ(expected, ref.NewLocal(isolate));
3553 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3554 CHECK_EQ(0, static_cast<int>(map.Size()));
3555 CHECK(expected == removed);
3556 removed = map.Remove(7);
3557 CHECK(removed.IsEmpty());
3558 map.Set(8, expected);
3559 CHECK_EQ(1, static_cast<int>(map.Size()));
3560 map.Set(8, expected);
3561 CHECK_EQ(1, static_cast<int>(map.Size()));
3563 typename Map::PersistentValueReference ref;
3564 Local<v8::Object> expected2 = v8::Object::New(isolate);
3565 removed = map.Set(8,
3566 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3567 CHECK_EQ(1, static_cast<int>(map.Size()));
3568 CHECK(expected == removed);
3569 CHECK_EQ(expected2, ref.NewLocal(isolate));
3572 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3574 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3575 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3579 CHECK_EQ(0, static_cast<int>(map.Size()));
3580 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3584 TEST(PersistentValueMap) {
3585 // Default case, w/o weak callbacks:
3586 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3588 // Custom traits with weak callbacks:
3589 typedef v8::PersistentValueMap<int, v8::Object,
3590 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3591 TestPersistentValueMap<WeakPersistentValueMap>();
3595 TEST(PersistentValueVector) {
3597 v8::Isolate* isolate = env->GetIsolate();
3598 v8::internal::GlobalHandles* global_handles =
3599 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3600 int handle_count = global_handles->global_handles_count();
3601 HandleScope scope(isolate);
3603 v8::PersistentValueVector<v8::Object> vector(isolate);
3605 Local<v8::Object> obj1 = v8::Object::New(isolate);
3606 Local<v8::Object> obj2 = v8::Object::New(isolate);
3607 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3609 CHECK(vector.IsEmpty());
3610 CHECK_EQ(0, static_cast<int>(vector.Size()));
3612 vector.ReserveCapacity(3);
3613 CHECK(vector.IsEmpty());
3615 vector.Append(obj1);
3616 vector.Append(obj2);
3617 vector.Append(obj1);
3618 vector.Append(obj3.Pass());
3619 vector.Append(obj1);
3621 CHECK(!vector.IsEmpty());
3622 CHECK_EQ(5, static_cast<int>(vector.Size()));
3623 CHECK(obj3.IsEmpty());
3624 CHECK_EQ(obj1, vector.Get(0));
3625 CHECK_EQ(obj1, vector.Get(2));
3626 CHECK_EQ(obj1, vector.Get(4));
3627 CHECK_EQ(obj2, vector.Get(1));
3629 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3632 CHECK(vector.IsEmpty());
3633 CHECK_EQ(0, static_cast<int>(vector.Size()));
3634 CHECK_EQ(handle_count, global_handles->global_handles_count());
3638 THREADED_TEST(GlobalHandleUpcast) {
3639 v8::Isolate* isolate = CcTest::isolate();
3640 v8::HandleScope scope(isolate);
3641 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3642 v8::Persistent<String> global_string(isolate, local);
3643 v8::Persistent<Value>& global_value =
3644 v8::Persistent<Value>::Cast(global_string);
3645 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3646 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3647 global_string.Reset();
3651 THREADED_TEST(HandleEquality) {
3652 v8::Isolate* isolate = CcTest::isolate();
3653 v8::Persistent<String> global1;
3654 v8::Persistent<String> global2;
3656 v8::HandleScope scope(isolate);
3657 global1.Reset(isolate, v8_str("str"));
3658 global2.Reset(isolate, v8_str("str2"));
3660 CHECK_EQ(global1 == global1, true);
3661 CHECK_EQ(global1 != global1, false);
3663 v8::HandleScope scope(isolate);
3664 Local<String> local1 = Local<String>::New(isolate, global1);
3665 Local<String> local2 = Local<String>::New(isolate, global2);
3667 CHECK_EQ(global1 == local1, true);
3668 CHECK_EQ(global1 != local1, false);
3669 CHECK_EQ(local1 == global1, true);
3670 CHECK_EQ(local1 != global1, false);
3672 CHECK_EQ(global1 == local2, false);
3673 CHECK_EQ(global1 != local2, true);
3674 CHECK_EQ(local2 == global1, false);
3675 CHECK_EQ(local2 != global1, true);
3677 CHECK_EQ(local1 == local2, false);
3678 CHECK_EQ(local1 != local2, true);
3680 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3681 CHECK_EQ(local1 == anotherLocal1, true);
3682 CHECK_EQ(local1 != anotherLocal1, false);
3689 THREADED_TEST(LocalHandle) {
3690 v8::HandleScope scope(CcTest::isolate());
3691 v8::Local<String> local =
3692 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3693 CHECK_EQ(local->Length(), 3);
3697 class WeakCallCounter {
3699 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3700 int id() { return id_; }
3701 void increment() { number_of_weak_calls_++; }
3702 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3705 int number_of_weak_calls_;
3709 template<typename T>
3710 struct WeakCallCounterAndPersistent {
3711 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3712 : counter(counter) {}
3713 WeakCallCounter* counter;
3714 v8::Persistent<T> handle;
3718 template <typename T>
3719 static void WeakPointerCallback(
3720 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3721 CHECK_EQ(1234, data.GetParameter()->counter->id());
3722 data.GetParameter()->counter->increment();
3723 data.GetParameter()->handle.Reset();
3727 template<typename T>
3728 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3729 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3733 THREADED_TEST(ApiObjectGroups) {
3735 v8::Isolate* iso = env->GetIsolate();
3736 HandleScope scope(iso);
3738 WeakCallCounter counter(1234);
3740 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3741 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3742 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3743 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3744 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3745 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3748 HandleScope scope(iso);
3749 g1s1.handle.Reset(iso, Object::New(iso));
3750 g1s2.handle.Reset(iso, Object::New(iso));
3751 g1c1.handle.Reset(iso, Object::New(iso));
3752 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3753 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3754 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3756 g2s1.handle.Reset(iso, Object::New(iso));
3757 g2s2.handle.Reset(iso, Object::New(iso));
3758 g2c1.handle.Reset(iso, Object::New(iso));
3759 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3760 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3761 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3764 WeakCallCounterAndPersistent<Value> root(&counter);
3765 root.handle.Reset(iso, g1s1.handle); // make a root.
3767 // Connect group 1 and 2, make a cycle.
3769 HandleScope scope(iso);
3770 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3771 Set(0, Local<Value>::New(iso, g2s2.handle)));
3772 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3773 Set(0, Local<Value>::New(iso, g1s1.handle)));
3777 UniqueId id1 = MakeUniqueId(g1s1.handle);
3778 UniqueId id2 = MakeUniqueId(g2s2.handle);
3779 iso->SetObjectGroupId(g1s1.handle, id1);
3780 iso->SetObjectGroupId(g1s2.handle, id1);
3781 iso->SetReferenceFromGroup(id1, g1c1.handle);
3782 iso->SetObjectGroupId(g2s1.handle, id2);
3783 iso->SetObjectGroupId(g2s2.handle, id2);
3784 iso->SetReferenceFromGroup(id2, g2c1.handle);
3786 // Do a single full GC, ensure incremental marking is stopped.
3787 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3789 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3791 // All object should be alive.
3792 CHECK_EQ(0, counter.NumberOfWeakCalls());
3795 root.handle.SetWeak(&root, &WeakPointerCallback);
3796 // But make children strong roots---all the objects (except for children)
3797 // should be collectable now.
3798 g1c1.handle.ClearWeak();
3799 g2c1.handle.ClearWeak();
3801 // Groups are deleted, rebuild groups.
3803 UniqueId id1 = MakeUniqueId(g1s1.handle);
3804 UniqueId id2 = MakeUniqueId(g2s2.handle);
3805 iso->SetObjectGroupId(g1s1.handle, id1);
3806 iso->SetObjectGroupId(g1s2.handle, id1);
3807 iso->SetReferenceFromGroup(id1, g1c1.handle);
3808 iso->SetObjectGroupId(g2s1.handle, id2);
3809 iso->SetObjectGroupId(g2s2.handle, id2);
3810 iso->SetReferenceFromGroup(id2, g2c1.handle);
3813 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3815 // All objects should be gone. 5 global handles in total.
3816 CHECK_EQ(5, counter.NumberOfWeakCalls());
3818 // And now make children weak again and collect them.
3819 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3820 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3822 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3823 CHECK_EQ(7, counter.NumberOfWeakCalls());
3827 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3829 v8::Isolate* iso = env->GetIsolate();
3830 HandleScope scope(iso);
3832 WeakCallCounter counter(1234);
3834 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3835 WeakCallCounterAndPersistent<String> g1s2(&counter);
3836 WeakCallCounterAndPersistent<String> g1c1(&counter);
3837 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3838 WeakCallCounterAndPersistent<String> g2s2(&counter);
3839 WeakCallCounterAndPersistent<String> g2c1(&counter);
3842 HandleScope scope(iso);
3843 g1s1.handle.Reset(iso, Object::New(iso));
3844 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3845 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3846 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3847 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3848 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3850 g2s1.handle.Reset(iso, Object::New(iso));
3851 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3852 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3853 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3854 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3855 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3858 WeakCallCounterAndPersistent<Value> root(&counter);
3859 root.handle.Reset(iso, g1s1.handle); // make a root.
3861 // Connect group 1 and 2, make a cycle.
3863 HandleScope scope(iso);
3864 CHECK(Local<Object>::New(iso, g1s1.handle)
3865 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3866 CHECK(Local<Object>::New(iso, g2s1.handle)
3867 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3871 UniqueId id1 = MakeUniqueId(g1s1.handle);
3872 UniqueId id2 = MakeUniqueId(g2s2.handle);
3873 iso->SetObjectGroupId(g1s1.handle, id1);
3874 iso->SetObjectGroupId(g1s2.handle, id1);
3875 iso->SetReference(g1s1.handle, g1c1.handle);
3876 iso->SetObjectGroupId(g2s1.handle, id2);
3877 iso->SetObjectGroupId(g2s2.handle, id2);
3878 iso->SetReferenceFromGroup(id2, g2c1.handle);
3880 // Do a single full GC, ensure incremental marking is stopped.
3881 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3883 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3885 // All object should be alive.
3886 CHECK_EQ(0, counter.NumberOfWeakCalls());
3889 root.handle.SetWeak(&root, &WeakPointerCallback);
3890 // But make children strong roots---all the objects (except for children)
3891 // should be collectable now.
3892 g1c1.handle.ClearWeak();
3893 g2c1.handle.ClearWeak();
3895 // Groups are deleted, rebuild groups.
3897 UniqueId id1 = MakeUniqueId(g1s1.handle);
3898 UniqueId id2 = MakeUniqueId(g2s2.handle);
3899 iso->SetObjectGroupId(g1s1.handle, id1);
3900 iso->SetObjectGroupId(g1s2.handle, id1);
3901 iso->SetReference(g1s1.handle, g1c1.handle);
3902 iso->SetObjectGroupId(g2s1.handle, id2);
3903 iso->SetObjectGroupId(g2s2.handle, id2);
3904 iso->SetReferenceFromGroup(id2, g2c1.handle);
3907 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3909 // All objects should be gone. 5 global handles in total.
3910 CHECK_EQ(5, counter.NumberOfWeakCalls());
3912 // And now make children weak again and collect them.
3913 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3914 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3916 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3917 CHECK_EQ(7, counter.NumberOfWeakCalls());
3921 THREADED_TEST(ApiObjectGroupsCycle) {
3923 v8::Isolate* iso = env->GetIsolate();
3924 HandleScope scope(iso);
3926 WeakCallCounter counter(1234);
3928 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3929 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3930 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3931 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3932 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3933 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3934 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3935 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3938 HandleScope scope(iso);
3939 g1s1.handle.Reset(iso, Object::New(iso));
3940 g1s2.handle.Reset(iso, Object::New(iso));
3941 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3942 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3943 CHECK(g1s1.handle.IsWeak());
3944 CHECK(g1s2.handle.IsWeak());
3946 g2s1.handle.Reset(iso, Object::New(iso));
3947 g2s2.handle.Reset(iso, Object::New(iso));
3948 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3949 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3950 CHECK(g2s1.handle.IsWeak());
3951 CHECK(g2s2.handle.IsWeak());
3953 g3s1.handle.Reset(iso, Object::New(iso));
3954 g3s2.handle.Reset(iso, Object::New(iso));
3955 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3956 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3957 CHECK(g3s1.handle.IsWeak());
3958 CHECK(g3s2.handle.IsWeak());
3960 g4s1.handle.Reset(iso, Object::New(iso));
3961 g4s2.handle.Reset(iso, Object::New(iso));
3962 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3963 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3964 CHECK(g4s1.handle.IsWeak());
3965 CHECK(g4s2.handle.IsWeak());
3968 WeakCallCounterAndPersistent<Value> root(&counter);
3969 root.handle.Reset(iso, g1s1.handle); // make a root.
3971 // Connect groups. We're building the following cycle:
3972 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3975 UniqueId id1 = MakeUniqueId(g1s1.handle);
3976 UniqueId id2 = MakeUniqueId(g2s1.handle);
3977 UniqueId id3 = MakeUniqueId(g3s1.handle);
3978 UniqueId id4 = MakeUniqueId(g4s1.handle);
3979 iso->SetObjectGroupId(g1s1.handle, id1);
3980 iso->SetObjectGroupId(g1s2.handle, id1);
3981 iso->SetReferenceFromGroup(id1, g2s1.handle);
3982 iso->SetObjectGroupId(g2s1.handle, id2);
3983 iso->SetObjectGroupId(g2s2.handle, id2);
3984 iso->SetReferenceFromGroup(id2, g3s1.handle);
3985 iso->SetObjectGroupId(g3s1.handle, id3);
3986 iso->SetObjectGroupId(g3s2.handle, id3);
3987 iso->SetReferenceFromGroup(id3, g4s1.handle);
3988 iso->SetObjectGroupId(g4s1.handle, id4);
3989 iso->SetObjectGroupId(g4s2.handle, id4);
3990 iso->SetReferenceFromGroup(id4, g1s1.handle);
3992 // Do a single full GC
3993 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3995 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3997 // All object should be alive.
3998 CHECK_EQ(0, counter.NumberOfWeakCalls());
4001 root.handle.SetWeak(&root, &WeakPointerCallback);
4003 // Groups are deleted, rebuild groups.
4005 UniqueId id1 = MakeUniqueId(g1s1.handle);
4006 UniqueId id2 = MakeUniqueId(g2s1.handle);
4007 UniqueId id3 = MakeUniqueId(g3s1.handle);
4008 UniqueId id4 = MakeUniqueId(g4s1.handle);
4009 iso->SetObjectGroupId(g1s1.handle, id1);
4010 iso->SetObjectGroupId(g1s2.handle, id1);
4011 iso->SetReferenceFromGroup(id1, g2s1.handle);
4012 iso->SetObjectGroupId(g2s1.handle, id2);
4013 iso->SetObjectGroupId(g2s2.handle, id2);
4014 iso->SetReferenceFromGroup(id2, g3s1.handle);
4015 iso->SetObjectGroupId(g3s1.handle, id3);
4016 iso->SetObjectGroupId(g3s2.handle, id3);
4017 iso->SetReferenceFromGroup(id3, g4s1.handle);
4018 iso->SetObjectGroupId(g4s1.handle, id4);
4019 iso->SetObjectGroupId(g4s2.handle, id4);
4020 iso->SetReferenceFromGroup(id4, g1s1.handle);
4023 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4025 // All objects should be gone. 9 global handles in total.
4026 CHECK_EQ(9, counter.NumberOfWeakCalls());
4030 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4031 // on the buildbots, so was made non-threaded for the time being.
4032 TEST(ApiObjectGroupsCycleForScavenger) {
4033 i::FLAG_stress_compaction = false;
4034 i::FLAG_gc_global = false;
4036 v8::Isolate* iso = env->GetIsolate();
4037 HandleScope scope(iso);
4039 WeakCallCounter counter(1234);
4041 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4042 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4043 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4044 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4045 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4046 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4049 HandleScope scope(iso);
4050 g1s1.handle.Reset(iso, Object::New(iso));
4051 g1s2.handle.Reset(iso, Object::New(iso));
4052 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4053 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4055 g2s1.handle.Reset(iso, Object::New(iso));
4056 g2s2.handle.Reset(iso, Object::New(iso));
4057 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4058 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4060 g3s1.handle.Reset(iso, Object::New(iso));
4061 g3s2.handle.Reset(iso, Object::New(iso));
4062 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4063 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4067 WeakCallCounterAndPersistent<Value> root(&counter);
4068 root.handle.Reset(iso, g1s1.handle);
4069 root.handle.MarkPartiallyDependent();
4071 // Connect groups. We're building the following cycle:
4072 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4075 HandleScope handle_scope(iso);
4076 g1s1.handle.MarkPartiallyDependent();
4077 g1s2.handle.MarkPartiallyDependent();
4078 g2s1.handle.MarkPartiallyDependent();
4079 g2s2.handle.MarkPartiallyDependent();
4080 g3s1.handle.MarkPartiallyDependent();
4081 g3s2.handle.MarkPartiallyDependent();
4082 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4083 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4084 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4085 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4086 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4087 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4088 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4089 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4090 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4091 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4092 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4093 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4096 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4098 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4100 // All objects should be alive.
4101 CHECK_EQ(0, counter.NumberOfWeakCalls());
4104 root.handle.SetWeak(&root, &WeakPointerCallback);
4105 root.handle.MarkPartiallyDependent();
4107 // Groups are deleted, rebuild groups.
4109 HandleScope handle_scope(iso);
4110 g1s1.handle.MarkPartiallyDependent();
4111 g1s2.handle.MarkPartiallyDependent();
4112 g2s1.handle.MarkPartiallyDependent();
4113 g2s2.handle.MarkPartiallyDependent();
4114 g3s1.handle.MarkPartiallyDependent();
4115 g3s2.handle.MarkPartiallyDependent();
4116 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4117 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4118 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4119 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4120 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4121 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4122 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4123 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4124 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4125 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4126 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4127 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4130 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4132 // All objects should be gone. 7 global handles in total.
4133 CHECK_EQ(7, counter.NumberOfWeakCalls());
4137 THREADED_TEST(ScriptException) {
4139 v8::HandleScope scope(env->GetIsolate());
4140 Local<Script> script = v8_compile("throw 'panama!';");
4141 v8::TryCatch try_catch;
4142 Local<Value> result = script->Run();
4143 CHECK(result.IsEmpty());
4144 CHECK(try_catch.HasCaught());
4145 String::Utf8Value exception_value(try_catch.Exception());
4146 CHECK_EQ(*exception_value, "panama!");
4150 TEST(TryCatchCustomException) {
4152 v8::HandleScope scope(env->GetIsolate());
4153 v8::TryCatch try_catch;
4154 CompileRun("function CustomError() { this.a = 'b'; }"
4155 "(function f() { throw new CustomError(); })();");
4156 CHECK(try_catch.HasCaught());
4157 CHECK(try_catch.Exception()->ToObject()->
4158 Get(v8_str("a"))->Equals(v8_str("b")));
4162 bool message_received;
4165 static void check_message_0(v8::Handle<v8::Message> message,
4166 v8::Handle<Value> data) {
4167 CHECK_EQ(5.76, data->NumberValue());
4168 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4169 CHECK(!message->IsSharedCrossOrigin());
4170 message_received = true;
4174 THREADED_TEST(MessageHandler0) {
4175 message_received = false;
4176 v8::HandleScope scope(CcTest::isolate());
4177 CHECK(!message_received);
4178 LocalContext context;
4179 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4180 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4182 CHECK(message_received);
4183 // clear out the message listener
4184 v8::V8::RemoveMessageListeners(check_message_0);
4188 static void check_message_1(v8::Handle<v8::Message> message,
4189 v8::Handle<Value> data) {
4190 CHECK(data->IsNumber());
4191 CHECK_EQ(1337, data->Int32Value());
4192 CHECK(!message->IsSharedCrossOrigin());
4193 message_received = true;
4197 TEST(MessageHandler1) {
4198 message_received = false;
4199 v8::HandleScope scope(CcTest::isolate());
4200 CHECK(!message_received);
4201 v8::V8::AddMessageListener(check_message_1);
4202 LocalContext context;
4203 CompileRun("throw 1337;");
4204 CHECK(message_received);
4205 // clear out the message listener
4206 v8::V8::RemoveMessageListeners(check_message_1);
4210 static void check_message_2(v8::Handle<v8::Message> message,
4211 v8::Handle<Value> data) {
4212 LocalContext context;
4213 CHECK(data->IsObject());
4214 v8::Local<v8::Value> hidden_property =
4215 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4216 CHECK(v8_str("hidden value")->Equals(hidden_property));
4217 CHECK(!message->IsSharedCrossOrigin());
4218 message_received = true;
4222 TEST(MessageHandler2) {
4223 message_received = false;
4224 v8::HandleScope scope(CcTest::isolate());
4225 CHECK(!message_received);
4226 v8::V8::AddMessageListener(check_message_2);
4227 LocalContext context;
4228 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4229 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4230 v8_str("hidden value"));
4231 context->Global()->Set(v8_str("error"), error);
4232 CompileRun("throw error;");
4233 CHECK(message_received);
4234 // clear out the message listener
4235 v8::V8::RemoveMessageListeners(check_message_2);
4239 static void check_message_3(v8::Handle<v8::Message> message,
4240 v8::Handle<Value> data) {
4241 CHECK(message->IsSharedCrossOrigin());
4242 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4243 message_received = true;
4247 TEST(MessageHandler3) {
4248 message_received = false;
4249 v8::Isolate* isolate = CcTest::isolate();
4250 v8::HandleScope scope(isolate);
4251 CHECK(!message_received);
4252 v8::V8::AddMessageListener(check_message_3);
4253 LocalContext context;
4254 v8::ScriptOrigin origin =
4255 v8::ScriptOrigin(v8_str("6.75"),
4256 v8::Integer::New(isolate, 1),
4257 v8::Integer::New(isolate, 2),
4259 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4262 CHECK(message_received);
4263 // clear out the message listener
4264 v8::V8::RemoveMessageListeners(check_message_3);
4268 static void check_message_4(v8::Handle<v8::Message> message,
4269 v8::Handle<Value> data) {
4270 CHECK(!message->IsSharedCrossOrigin());
4271 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4272 message_received = true;
4276 TEST(MessageHandler4) {
4277 message_received = false;
4278 v8::Isolate* isolate = CcTest::isolate();
4279 v8::HandleScope scope(isolate);
4280 CHECK(!message_received);
4281 v8::V8::AddMessageListener(check_message_4);
4282 LocalContext context;
4283 v8::ScriptOrigin origin =
4284 v8::ScriptOrigin(v8_str("6.75"),
4285 v8::Integer::New(isolate, 1),
4286 v8::Integer::New(isolate, 2),
4287 v8::False(isolate));
4288 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4291 CHECK(message_received);
4292 // clear out the message listener
4293 v8::V8::RemoveMessageListeners(check_message_4);
4297 static void check_message_5a(v8::Handle<v8::Message> message,
4298 v8::Handle<Value> data) {
4299 CHECK(message->IsSharedCrossOrigin());
4300 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4301 message_received = true;
4305 static void check_message_5b(v8::Handle<v8::Message> message,
4306 v8::Handle<Value> data) {
4307 CHECK(!message->IsSharedCrossOrigin());
4308 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4309 message_received = true;
4313 TEST(MessageHandler5) {
4314 message_received = false;
4315 v8::Isolate* isolate = CcTest::isolate();
4316 v8::HandleScope scope(isolate);
4317 CHECK(!message_received);
4318 v8::V8::AddMessageListener(check_message_5a);
4319 LocalContext context;
4320 v8::ScriptOrigin origin =
4321 v8::ScriptOrigin(v8_str("6.75"),
4322 v8::Integer::New(isolate, 1),
4323 v8::Integer::New(isolate, 2),
4325 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4328 CHECK(message_received);
4329 // clear out the message listener
4330 v8::V8::RemoveMessageListeners(check_message_5a);
4332 message_received = false;
4333 v8::V8::AddMessageListener(check_message_5b);
4335 v8::ScriptOrigin(v8_str("6.75"),
4336 v8::Integer::New(isolate, 1),
4337 v8::Integer::New(isolate, 2),
4338 v8::False(isolate));
4339 script = Script::Compile(v8_str("throw 'error'"),
4342 CHECK(message_received);
4343 // clear out the message listener
4344 v8::V8::RemoveMessageListeners(check_message_5b);
4348 THREADED_TEST(GetSetProperty) {
4349 LocalContext context;
4350 v8::Isolate* isolate = context->GetIsolate();
4351 v8::HandleScope scope(isolate);
4352 context->Global()->Set(v8_str("foo"), v8_num(14));
4353 context->Global()->Set(v8_str("12"), v8_num(92));
4354 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4355 context->Global()->Set(v8_num(13), v8_num(56));
4356 Local<Value> foo = CompileRun("this.foo");
4357 CHECK_EQ(14, foo->Int32Value());
4358 Local<Value> twelve = CompileRun("this[12]");
4359 CHECK_EQ(92, twelve->Int32Value());
4360 Local<Value> sixteen = CompileRun("this[16]");
4361 CHECK_EQ(32, sixteen->Int32Value());
4362 Local<Value> thirteen = CompileRun("this[13]");
4363 CHECK_EQ(56, thirteen->Int32Value());
4365 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4366 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4367 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4369 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4370 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4371 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4373 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4374 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4375 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4379 THREADED_TEST(PropertyAttributes) {
4380 LocalContext context;
4381 v8::HandleScope scope(context->GetIsolate());
4383 Local<String> prop = v8_str("none");
4384 context->Global()->Set(prop, v8_num(7));
4385 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4387 prop = v8_str("read_only");
4388 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4389 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4390 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4391 CompileRun("read_only = 9");
4392 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4393 context->Global()->Set(prop, v8_num(10));
4394 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4396 prop = v8_str("dont_delete");
4397 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4398 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4399 CompileRun("delete dont_delete");
4400 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4401 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4403 prop = v8_str("dont_enum");
4404 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4405 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4407 prop = v8_str("absent");
4408 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4409 Local<Value> fake_prop = v8_num(1);
4410 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4413 Local<Value> exception =
4414 CompileRun("({ toString: function() { throw 'exception';} })");
4415 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4416 CHECK(try_catch.HasCaught());
4417 String::Utf8Value exception_value(try_catch.Exception());
4418 CHECK_EQ("exception", *exception_value);
4423 THREADED_TEST(Array) {
4424 LocalContext context;
4425 v8::HandleScope scope(context->GetIsolate());
4426 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4427 CHECK_EQ(0, array->Length());
4428 CHECK(array->Get(0)->IsUndefined());
4429 CHECK(!array->Has(0));
4430 CHECK(array->Get(100)->IsUndefined());
4431 CHECK(!array->Has(100));
4432 array->Set(2, v8_num(7));
4433 CHECK_EQ(3, array->Length());
4434 CHECK(!array->Has(0));
4435 CHECK(!array->Has(1));
4436 CHECK(array->Has(2));
4437 CHECK_EQ(7, array->Get(2)->Int32Value());
4438 Local<Value> obj = CompileRun("[1, 2, 3]");
4439 Local<v8::Array> arr = obj.As<v8::Array>();
4440 CHECK_EQ(3, arr->Length());
4441 CHECK_EQ(1, arr->Get(0)->Int32Value());
4442 CHECK_EQ(2, arr->Get(1)->Int32Value());
4443 CHECK_EQ(3, arr->Get(2)->Int32Value());
4444 array = v8::Array::New(context->GetIsolate(), 27);
4445 CHECK_EQ(27, array->Length());
4446 array = v8::Array::New(context->GetIsolate(), -27);
4447 CHECK_EQ(0, array->Length());
4451 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4452 v8::EscapableHandleScope scope(args.GetIsolate());
4453 ApiTestFuzzer::Fuzz();
4454 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4455 for (int i = 0; i < args.Length(); i++)
4456 result->Set(i, args[i]);
4457 args.GetReturnValue().Set(scope.Escape(result));
4461 THREADED_TEST(Vector) {
4462 v8::Isolate* isolate = CcTest::isolate();
4463 v8::HandleScope scope(isolate);
4464 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4465 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4466 LocalContext context(0, global);
4468 const char* fun = "f()";
4469 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4470 CHECK_EQ(0, a0->Length());
4472 const char* fun2 = "f(11)";
4473 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4474 CHECK_EQ(1, a1->Length());
4475 CHECK_EQ(11, a1->Get(0)->Int32Value());
4477 const char* fun3 = "f(12, 13)";
4478 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4479 CHECK_EQ(2, a2->Length());
4480 CHECK_EQ(12, a2->Get(0)->Int32Value());
4481 CHECK_EQ(13, a2->Get(1)->Int32Value());
4483 const char* fun4 = "f(14, 15, 16)";
4484 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4485 CHECK_EQ(3, a3->Length());
4486 CHECK_EQ(14, a3->Get(0)->Int32Value());
4487 CHECK_EQ(15, a3->Get(1)->Int32Value());
4488 CHECK_EQ(16, a3->Get(2)->Int32Value());
4490 const char* fun5 = "f(17, 18, 19, 20)";
4491 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4492 CHECK_EQ(4, a4->Length());
4493 CHECK_EQ(17, a4->Get(0)->Int32Value());
4494 CHECK_EQ(18, a4->Get(1)->Int32Value());
4495 CHECK_EQ(19, a4->Get(2)->Int32Value());
4496 CHECK_EQ(20, a4->Get(3)->Int32Value());
4500 THREADED_TEST(FunctionCall) {
4501 LocalContext context;
4502 v8::Isolate* isolate = context->GetIsolate();
4503 v8::HandleScope scope(isolate);
4507 " for (var i = 0; i < arguments.length; i++) {"
4508 " result.push(arguments[i]);"
4512 "function ReturnThisSloppy() {"
4515 "function ReturnThisStrict() {"
4519 Local<Function> Foo =
4520 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4521 Local<Function> ReturnThisSloppy =
4522 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4523 Local<Function> ReturnThisStrict =
4524 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4526 v8::Handle<Value>* args0 = NULL;
4527 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4528 CHECK_EQ(0, a0->Length());
4530 v8::Handle<Value> args1[] = { v8_num(1.1) };
4531 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4532 CHECK_EQ(1, a1->Length());
4533 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4535 v8::Handle<Value> args2[] = { v8_num(2.2),
4537 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4538 CHECK_EQ(2, a2->Length());
4539 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4540 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4542 v8::Handle<Value> args3[] = { v8_num(4.4),
4545 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4546 CHECK_EQ(3, a3->Length());
4547 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4548 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4549 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4551 v8::Handle<Value> args4[] = { v8_num(7.7),
4555 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4556 CHECK_EQ(4, a4->Length());
4557 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4558 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4559 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4560 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4562 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4563 CHECK(r1->StrictEquals(context->Global()));
4564 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4565 CHECK(r2->StrictEquals(context->Global()));
4566 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4567 CHECK(r3->IsNumberObject());
4568 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4569 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4570 CHECK(r4->IsStringObject());
4571 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4572 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4573 CHECK(r5->IsBooleanObject());
4574 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4576 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4577 CHECK(r6->IsUndefined());
4578 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4579 CHECK(r7->IsNull());
4580 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4581 CHECK(r8->StrictEquals(v8_num(42)));
4582 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4583 CHECK(r9->StrictEquals(v8_str("hello")));
4584 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4585 CHECK(r10->StrictEquals(v8::True(isolate)));
4589 THREADED_TEST(ConstructCall) {
4590 LocalContext context;
4591 v8::Isolate* isolate = context->GetIsolate();
4592 v8::HandleScope scope(isolate);
4596 " for (var i = 0; i < arguments.length; i++) {"
4597 " result.push(arguments[i]);"
4601 Local<Function> Foo =
4602 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4604 v8::Handle<Value>* args0 = NULL;
4605 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4606 CHECK_EQ(0, a0->Length());
4608 v8::Handle<Value> args1[] = { v8_num(1.1) };
4609 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4610 CHECK_EQ(1, a1->Length());
4611 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4613 v8::Handle<Value> args2[] = { v8_num(2.2),
4615 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4616 CHECK_EQ(2, a2->Length());
4617 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4618 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4620 v8::Handle<Value> args3[] = { v8_num(4.4),
4623 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4624 CHECK_EQ(3, a3->Length());
4625 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4626 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4627 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4629 v8::Handle<Value> args4[] = { v8_num(7.7),
4633 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4634 CHECK_EQ(4, a4->Length());
4635 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4636 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4637 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4638 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4642 static void CheckUncle(v8::TryCatch* try_catch) {
4643 CHECK(try_catch->HasCaught());
4644 String::Utf8Value str_value(try_catch->Exception());
4645 CHECK_EQ(*str_value, "uncle?");
4650 THREADED_TEST(ConversionNumber) {
4652 v8::HandleScope scope(env->GetIsolate());
4653 // Very large number.
4654 CompileRun("var obj = Math.pow(2,32) * 1237;");
4655 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4656 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4657 CHECK_EQ(0, obj->ToInt32()->Value());
4658 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4660 CompileRun("var obj = -1234567890123;");
4661 obj = env->Global()->Get(v8_str("obj"));
4662 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4663 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4664 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4665 // Small positive integer.
4666 CompileRun("var obj = 42;");
4667 obj = env->Global()->Get(v8_str("obj"));
4668 CHECK_EQ(42.0, obj->ToNumber()->Value());
4669 CHECK_EQ(42, obj->ToInt32()->Value());
4670 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4671 // Negative integer.
4672 CompileRun("var obj = -37;");
4673 obj = env->Global()->Get(v8_str("obj"));
4674 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4675 CHECK_EQ(-37, obj->ToInt32()->Value());
4676 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4677 // Positive non-int32 integer.
4678 CompileRun("var obj = 0x81234567;");
4679 obj = env->Global()->Get(v8_str("obj"));
4680 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4681 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4682 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4684 CompileRun("var obj = 42.3;");
4685 obj = env->Global()->Get(v8_str("obj"));
4686 CHECK_EQ(42.3, obj->ToNumber()->Value());
4687 CHECK_EQ(42, obj->ToInt32()->Value());
4688 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4689 // Large negative fraction.
4690 CompileRun("var obj = -5726623061.75;");
4691 obj = env->Global()->Get(v8_str("obj"));
4692 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4693 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4694 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4698 THREADED_TEST(isNumberType) {
4700 v8::HandleScope scope(env->GetIsolate());
4701 // Very large number.
4702 CompileRun("var obj = Math.pow(2,32) * 1237;");
4703 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4704 CHECK(!obj->IsInt32());
4705 CHECK(!obj->IsUint32());
4706 // Large negative number.
4707 CompileRun("var obj = -1234567890123;");
4708 obj = env->Global()->Get(v8_str("obj"));
4709 CHECK(!obj->IsInt32());
4710 CHECK(!obj->IsUint32());
4711 // Small positive integer.
4712 CompileRun("var obj = 42;");
4713 obj = env->Global()->Get(v8_str("obj"));
4714 CHECK(obj->IsInt32());
4715 CHECK(obj->IsUint32());
4716 // Negative integer.
4717 CompileRun("var obj = -37;");
4718 obj = env->Global()->Get(v8_str("obj"));
4719 CHECK(obj->IsInt32());
4720 CHECK(!obj->IsUint32());
4721 // Positive non-int32 integer.
4722 CompileRun("var obj = 0x81234567;");
4723 obj = env->Global()->Get(v8_str("obj"));
4724 CHECK(!obj->IsInt32());
4725 CHECK(obj->IsUint32());
4727 CompileRun("var obj = 42.3;");
4728 obj = env->Global()->Get(v8_str("obj"));
4729 CHECK(!obj->IsInt32());
4730 CHECK(!obj->IsUint32());
4731 // Large negative fraction.
4732 CompileRun("var obj = -5726623061.75;");
4733 obj = env->Global()->Get(v8_str("obj"));
4734 CHECK(!obj->IsInt32());
4735 CHECK(!obj->IsUint32());
4737 CompileRun("var obj = 0.0;");
4738 obj = env->Global()->Get(v8_str("obj"));
4739 CHECK(obj->IsInt32());
4740 CHECK(obj->IsUint32());
4742 CompileRun("var obj = -0.0;");
4743 obj = env->Global()->Get(v8_str("obj"));
4744 CHECK(!obj->IsInt32());
4745 CHECK(!obj->IsUint32());
4749 THREADED_TEST(ConversionException) {
4751 v8::Isolate* isolate = env->GetIsolate();
4752 v8::HandleScope scope(isolate);
4754 "function TestClass() { };"
4755 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4756 "var obj = new TestClass();");
4757 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4759 v8::TryCatch try_catch;
4761 Local<Value> to_string_result = obj->ToString();
4762 CHECK(to_string_result.IsEmpty());
4763 CheckUncle(&try_catch);
4765 Local<Value> to_number_result = obj->ToNumber();
4766 CHECK(to_number_result.IsEmpty());
4767 CheckUncle(&try_catch);
4769 Local<Value> to_integer_result = obj->ToInteger();
4770 CHECK(to_integer_result.IsEmpty());
4771 CheckUncle(&try_catch);
4773 Local<Value> to_uint32_result = obj->ToUint32();
4774 CHECK(to_uint32_result.IsEmpty());
4775 CheckUncle(&try_catch);
4777 Local<Value> to_int32_result = obj->ToInt32();
4778 CHECK(to_int32_result.IsEmpty());
4779 CheckUncle(&try_catch);
4781 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4782 CHECK(to_object_result.IsEmpty());
4783 CHECK(try_catch.HasCaught());
4786 int32_t int32_value = obj->Int32Value();
4787 CHECK_EQ(0, int32_value);
4788 CheckUncle(&try_catch);
4790 uint32_t uint32_value = obj->Uint32Value();
4791 CHECK_EQ(0, uint32_value);
4792 CheckUncle(&try_catch);
4794 double number_value = obj->NumberValue();
4795 CHECK_NE(0, std::isnan(number_value));
4796 CheckUncle(&try_catch);
4798 int64_t integer_value = obj->IntegerValue();
4799 CHECK_EQ(0.0, static_cast<double>(integer_value));
4800 CheckUncle(&try_catch);
4804 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4805 ApiTestFuzzer::Fuzz();
4806 args.GetIsolate()->ThrowException(v8_str("konto"));
4810 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4811 if (args.Length() < 1) {
4812 args.GetReturnValue().Set(false);
4815 v8::HandleScope scope(args.GetIsolate());
4816 v8::TryCatch try_catch;
4817 Local<Value> result = CompileRun(args[0]->ToString());
4818 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4819 args.GetReturnValue().Set(try_catch.HasCaught());
4823 THREADED_TEST(APICatch) {
4824 v8::Isolate* isolate = CcTest::isolate();
4825 v8::HandleScope scope(isolate);
4826 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4827 templ->Set(v8_str("ThrowFromC"),
4828 v8::FunctionTemplate::New(isolate, ThrowFromC));
4829 LocalContext context(0, templ);
4831 "var thrown = false;"
4837 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4838 CHECK(thrown->BooleanValue());
4842 THREADED_TEST(APIThrowTryCatch) {
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);
4849 v8::TryCatch try_catch;
4850 CompileRun("ThrowFromC();");
4851 CHECK(try_catch.HasCaught());
4855 // Test that a try-finally block doesn't shadow a try-catch block
4856 // when setting up an external handler.
4858 // BUG(271): Some of the exception propagation does not work on the
4859 // ARM simulator because the simulator separates the C++ stack and the
4860 // JS stack. This test therefore fails on the simulator. The test is
4861 // not threaded to allow the threading tests to run on the simulator.
4862 TEST(TryCatchInTryFinally) {
4863 v8::Isolate* isolate = CcTest::isolate();
4864 v8::HandleScope scope(isolate);
4865 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4866 templ->Set(v8_str("CCatcher"),
4867 v8::FunctionTemplate::New(isolate, CCatcher));
4868 LocalContext context(0, templ);
4869 Local<Value> result = CompileRun("try {"
4871 " CCatcher('throw 7;');"
4876 CHECK(result->IsTrue());
4880 static void check_reference_error_message(
4881 v8::Handle<v8::Message> message,
4882 v8::Handle<v8::Value> data) {
4883 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4884 CHECK(message->Get()->Equals(v8_str(reference_error)));
4888 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4889 ApiTestFuzzer::Fuzz();
4894 // Test that overwritten methods are not invoked on uncaught exception
4895 // formatting. However, they are invoked when performing normal error
4896 // string conversions.
4897 TEST(APIThrowMessageOverwrittenToString) {
4898 v8::Isolate* isolate = CcTest::isolate();
4899 v8::HandleScope scope(isolate);
4900 v8::V8::AddMessageListener(check_reference_error_message);
4901 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4902 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4903 LocalContext context(NULL, templ);
4904 CompileRun("asdf;");
4905 CompileRun("var limit = {};"
4906 "limit.valueOf = fail;"
4907 "Error.stackTraceLimit = limit;");
4909 CompileRun("Array.prototype.pop = fail;");
4910 CompileRun("Object.prototype.hasOwnProperty = fail;");
4911 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4912 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4913 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4914 CompileRun("ReferenceError.prototype.toString ="
4915 " function() { return 'Whoops' }");
4916 CompileRun("asdf;");
4917 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4918 CompileRun("asdf;");
4919 CompileRun("ReferenceError.prototype.constructor = void 0;");
4920 CompileRun("asdf;");
4921 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4922 CompileRun("asdf;");
4923 CompileRun("ReferenceError.prototype = new Object();");
4924 CompileRun("asdf;");
4925 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4926 CHECK(string->Equals(v8_str("Whoops")));
4927 CompileRun("ReferenceError.prototype.constructor = new Object();"
4928 "ReferenceError.prototype.constructor.name = 1;"
4929 "Number.prototype.toString = function() { return 'Whoops'; };"
4930 "ReferenceError.prototype.toString = Object.prototype.toString;");
4931 CompileRun("asdf;");
4932 v8::V8::RemoveMessageListeners(check_reference_error_message);
4936 static void check_custom_error_tostring(
4937 v8::Handle<v8::Message> message,
4938 v8::Handle<v8::Value> data) {
4939 const char* uncaught_error = "Uncaught MyError toString";
4940 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4944 TEST(CustomErrorToString) {
4945 LocalContext context;
4946 v8::HandleScope scope(context->GetIsolate());
4947 v8::V8::AddMessageListener(check_custom_error_tostring);
4949 "function MyError(name, message) { "
4950 " this.name = name; "
4951 " this.message = message; "
4953 "MyError.prototype = Object.create(Error.prototype); "
4954 "MyError.prototype.toString = function() { "
4955 " return 'MyError toString'; "
4957 "throw new MyError('my name', 'my message'); ");
4958 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4962 static void check_custom_error_message(
4963 v8::Handle<v8::Message> message,
4964 v8::Handle<v8::Value> data) {
4965 const char* uncaught_error = "Uncaught MyError: my message";
4966 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4967 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4971 TEST(CustomErrorMessage) {
4972 LocalContext context;
4973 v8::HandleScope scope(context->GetIsolate());
4974 v8::V8::AddMessageListener(check_custom_error_message);
4978 "function MyError(msg) { "
4979 " this.name = 'MyError'; "
4980 " this.message = msg; "
4982 "MyError.prototype = new Error(); "
4983 "throw new MyError('my message'); ");
4987 "function MyError(msg) { "
4988 " this.name = 'MyError'; "
4989 " this.message = msg; "
4991 "inherits = function(childCtor, parentCtor) { "
4992 " function tempCtor() {}; "
4993 " tempCtor.prototype = parentCtor.prototype; "
4994 " childCtor.superClass_ = parentCtor.prototype; "
4995 " childCtor.prototype = new tempCtor(); "
4996 " childCtor.prototype.constructor = childCtor; "
4998 "inherits(MyError, Error); "
4999 "throw new MyError('my message'); ");
5003 "function MyError(msg) { "
5004 " this.name = 'MyError'; "
5005 " this.message = msg; "
5007 "MyError.prototype = Object.create(Error.prototype); "
5008 "throw new MyError('my message'); ");
5010 v8::V8::RemoveMessageListeners(check_custom_error_message);
5014 static void receive_message(v8::Handle<v8::Message> message,
5015 v8::Handle<v8::Value> data) {
5017 message_received = true;
5021 TEST(APIThrowMessage) {
5022 message_received = false;
5023 v8::Isolate* isolate = CcTest::isolate();
5024 v8::HandleScope scope(isolate);
5025 v8::V8::AddMessageListener(receive_message);
5026 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5027 templ->Set(v8_str("ThrowFromC"),
5028 v8::FunctionTemplate::New(isolate, ThrowFromC));
5029 LocalContext context(0, templ);
5030 CompileRun("ThrowFromC();");
5031 CHECK(message_received);
5032 v8::V8::RemoveMessageListeners(receive_message);
5036 TEST(APIThrowMessageAndVerboseTryCatch) {
5037 message_received = false;
5038 v8::Isolate* isolate = CcTest::isolate();
5039 v8::HandleScope scope(isolate);
5040 v8::V8::AddMessageListener(receive_message);
5041 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5042 templ->Set(v8_str("ThrowFromC"),
5043 v8::FunctionTemplate::New(isolate, ThrowFromC));
5044 LocalContext context(0, templ);
5045 v8::TryCatch try_catch;
5046 try_catch.SetVerbose(true);
5047 Local<Value> result = CompileRun("ThrowFromC();");
5048 CHECK(try_catch.HasCaught());
5049 CHECK(result.IsEmpty());
5050 CHECK(message_received);
5051 v8::V8::RemoveMessageListeners(receive_message);
5055 TEST(APIStackOverflowAndVerboseTryCatch) {
5056 message_received = false;
5057 LocalContext context;
5058 v8::HandleScope scope(context->GetIsolate());
5059 v8::V8::AddMessageListener(receive_message);
5060 v8::TryCatch try_catch;
5061 try_catch.SetVerbose(true);
5062 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5063 CHECK(try_catch.HasCaught());
5064 CHECK(result.IsEmpty());
5065 CHECK(message_received);
5066 v8::V8::RemoveMessageListeners(receive_message);
5070 THREADED_TEST(ExternalScriptException) {
5071 v8::Isolate* isolate = CcTest::isolate();
5072 v8::HandleScope scope(isolate);
5073 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5074 templ->Set(v8_str("ThrowFromC"),
5075 v8::FunctionTemplate::New(isolate, ThrowFromC));
5076 LocalContext context(0, templ);
5078 v8::TryCatch try_catch;
5079 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5080 CHECK(result.IsEmpty());
5081 CHECK(try_catch.HasCaught());
5082 String::Utf8Value exception_value(try_catch.Exception());
5083 CHECK_EQ("konto", *exception_value);
5088 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5089 ApiTestFuzzer::Fuzz();
5090 CHECK_EQ(4, args.Length());
5091 int count = args[0]->Int32Value();
5092 int cInterval = args[2]->Int32Value();
5094 args.GetIsolate()->ThrowException(v8_str("FromC"));
5097 Local<v8::Object> global =
5098 args.GetIsolate()->GetCurrentContext()->Global();
5099 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5100 v8::Handle<Value> argv[] = { v8_num(count - 1),
5104 if (count % cInterval == 0) {
5105 v8::TryCatch try_catch;
5106 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5107 int expected = args[3]->Int32Value();
5108 if (try_catch.HasCaught()) {
5109 CHECK_EQ(expected, count);
5110 CHECK(result.IsEmpty());
5111 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5113 CHECK_NE(expected, count);
5115 args.GetReturnValue().Set(result);
5118 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5125 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5126 ApiTestFuzzer::Fuzz();
5127 CHECK_EQ(3, args.Length());
5128 bool equality = args[0]->BooleanValue();
5129 int count = args[1]->Int32Value();
5130 int expected = args[2]->Int32Value();
5132 CHECK_EQ(count, expected);
5134 CHECK_NE(count, expected);
5139 THREADED_TEST(EvalInTryFinally) {
5140 LocalContext context;
5141 v8::HandleScope scope(context->GetIsolate());
5142 v8::TryCatch try_catch;
5143 CompileRun("(function() {"
5145 " eval('asldkf (*&^&*^');"
5150 CHECK(!try_catch.HasCaught());
5154 // This test works by making a stack of alternating JavaScript and C
5155 // activations. These activations set up exception handlers with regular
5156 // intervals, one interval for C activations and another for JavaScript
5157 // activations. When enough activations have been created an exception is
5158 // thrown and we check that the right activation catches the exception and that
5159 // no other activations do. The right activation is always the topmost one with
5160 // a handler, regardless of whether it is in JavaScript or C.
5162 // The notation used to describe a test case looks like this:
5164 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5166 // Each entry is an activation, either JS or C. The index is the count at that
5167 // level. Stars identify activations with exception handlers, the @ identifies
5168 // the exception handler that should catch the exception.
5170 // BUG(271): Some of the exception propagation does not work on the
5171 // ARM simulator because the simulator separates the C++ stack and the
5172 // JS stack. This test therefore fails on the simulator. The test is
5173 // not threaded to allow the threading tests to run on the simulator.
5174 TEST(ExceptionOrder) {
5175 v8::Isolate* isolate = CcTest::isolate();
5176 v8::HandleScope scope(isolate);
5177 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5178 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5179 templ->Set(v8_str("CThrowCountDown"),
5180 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5181 LocalContext context(0, templ);
5183 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5184 " if (count == 0) throw 'FromJS';"
5185 " if (count % jsInterval == 0) {"
5187 " var value = CThrowCountDown(count - 1,"
5191 " check(false, count, expected);"
5194 " check(true, count, expected);"
5197 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5200 Local<Function> fun =
5201 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5204 // count jsInterval cInterval expected
5206 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5207 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5208 fun->Call(fun, argc, a0);
5210 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5211 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5212 fun->Call(fun, argc, a1);
5214 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5215 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5216 fun->Call(fun, argc, a2);
5218 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5219 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5220 fun->Call(fun, argc, a3);
5222 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5223 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5224 fun->Call(fun, argc, a4);
5226 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5227 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5228 fun->Call(fun, argc, a5);
5232 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5233 ApiTestFuzzer::Fuzz();
5234 CHECK_EQ(1, args.Length());
5235 args.GetIsolate()->ThrowException(args[0]);
5239 THREADED_TEST(ThrowValues) {
5240 v8::Isolate* isolate = CcTest::isolate();
5241 v8::HandleScope scope(isolate);
5242 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5243 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5244 LocalContext context(0, templ);
5245 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5246 "function Run(obj) {"
5252 " return 'no exception';"
5254 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5255 CHECK_EQ(5, result->Length());
5256 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5257 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5258 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5259 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5260 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5261 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5262 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5266 THREADED_TEST(CatchZero) {
5267 LocalContext context;
5268 v8::HandleScope scope(context->GetIsolate());
5269 v8::TryCatch try_catch;
5270 CHECK(!try_catch.HasCaught());
5271 CompileRun("throw 10");
5272 CHECK(try_catch.HasCaught());
5273 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5275 CHECK(!try_catch.HasCaught());
5276 CompileRun("throw 0");
5277 CHECK(try_catch.HasCaught());
5278 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5282 THREADED_TEST(CatchExceptionFromWith) {
5283 LocalContext context;
5284 v8::HandleScope scope(context->GetIsolate());
5285 v8::TryCatch try_catch;
5286 CHECK(!try_catch.HasCaught());
5287 CompileRun("var o = {}; with (o) { throw 42; }");
5288 CHECK(try_catch.HasCaught());
5292 THREADED_TEST(TryCatchAndFinallyHidingException) {
5293 LocalContext context;
5294 v8::HandleScope scope(context->GetIsolate());
5295 v8::TryCatch try_catch;
5296 CHECK(!try_catch.HasCaught());
5297 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5298 CompileRun("f({toString: function() { throw 42; }});");
5299 CHECK(!try_catch.HasCaught());
5303 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5304 v8::TryCatch try_catch;
5308 THREADED_TEST(TryCatchAndFinally) {
5309 LocalContext context;
5310 v8::Isolate* isolate = context->GetIsolate();
5311 v8::HandleScope scope(isolate);
5312 context->Global()->Set(
5313 v8_str("native_with_try_catch"),
5314 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5315 v8::TryCatch try_catch;
5316 CHECK(!try_catch.HasCaught());
5319 " throw new Error('a');\n"
5321 " native_with_try_catch();\n"
5323 CHECK(try_catch.HasCaught());
5327 static void TryCatchNestedHelper(int depth) {
5329 v8::TryCatch try_catch;
5330 try_catch.SetVerbose(true);
5331 TryCatchNestedHelper(depth - 1);
5332 CHECK(try_catch.HasCaught());
5333 try_catch.ReThrow();
5335 CcTest::isolate()->ThrowException(v8_str("back"));
5340 TEST(TryCatchNested) {
5341 v8::V8::Initialize();
5342 LocalContext context;
5343 v8::HandleScope scope(context->GetIsolate());
5344 v8::TryCatch try_catch;
5345 TryCatchNestedHelper(5);
5346 CHECK(try_catch.HasCaught());
5347 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5351 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5352 CHECK(try_catch->HasCaught());
5353 Handle<Message> message = try_catch->Message();
5354 Handle<Value> resource = message->GetScriptResourceName();
5355 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5356 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5357 "Uncaught Error: a"));
5358 CHECK_EQ(1, message->GetLineNumber());
5359 CHECK_EQ(6, message->GetStartColumn());
5363 void TryCatchMixedNestingHelper(
5364 const v8::FunctionCallbackInfo<v8::Value>& args) {
5365 ApiTestFuzzer::Fuzz();
5366 v8::TryCatch try_catch;
5367 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5368 CHECK(try_catch.HasCaught());
5369 TryCatchMixedNestingCheck(&try_catch);
5370 try_catch.ReThrow();
5374 // This test ensures that an outer TryCatch in the following situation:
5375 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5376 // does not clobber the Message object generated for the inner TryCatch.
5377 // This exercises the ability of TryCatch.ReThrow() to restore the
5378 // inner pending Message before throwing the exception again.
5379 TEST(TryCatchMixedNesting) {
5380 v8::Isolate* isolate = CcTest::isolate();
5381 v8::HandleScope scope(isolate);
5382 v8::V8::Initialize();
5383 v8::TryCatch try_catch;
5384 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5385 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5386 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5387 LocalContext context(0, templ);
5388 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5389 TryCatchMixedNestingCheck(&try_catch);
5393 THREADED_TEST(Equality) {
5394 LocalContext context;
5395 v8::Isolate* isolate = context->GetIsolate();
5396 v8::HandleScope scope(context->GetIsolate());
5397 // Check that equality works at all before relying on CHECK_EQ
5398 CHECK(v8_str("a")->Equals(v8_str("a")));
5399 CHECK(!v8_str("a")->Equals(v8_str("b")));
5401 CHECK_EQ(v8_str("a"), v8_str("a"));
5402 CHECK_NE(v8_str("a"), v8_str("b"));
5403 CHECK_EQ(v8_num(1), v8_num(1));
5404 CHECK_EQ(v8_num(1.00), v8_num(1));
5405 CHECK_NE(v8_num(1), v8_num(2));
5407 // Assume String is not internalized.
5408 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5409 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5410 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5411 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5412 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5413 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5414 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5415 CHECK(!not_a_number->StrictEquals(not_a_number));
5416 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5417 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5419 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5420 v8::Persistent<v8::Object> alias(isolate, obj);
5421 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5424 CHECK(v8_str("a")->SameValue(v8_str("a")));
5425 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5426 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5427 CHECK(v8_num(1)->SameValue(v8_num(1)));
5428 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5429 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5430 CHECK(not_a_number->SameValue(not_a_number));
5431 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5432 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5436 THREADED_TEST(MultiRun) {
5437 LocalContext context;
5438 v8::HandleScope scope(context->GetIsolate());
5439 Local<Script> script = v8_compile("x");
5440 for (int i = 0; i < 10; i++)
5445 static void GetXValue(Local<String> name,
5446 const v8::PropertyCallbackInfo<v8::Value>& info) {
5447 ApiTestFuzzer::Fuzz();
5448 CHECK_EQ(info.Data(), v8_str("donut"));
5449 CHECK_EQ(name, v8_str("x"));
5450 info.GetReturnValue().Set(name);
5454 THREADED_TEST(SimplePropertyRead) {
5455 LocalContext context;
5456 v8::Isolate* isolate = context->GetIsolate();
5457 v8::HandleScope scope(isolate);
5458 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5459 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5460 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5461 Local<Script> script = v8_compile("obj.x");
5462 for (int i = 0; i < 10; i++) {
5463 Local<Value> result = script->Run();
5464 CHECK_EQ(result, v8_str("x"));
5469 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5470 LocalContext context;
5471 v8::Isolate* isolate = context->GetIsolate();
5472 v8::HandleScope scope(isolate);
5473 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5474 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5475 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5477 // Uses getOwnPropertyDescriptor to check the configurable status
5478 Local<Script> script_desc = v8_compile(
5479 "var prop = Object.getOwnPropertyDescriptor( "
5481 "prop.configurable;");
5482 Local<Value> result = script_desc->Run();
5483 CHECK_EQ(result->BooleanValue(), true);
5485 // Redefine get - but still configurable
5486 Local<Script> script_define = v8_compile(
5487 "var desc = { get: function(){return 42; },"
5488 " configurable: true };"
5489 "Object.defineProperty(obj, 'x', desc);"
5491 result = script_define->Run();
5492 CHECK_EQ(result, v8_num(42));
5494 // Check that the accessor is still configurable
5495 result = script_desc->Run();
5496 CHECK_EQ(result->BooleanValue(), true);
5498 // Redefine to a non-configurable
5499 script_define = v8_compile(
5500 "var desc = { get: function(){return 43; },"
5501 " configurable: false };"
5502 "Object.defineProperty(obj, 'x', desc);"
5504 result = script_define->Run();
5505 CHECK_EQ(result, v8_num(43));
5506 result = script_desc->Run();
5507 CHECK_EQ(result->BooleanValue(), false);
5509 // Make sure that it is not possible to redefine again
5510 v8::TryCatch try_catch;
5511 result = script_define->Run();
5512 CHECK(try_catch.HasCaught());
5513 String::Utf8Value exception_value(try_catch.Exception());
5514 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5518 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5519 v8::Isolate* isolate = CcTest::isolate();
5520 v8::HandleScope scope(isolate);
5521 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5522 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5523 LocalContext context;
5524 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5526 Local<Script> script_desc = v8_compile(
5528 "Object.getOwnPropertyDescriptor( "
5530 "prop.configurable;");
5531 Local<Value> result = script_desc->Run();
5532 CHECK_EQ(result->BooleanValue(), true);
5534 Local<Script> script_define = v8_compile(
5535 "var desc = {get: function(){return 42; },"
5536 " configurable: true };"
5537 "Object.defineProperty(obj, 'x', desc);"
5539 result = script_define->Run();
5540 CHECK_EQ(result, v8_num(42));
5543 result = script_desc->Run();
5544 CHECK_EQ(result->BooleanValue(), true);
5547 script_define = v8_compile(
5548 "var desc = {get: function(){return 43; },"
5549 " configurable: false };"
5550 "Object.defineProperty(obj, 'x', desc);"
5552 result = script_define->Run();
5553 CHECK_EQ(result, v8_num(43));
5554 result = script_desc->Run();
5556 CHECK_EQ(result->BooleanValue(), false);
5558 v8::TryCatch try_catch;
5559 result = script_define->Run();
5560 CHECK(try_catch.HasCaught());
5561 String::Utf8Value exception_value(try_catch.Exception());
5562 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5566 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5568 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5572 THREADED_TEST(DefineAPIAccessorOnObject) {
5573 v8::Isolate* isolate = CcTest::isolate();
5574 v8::HandleScope scope(isolate);
5575 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5576 LocalContext context;
5578 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5579 CompileRun("var obj2 = {};");
5581 CHECK(CompileRun("obj1.x")->IsUndefined());
5582 CHECK(CompileRun("obj2.x")->IsUndefined());
5584 CHECK(GetGlobalProperty(&context, "obj1")->
5585 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5587 ExpectString("obj1.x", "x");
5588 CHECK(CompileRun("obj2.x")->IsUndefined());
5590 CHECK(GetGlobalProperty(&context, "obj2")->
5591 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5593 ExpectString("obj1.x", "x");
5594 ExpectString("obj2.x", "x");
5596 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5597 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5599 CompileRun("Object.defineProperty(obj1, 'x',"
5600 "{ get: function() { return 'y'; }, configurable: true })");
5602 ExpectString("obj1.x", "y");
5603 ExpectString("obj2.x", "x");
5605 CompileRun("Object.defineProperty(obj2, 'x',"
5606 "{ get: function() { return 'y'; }, configurable: true })");
5608 ExpectString("obj1.x", "y");
5609 ExpectString("obj2.x", "y");
5611 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5612 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5614 CHECK(GetGlobalProperty(&context, "obj1")->
5615 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5616 CHECK(GetGlobalProperty(&context, "obj2")->
5617 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5619 ExpectString("obj1.x", "x");
5620 ExpectString("obj2.x", "x");
5622 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5623 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5625 // Define getters/setters, but now make them not configurable.
5626 CompileRun("Object.defineProperty(obj1, 'x',"
5627 "{ get: function() { return 'z'; }, configurable: false })");
5628 CompileRun("Object.defineProperty(obj2, 'x',"
5629 "{ get: function() { return 'z'; }, configurable: false })");
5631 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5632 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5634 ExpectString("obj1.x", "z");
5635 ExpectString("obj2.x", "z");
5637 CHECK(!GetGlobalProperty(&context, "obj1")->
5638 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5639 CHECK(!GetGlobalProperty(&context, "obj2")->
5640 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5642 ExpectString("obj1.x", "z");
5643 ExpectString("obj2.x", "z");
5647 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5648 v8::Isolate* isolate = CcTest::isolate();
5649 v8::HandleScope scope(isolate);
5650 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5651 LocalContext context;
5653 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5654 CompileRun("var obj2 = {};");
5656 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5659 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5660 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5663 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5665 ExpectString("obj1.x", "x");
5666 ExpectString("obj2.x", "x");
5668 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5669 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5671 CHECK(!GetGlobalProperty(&context, "obj1")->
5672 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5673 CHECK(!GetGlobalProperty(&context, "obj2")->
5674 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5677 v8::TryCatch try_catch;
5678 CompileRun("Object.defineProperty(obj1, 'x',"
5679 "{get: function() { return 'func'; }})");
5680 CHECK(try_catch.HasCaught());
5681 String::Utf8Value exception_value(try_catch.Exception());
5682 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5685 v8::TryCatch try_catch;
5686 CompileRun("Object.defineProperty(obj2, 'x',"
5687 "{get: function() { return 'func'; }})");
5688 CHECK(try_catch.HasCaught());
5689 String::Utf8Value exception_value(try_catch.Exception());
5690 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5695 static void Get239Value(Local<String> name,
5696 const v8::PropertyCallbackInfo<v8::Value>& info) {
5697 ApiTestFuzzer::Fuzz();
5698 CHECK_EQ(info.Data(), v8_str("donut"));
5699 CHECK_EQ(name, v8_str("239"));
5700 info.GetReturnValue().Set(name);
5704 THREADED_TEST(ElementAPIAccessor) {
5705 v8::Isolate* isolate = CcTest::isolate();
5706 v8::HandleScope scope(isolate);
5707 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5708 LocalContext context;
5710 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5711 CompileRun("var obj2 = {};");
5713 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5717 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5722 ExpectString("obj1[239]", "239");
5723 ExpectString("obj2[239]", "239");
5724 ExpectString("obj1['239']", "239");
5725 ExpectString("obj2['239']", "239");
5729 v8::Persistent<Value> xValue;
5732 static void SetXValue(Local<String> name,
5734 const v8::PropertyCallbackInfo<void>& info) {
5735 CHECK_EQ(value, v8_num(4));
5736 CHECK_EQ(info.Data(), v8_str("donut"));
5737 CHECK_EQ(name, v8_str("x"));
5738 CHECK(xValue.IsEmpty());
5739 xValue.Reset(info.GetIsolate(), value);
5743 THREADED_TEST(SimplePropertyWrite) {
5744 v8::Isolate* isolate = CcTest::isolate();
5745 v8::HandleScope scope(isolate);
5746 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5747 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5748 LocalContext context;
5749 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5750 Local<Script> script = v8_compile("obj.x = 4");
5751 for (int i = 0; i < 10; i++) {
5752 CHECK(xValue.IsEmpty());
5754 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5760 THREADED_TEST(SetterOnly) {
5761 v8::Isolate* isolate = CcTest::isolate();
5762 v8::HandleScope scope(isolate);
5763 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5765 LocalContext context;
5766 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5767 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5768 for (int i = 0; i < 10; i++) {
5769 CHECK(xValue.IsEmpty());
5771 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5777 THREADED_TEST(NoAccessors) {
5778 v8::Isolate* isolate = CcTest::isolate();
5779 v8::HandleScope scope(isolate);
5780 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5781 templ->SetAccessor(v8_str("x"),
5782 static_cast<v8::AccessorGetterCallback>(NULL),
5785 LocalContext context;
5786 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5787 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5788 for (int i = 0; i < 10; i++) {
5794 static void XPropertyGetter(Local<String> property,
5795 const v8::PropertyCallbackInfo<v8::Value>& info) {
5796 ApiTestFuzzer::Fuzz();
5797 CHECK(info.Data()->IsUndefined());
5798 info.GetReturnValue().Set(property);
5802 THREADED_TEST(NamedInterceptorPropertyRead) {
5803 v8::Isolate* isolate = CcTest::isolate();
5804 v8::HandleScope scope(isolate);
5805 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5806 templ->SetNamedPropertyHandler(XPropertyGetter);
5807 LocalContext context;
5808 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5809 Local<Script> script = v8_compile("obj.x");
5810 for (int i = 0; i < 10; i++) {
5811 Local<Value> result = script->Run();
5812 CHECK_EQ(result, v8_str("x"));
5817 THREADED_TEST(NamedInterceptorDictionaryIC) {
5818 v8::Isolate* isolate = CcTest::isolate();
5819 v8::HandleScope scope(isolate);
5820 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5821 templ->SetNamedPropertyHandler(XPropertyGetter);
5822 LocalContext context;
5823 // Create an object with a named interceptor.
5824 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5825 Local<Script> script = v8_compile("interceptor_obj.x");
5826 for (int i = 0; i < 10; i++) {
5827 Local<Value> result = script->Run();
5828 CHECK_EQ(result, v8_str("x"));
5830 // Create a slow case object and a function accessing a property in
5831 // that slow case object (with dictionary probing in generated
5832 // code). Then force object with a named interceptor into slow-case,
5833 // pass it to the function, and check that the interceptor is called
5834 // instead of accessing the local property.
5835 Local<Value> result =
5836 CompileRun("function get_x(o) { return o.x; };"
5837 "var obj = { x : 42, y : 0 };"
5839 "for (var i = 0; i < 10; i++) get_x(obj);"
5840 "interceptor_obj.x = 42;"
5841 "interceptor_obj.y = 10;"
5842 "delete interceptor_obj.y;"
5843 "get_x(interceptor_obj)");
5844 CHECK_EQ(result, v8_str("x"));
5848 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5849 v8::Isolate* isolate = CcTest::isolate();
5850 v8::HandleScope scope(isolate);
5851 v8::Local<Context> context1 = Context::New(isolate);
5854 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5855 templ->SetNamedPropertyHandler(XPropertyGetter);
5856 // Create an object with a named interceptor.
5857 v8::Local<v8::Object> object = templ->NewInstance();
5858 context1->Global()->Set(v8_str("interceptor_obj"), object);
5860 // Force the object into the slow case.
5861 CompileRun("interceptor_obj.y = 0;"
5862 "delete interceptor_obj.y;");
5866 // Introduce the object into a different context.
5867 // Repeat named loads to exercise ICs.
5868 LocalContext context2;
5869 context2->Global()->Set(v8_str("interceptor_obj"), object);
5870 Local<Value> result =
5871 CompileRun("function get_x(o) { return o.x; }"
5872 "interceptor_obj.x = 42;"
5873 "for (var i=0; i != 10; i++) {"
5874 " get_x(interceptor_obj);"
5876 "get_x(interceptor_obj)");
5877 // Check that the interceptor was actually invoked.
5878 CHECK_EQ(result, v8_str("x"));
5881 // Return to the original context and force some object to the slow case
5882 // to cause the NormalizedMapCache to verify.
5884 CompileRun("var obj = { x : 0 }; delete obj.x;");
5889 static void SetXOnPrototypeGetter(
5890 Local<String> property,
5891 const v8::PropertyCallbackInfo<v8::Value>& info) {
5892 // Set x on the prototype object and do not handle the get request.
5893 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5894 proto.As<v8::Object>()->Set(v8_str("x"),
5895 v8::Integer::New(info.GetIsolate(), 23));
5899 // This is a regression test for http://crbug.com/20104. Map
5900 // transitions should not interfere with post interceptor lookup.
5901 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5902 v8::Isolate* isolate = CcTest::isolate();
5903 v8::HandleScope scope(isolate);
5904 Local<v8::FunctionTemplate> function_template =
5905 v8::FunctionTemplate::New(isolate);
5906 Local<v8::ObjectTemplate> instance_template
5907 = function_template->InstanceTemplate();
5908 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5909 LocalContext context;
5910 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5911 // Create an instance of F and introduce a map transition for x.
5912 CompileRun("var o = new F(); o.x = 23;");
5913 // Create an instance of F and invoke the getter. The result should be 23.
5914 Local<Value> result = CompileRun("o = new F(); o.x");
5915 CHECK_EQ(result->Int32Value(), 23);
5919 static void IndexedPropertyGetter(
5921 const v8::PropertyCallbackInfo<v8::Value>& info) {
5922 ApiTestFuzzer::Fuzz();
5924 info.GetReturnValue().Set(v8_num(625));
5929 static void IndexedPropertySetter(
5932 const v8::PropertyCallbackInfo<v8::Value>& info) {
5933 ApiTestFuzzer::Fuzz();
5935 info.GetReturnValue().Set(value);
5940 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5941 v8::Isolate* isolate = CcTest::isolate();
5942 v8::HandleScope scope(isolate);
5943 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5944 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5945 IndexedPropertySetter);
5946 LocalContext context;
5947 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5948 Local<Script> getter_script = v8_compile(
5949 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5950 Local<Script> setter_script = v8_compile(
5951 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5954 Local<Script> interceptor_setter_script = v8_compile(
5955 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5957 "obj.foo;"); // This setter should not run, due to the interceptor.
5958 Local<Script> interceptor_getter_script = v8_compile(
5960 Local<Value> result = getter_script->Run();
5961 CHECK_EQ(v8_num(5), result);
5962 result = setter_script->Run();
5963 CHECK_EQ(v8_num(23), result);
5964 result = interceptor_setter_script->Run();
5965 CHECK_EQ(v8_num(23), result);
5966 result = interceptor_getter_script->Run();
5967 CHECK_EQ(v8_num(625), result);
5971 static void UnboxedDoubleIndexedPropertyGetter(
5973 const v8::PropertyCallbackInfo<v8::Value>& info) {
5974 ApiTestFuzzer::Fuzz();
5976 info.GetReturnValue().Set(v8_num(index));
5981 static void UnboxedDoubleIndexedPropertySetter(
5984 const v8::PropertyCallbackInfo<v8::Value>& info) {
5985 ApiTestFuzzer::Fuzz();
5987 info.GetReturnValue().Set(v8_num(index));
5992 void UnboxedDoubleIndexedPropertyEnumerator(
5993 const v8::PropertyCallbackInfo<v8::Array>& info) {
5994 // Force the list of returned keys to be stored in a FastDoubleArray.
5995 Local<Script> indexed_property_names_script = v8_compile(
5996 "keys = new Array(); keys[125000] = 1;"
5997 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5998 "keys.length = 25; keys;");
5999 Local<Value> result = indexed_property_names_script->Run();
6000 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6004 // Make sure that the the interceptor code in the runtime properly handles
6005 // merging property name lists for double-array-backed arrays.
6006 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6007 v8::Isolate* isolate = CcTest::isolate();
6008 v8::HandleScope scope(isolate);
6009 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6010 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6011 UnboxedDoubleIndexedPropertySetter,
6014 UnboxedDoubleIndexedPropertyEnumerator);
6015 LocalContext context;
6016 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6017 // When obj is created, force it to be Stored in a FastDoubleArray.
6018 Local<Script> create_unboxed_double_script = v8_compile(
6019 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6021 "for (x in obj) {key_count++;};"
6023 Local<Value> result = create_unboxed_double_script->Run();
6024 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6025 Local<Script> key_count_check = v8_compile("key_count;");
6026 result = key_count_check->Run();
6027 CHECK_EQ(v8_num(40013), result);
6031 void SloppyArgsIndexedPropertyEnumerator(
6032 const v8::PropertyCallbackInfo<v8::Array>& info) {
6033 // Force the list of returned keys to be stored in a Arguments object.
6034 Local<Script> indexed_property_names_script = v8_compile(
6036 " return arguments;"
6038 "keys = f(0, 1, 2, 3);"
6040 Local<Object> result =
6041 Local<Object>::Cast(indexed_property_names_script->Run());
6042 // Have to populate the handle manually, as it's not Cast-able.
6043 i::Handle<i::JSObject> o =
6044 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6045 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6046 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6050 static void SloppyIndexedPropertyGetter(
6052 const v8::PropertyCallbackInfo<v8::Value>& info) {
6053 ApiTestFuzzer::Fuzz();
6055 info.GetReturnValue().Set(v8_num(index));
6060 // Make sure that the the interceptor code in the runtime properly handles
6061 // merging property name lists for non-string arguments arrays.
6062 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6063 v8::Isolate* isolate = CcTest::isolate();
6064 v8::HandleScope scope(isolate);
6065 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6066 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6070 SloppyArgsIndexedPropertyEnumerator);
6071 LocalContext context;
6072 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6073 Local<Script> create_args_script = v8_compile(
6074 "var key_count = 0;"
6075 "for (x in obj) {key_count++;} key_count;");
6076 Local<Value> result = create_args_script->Run();
6077 CHECK_EQ(v8_num(4), result);
6081 static void IdentityIndexedPropertyGetter(
6083 const v8::PropertyCallbackInfo<v8::Value>& info) {
6084 info.GetReturnValue().Set(index);
6088 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6089 v8::Isolate* isolate = CcTest::isolate();
6090 v8::HandleScope scope(isolate);
6091 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6092 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6094 LocalContext context;
6095 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6097 // Check fast object case.
6098 const char* fast_case_code =
6099 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6100 ExpectString(fast_case_code, "0");
6103 const char* slow_case_code =
6104 "obj.x = 1; delete obj.x;"
6105 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6106 ExpectString(slow_case_code, "1");
6110 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6111 v8::Isolate* isolate = CcTest::isolate();
6112 v8::HandleScope scope(isolate);
6113 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6114 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6116 LocalContext context;
6117 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6122 " for (var i = 0; i < 100; i++) {"
6124 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6130 ExpectString(code, "PASSED");
6134 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6135 v8::Isolate* isolate = CcTest::isolate();
6136 v8::HandleScope scope(isolate);
6137 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6138 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6140 LocalContext context;
6141 Local<v8::Object> obj = templ->NewInstance();
6142 obj->TurnOnAccessCheck();
6143 context->Global()->Set(v8_str("obj"), obj);
6147 " for (var i = 0; i < 100; i++) {"
6149 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6155 ExpectString(code, "PASSED");
6159 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6160 i::FLAG_allow_natives_syntax = true;
6161 v8::Isolate* isolate = CcTest::isolate();
6162 v8::HandleScope scope(isolate);
6163 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6164 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6166 LocalContext context;
6167 Local<v8::Object> obj = templ->NewInstance();
6168 context->Global()->Set(v8_str("obj"), obj);
6172 " for (var i = 0; i < 100; i++) {"
6173 " var expected = i;"
6175 " %EnableAccessChecks(obj);"
6176 " expected = undefined;"
6179 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6180 " if (i == 5) %DisableAccessChecks(obj);"
6186 ExpectString(code, "PASSED");
6190 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6191 v8::Isolate* isolate = CcTest::isolate();
6192 v8::HandleScope scope(isolate);
6193 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6194 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6196 LocalContext context;
6197 Local<v8::Object> obj = templ->NewInstance();
6198 context->Global()->Set(v8_str("obj"), obj);
6202 " for (var i = 0; i < 100; i++) {"
6204 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6210 ExpectString(code, "PASSED");
6214 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6215 v8::Isolate* isolate = CcTest::isolate();
6216 v8::HandleScope scope(isolate);
6217 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6218 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6220 LocalContext context;
6221 Local<v8::Object> obj = templ->NewInstance();
6222 context->Global()->Set(v8_str("obj"), obj);
6226 " for (var i = 0; i < 100; i++) {"
6227 " var expected = i;"
6231 " expected = undefined;"
6234 " /* probe minimal Smi number on 32-bit platforms */"
6235 " key = -(1 << 30);"
6236 " expected = undefined;"
6239 " /* probe minimal Smi number on 64-bit platforms */"
6241 " expected = undefined;"
6243 " var v = obj[key];"
6244 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6250 ExpectString(code, "PASSED");
6254 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6255 v8::Isolate* isolate = CcTest::isolate();
6256 v8::HandleScope scope(isolate);
6257 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6258 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6260 LocalContext context;
6261 Local<v8::Object> obj = templ->NewInstance();
6262 context->Global()->Set(v8_str("obj"), obj);
6266 " for (var i = 0; i < 100; i++) {"
6267 " var expected = i;"
6271 " expected = undefined;"
6273 " var v = obj[key];"
6274 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6280 ExpectString(code, "PASSED");
6284 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6285 v8::Isolate* isolate = CcTest::isolate();
6286 v8::HandleScope scope(isolate);
6287 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6288 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6290 LocalContext context;
6291 Local<v8::Object> obj = templ->NewInstance();
6292 context->Global()->Set(v8_str("obj"), obj);
6295 "var original = obj;"
6297 " for (var i = 0; i < 100; i++) {"
6298 " var expected = i;"
6300 " obj = {50: 'foobar'};"
6301 " expected = 'foobar';"
6304 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6305 " if (i == 50) obj = original;"
6311 ExpectString(code, "PASSED");
6315 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6316 v8::Isolate* isolate = CcTest::isolate();
6317 v8::HandleScope scope(isolate);
6318 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6319 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6321 LocalContext context;
6322 Local<v8::Object> obj = templ->NewInstance();
6323 context->Global()->Set(v8_str("obj"), obj);
6326 "var original = obj;"
6328 " for (var i = 0; i < 100; i++) {"
6329 " var expected = i;"
6332 " expected = undefined;"
6335 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6336 " if (i == 5) obj = original;"
6342 ExpectString(code, "PASSED");
6346 THREADED_TEST(IndexedInterceptorOnProto) {
6347 v8::Isolate* isolate = CcTest::isolate();
6348 v8::HandleScope scope(isolate);
6349 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6350 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6352 LocalContext context;
6353 Local<v8::Object> obj = templ->NewInstance();
6354 context->Global()->Set(v8_str("obj"), obj);
6357 "var o = {__proto__: obj};"
6359 " for (var i = 0; i < 100; i++) {"
6361 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6367 ExpectString(code, "PASSED");
6371 THREADED_TEST(MultiContexts) {
6372 v8::Isolate* isolate = CcTest::isolate();
6373 v8::HandleScope scope(isolate);
6374 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6375 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6378 Local<String> password = v8_str("Password");
6380 // Create an environment
6381 LocalContext context0(0, templ);
6382 context0->SetSecurityToken(password);
6383 v8::Handle<v8::Object> global0 = context0->Global();
6384 global0->Set(v8_str("custom"), v8_num(1234));
6385 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6387 // Create an independent environment
6388 LocalContext context1(0, templ);
6389 context1->SetSecurityToken(password);
6390 v8::Handle<v8::Object> global1 = context1->Global();
6391 global1->Set(v8_str("custom"), v8_num(1234));
6392 CHECK_NE(global0, global1);
6393 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6394 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6396 // Now create a new context with the old global
6397 LocalContext context2(0, templ, global1);
6398 context2->SetSecurityToken(password);
6399 v8::Handle<v8::Object> global2 = context2->Global();
6400 CHECK_EQ(global1, global2);
6401 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6402 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6406 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6407 // Make sure that functions created by cloning boilerplates cannot
6408 // communicate through their __proto__ field.
6410 v8::HandleScope scope(CcTest::isolate());
6413 v8::Handle<v8::Object> global0 =
6415 v8::Handle<v8::Object> object0 =
6416 global0->Get(v8_str("Object")).As<v8::Object>();
6417 v8::Handle<v8::Object> tostring0 =
6418 object0->Get(v8_str("toString")).As<v8::Object>();
6419 v8::Handle<v8::Object> proto0 =
6420 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6421 proto0->Set(v8_str("custom"), v8_num(1234));
6424 v8::Handle<v8::Object> global1 =
6426 v8::Handle<v8::Object> object1 =
6427 global1->Get(v8_str("Object")).As<v8::Object>();
6428 v8::Handle<v8::Object> tostring1 =
6429 object1->Get(v8_str("toString")).As<v8::Object>();
6430 v8::Handle<v8::Object> proto1 =
6431 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6432 CHECK(!proto1->Has(v8_str("custom")));
6436 THREADED_TEST(Regress892105) {
6437 // Make sure that object and array literals created by cloning
6438 // boilerplates cannot communicate through their __proto__
6439 // field. This is rather difficult to check, but we try to add stuff
6440 // to Object.prototype and Array.prototype and create a new
6441 // environment. This should succeed.
6443 v8::HandleScope scope(CcTest::isolate());
6445 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6446 "Array.prototype.arr = 4567;"
6450 Local<Script> script0 = v8_compile(source);
6451 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6454 Local<Script> script1 = v8_compile(source);
6455 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6459 THREADED_TEST(UndetectableObject) {
6461 v8::HandleScope scope(env->GetIsolate());
6463 Local<v8::FunctionTemplate> desc =
6464 v8::FunctionTemplate::New(env->GetIsolate());
6465 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6467 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6468 env->Global()->Set(v8_str("undetectable"), obj);
6470 ExpectString("undetectable.toString()", "[object Object]");
6471 ExpectString("typeof undetectable", "undefined");
6472 ExpectString("typeof(undetectable)", "undefined");
6473 ExpectBoolean("typeof undetectable == 'undefined'", true);
6474 ExpectBoolean("typeof undetectable == 'object'", false);
6475 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6476 ExpectBoolean("!undetectable", true);
6478 ExpectObject("true&&undetectable", obj);
6479 ExpectBoolean("false&&undetectable", false);
6480 ExpectBoolean("true||undetectable", true);
6481 ExpectObject("false||undetectable", obj);
6483 ExpectObject("undetectable&&true", obj);
6484 ExpectObject("undetectable&&false", obj);
6485 ExpectBoolean("undetectable||true", true);
6486 ExpectBoolean("undetectable||false", false);
6488 ExpectBoolean("undetectable==null", true);
6489 ExpectBoolean("null==undetectable", true);
6490 ExpectBoolean("undetectable==undefined", true);
6491 ExpectBoolean("undefined==undetectable", true);
6492 ExpectBoolean("undetectable==undetectable", true);
6495 ExpectBoolean("undetectable===null", false);
6496 ExpectBoolean("null===undetectable", false);
6497 ExpectBoolean("undetectable===undefined", false);
6498 ExpectBoolean("undefined===undetectable", false);
6499 ExpectBoolean("undetectable===undetectable", true);
6503 THREADED_TEST(VoidLiteral) {
6505 v8::Isolate* isolate = env->GetIsolate();
6506 v8::HandleScope scope(isolate);
6508 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6509 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6511 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6512 env->Global()->Set(v8_str("undetectable"), obj);
6514 ExpectBoolean("undefined == void 0", true);
6515 ExpectBoolean("undetectable == void 0", true);
6516 ExpectBoolean("null == void 0", true);
6517 ExpectBoolean("undefined === void 0", true);
6518 ExpectBoolean("undetectable === void 0", false);
6519 ExpectBoolean("null === void 0", false);
6521 ExpectBoolean("void 0 == undefined", true);
6522 ExpectBoolean("void 0 == undetectable", true);
6523 ExpectBoolean("void 0 == null", true);
6524 ExpectBoolean("void 0 === undefined", true);
6525 ExpectBoolean("void 0 === undetectable", false);
6526 ExpectBoolean("void 0 === null", false);
6528 ExpectString("(function() {"
6530 " return x === void 0;"
6532 " return e.toString();"
6535 "ReferenceError: x is not defined");
6536 ExpectString("(function() {"
6538 " return void 0 === x;"
6540 " return e.toString();"
6543 "ReferenceError: x is not defined");
6547 THREADED_TEST(ExtensibleOnUndetectable) {
6549 v8::Isolate* isolate = env->GetIsolate();
6550 v8::HandleScope scope(isolate);
6552 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6553 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6555 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6556 env->Global()->Set(v8_str("undetectable"), obj);
6558 Local<String> source = v8_str("undetectable.x = 42;"
6561 Local<Script> script = v8_compile(source);
6563 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6565 ExpectBoolean("Object.isExtensible(undetectable)", true);
6567 source = v8_str("Object.preventExtensions(undetectable);");
6568 script = v8_compile(source);
6570 ExpectBoolean("Object.isExtensible(undetectable)", false);
6572 source = v8_str("undetectable.y = 2000;");
6573 script = v8_compile(source);
6575 ExpectBoolean("undetectable.y == undefined", true);
6580 THREADED_TEST(UndetectableString) {
6582 v8::HandleScope scope(env->GetIsolate());
6584 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6585 String::kUndetectableString);
6586 env->Global()->Set(v8_str("undetectable"), obj);
6588 ExpectString("undetectable", "foo");
6589 ExpectString("typeof undetectable", "undefined");
6590 ExpectString("typeof(undetectable)", "undefined");
6591 ExpectBoolean("typeof undetectable == 'undefined'", true);
6592 ExpectBoolean("typeof undetectable == 'string'", false);
6593 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6594 ExpectBoolean("!undetectable", true);
6596 ExpectObject("true&&undetectable", obj);
6597 ExpectBoolean("false&&undetectable", false);
6598 ExpectBoolean("true||undetectable", true);
6599 ExpectObject("false||undetectable", obj);
6601 ExpectObject("undetectable&&true", obj);
6602 ExpectObject("undetectable&&false", obj);
6603 ExpectBoolean("undetectable||true", true);
6604 ExpectBoolean("undetectable||false", false);
6606 ExpectBoolean("undetectable==null", true);
6607 ExpectBoolean("null==undetectable", true);
6608 ExpectBoolean("undetectable==undefined", true);
6609 ExpectBoolean("undefined==undetectable", true);
6610 ExpectBoolean("undetectable==undetectable", true);
6613 ExpectBoolean("undetectable===null", false);
6614 ExpectBoolean("null===undetectable", false);
6615 ExpectBoolean("undetectable===undefined", false);
6616 ExpectBoolean("undefined===undetectable", false);
6617 ExpectBoolean("undetectable===undetectable", true);
6621 TEST(UndetectableOptimized) {
6622 i::FLAG_allow_natives_syntax = true;
6624 v8::HandleScope scope(env->GetIsolate());
6626 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6627 String::kUndetectableString);
6628 env->Global()->Set(v8_str("undetectable"), obj);
6629 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6632 "function testBranch() {"
6633 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6634 " if (%_IsUndetectableObject(detectable)) throw 2;"
6636 "function testBool() {"
6637 " var b1 = !%_IsUndetectableObject(undetectable);"
6638 " var b2 = %_IsUndetectableObject(detectable);"
6643 "%OptimizeFunctionOnNextCall(testBranch);"
6644 "%OptimizeFunctionOnNextCall(testBool);"
6645 "for (var i = 0; i < 10; i++) {"
6654 template <typename T> static void USE(T) { }
6657 // The point of this test is type checking. We run it only so compilers
6658 // don't complain about an unused function.
6659 TEST(PersistentHandles) {
6661 v8::Isolate* isolate = CcTest::isolate();
6662 v8::HandleScope scope(isolate);
6663 Local<String> str = v8_str("foo");
6664 v8::Persistent<String> p_str(isolate, str);
6666 Local<Script> scr = v8_compile("");
6667 v8::Persistent<Script> p_scr(isolate, scr);
6669 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6670 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6675 static void HandleLogDelegator(
6676 const v8::FunctionCallbackInfo<v8::Value>& args) {
6677 ApiTestFuzzer::Fuzz();
6681 THREADED_TEST(GlobalObjectTemplate) {
6682 v8::Isolate* isolate = CcTest::isolate();
6683 v8::HandleScope handle_scope(isolate);
6684 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6685 global_template->Set(v8_str("JSNI_Log"),
6686 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6687 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6688 Context::Scope context_scope(context);
6689 CompileRun("JSNI_Log('LOG')");
6693 static const char* kSimpleExtensionSource =
6699 TEST(SimpleExtensions) {
6700 v8::HandleScope handle_scope(CcTest::isolate());
6701 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6702 const char* extension_names[] = { "simpletest" };
6703 v8::ExtensionConfiguration extensions(1, extension_names);
6704 v8::Handle<Context> context =
6705 Context::New(CcTest::isolate(), &extensions);
6706 Context::Scope lock(context);
6707 v8::Handle<Value> result = CompileRun("Foo()");
6708 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6712 TEST(NullExtensions) {
6713 v8::HandleScope handle_scope(CcTest::isolate());
6714 v8::RegisterExtension(new Extension("nulltest", NULL));
6715 const char* extension_names[] = { "nulltest" };
6716 v8::ExtensionConfiguration extensions(1, extension_names);
6717 v8::Handle<Context> context =
6718 Context::New(CcTest::isolate(), &extensions);
6719 Context::Scope lock(context);
6720 v8::Handle<Value> result = CompileRun("1+3");
6721 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6725 static const char* kEmbeddedExtensionSource =
6726 "function Ret54321(){return 54321;}~~@@$"
6727 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6728 static const int kEmbeddedExtensionSourceValidLen = 34;
6731 TEST(ExtensionMissingSourceLength) {
6732 v8::HandleScope handle_scope(CcTest::isolate());
6733 v8::RegisterExtension(new Extension("srclentest_fail",
6734 kEmbeddedExtensionSource));
6735 const char* extension_names[] = { "srclentest_fail" };
6736 v8::ExtensionConfiguration extensions(1, extension_names);
6737 v8::Handle<Context> context =
6738 Context::New(CcTest::isolate(), &extensions);
6739 CHECK_EQ(0, *context);
6743 TEST(ExtensionWithSourceLength) {
6744 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6745 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6746 v8::HandleScope handle_scope(CcTest::isolate());
6747 i::ScopedVector<char> extension_name(32);
6748 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6749 v8::RegisterExtension(new Extension(extension_name.start(),
6750 kEmbeddedExtensionSource, 0, 0,
6752 const char* extension_names[1] = { extension_name.start() };
6753 v8::ExtensionConfiguration extensions(1, extension_names);
6754 v8::Handle<Context> context =
6755 Context::New(CcTest::isolate(), &extensions);
6756 if (source_len == kEmbeddedExtensionSourceValidLen) {
6757 Context::Scope lock(context);
6758 v8::Handle<Value> result = CompileRun("Ret54321()");
6759 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6761 // Anything but exactly the right length should fail to compile.
6762 CHECK_EQ(0, *context);
6768 static const char* kEvalExtensionSource1 =
6769 "function UseEval1() {"
6771 " return eval('x');"
6775 static const char* kEvalExtensionSource2 =
6779 " return eval('x');"
6781 " this.UseEval2 = e;"
6785 TEST(UseEvalFromExtension) {
6786 v8::HandleScope handle_scope(CcTest::isolate());
6787 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6788 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6789 const char* extension_names[] = { "evaltest1", "evaltest2" };
6790 v8::ExtensionConfiguration extensions(2, extension_names);
6791 v8::Handle<Context> context =
6792 Context::New(CcTest::isolate(), &extensions);
6793 Context::Scope lock(context);
6794 v8::Handle<Value> result = CompileRun("UseEval1()");
6795 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6796 result = CompileRun("UseEval2()");
6797 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6801 static const char* kWithExtensionSource1 =
6802 "function UseWith1() {"
6804 " with({x:87}) { return x; }"
6809 static const char* kWithExtensionSource2 =
6813 " with ({x:87}) { return x; }"
6815 " this.UseWith2 = e;"
6819 TEST(UseWithFromExtension) {
6820 v8::HandleScope handle_scope(CcTest::isolate());
6821 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6822 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6823 const char* extension_names[] = { "withtest1", "withtest2" };
6824 v8::ExtensionConfiguration extensions(2, extension_names);
6825 v8::Handle<Context> context =
6826 Context::New(CcTest::isolate(), &extensions);
6827 Context::Scope lock(context);
6828 v8::Handle<Value> result = CompileRun("UseWith1()");
6829 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6830 result = CompileRun("UseWith2()");
6831 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6835 TEST(AutoExtensions) {
6836 v8::HandleScope handle_scope(CcTest::isolate());
6837 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6838 extension->set_auto_enable(true);
6839 v8::RegisterExtension(extension);
6840 v8::Handle<Context> context =
6841 Context::New(CcTest::isolate());
6842 Context::Scope lock(context);
6843 v8::Handle<Value> result = CompileRun("Foo()");
6844 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6848 static const char* kSyntaxErrorInExtensionSource =
6852 // Test that a syntax error in an extension does not cause a fatal
6853 // error but results in an empty context.
6854 TEST(SyntaxErrorExtensions) {
6855 v8::HandleScope handle_scope(CcTest::isolate());
6856 v8::RegisterExtension(new Extension("syntaxerror",
6857 kSyntaxErrorInExtensionSource));
6858 const char* extension_names[] = { "syntaxerror" };
6859 v8::ExtensionConfiguration extensions(1, extension_names);
6860 v8::Handle<Context> context =
6861 Context::New(CcTest::isolate(), &extensions);
6862 CHECK(context.IsEmpty());
6866 static const char* kExceptionInExtensionSource =
6870 // Test that an exception when installing an extension does not cause
6871 // a fatal error but results in an empty context.
6872 TEST(ExceptionExtensions) {
6873 v8::HandleScope handle_scope(CcTest::isolate());
6874 v8::RegisterExtension(new Extension("exception",
6875 kExceptionInExtensionSource));
6876 const char* extension_names[] = { "exception" };
6877 v8::ExtensionConfiguration extensions(1, extension_names);
6878 v8::Handle<Context> context =
6879 Context::New(CcTest::isolate(), &extensions);
6880 CHECK(context.IsEmpty());
6884 static const char* kNativeCallInExtensionSource =
6885 "function call_runtime_last_index_of(x) {"
6886 " return %StringLastIndexOf(x, 'bob', 10);"
6890 static const char* kNativeCallTest =
6891 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6893 // Test that a native runtime calls are supported in extensions.
6894 TEST(NativeCallInExtensions) {
6895 v8::HandleScope handle_scope(CcTest::isolate());
6896 v8::RegisterExtension(new Extension("nativecall",
6897 kNativeCallInExtensionSource));
6898 const char* extension_names[] = { "nativecall" };
6899 v8::ExtensionConfiguration extensions(1, extension_names);
6900 v8::Handle<Context> context =
6901 Context::New(CcTest::isolate(), &extensions);
6902 Context::Scope lock(context);
6903 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6904 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6908 class NativeFunctionExtension : public Extension {
6910 NativeFunctionExtension(const char* name,
6912 v8::FunctionCallback fun = &Echo)
6913 : Extension(name, source),
6916 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6917 v8::Isolate* isolate,
6918 v8::Handle<v8::String> name) {
6919 return v8::FunctionTemplate::New(isolate, function_);
6922 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6923 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6926 v8::FunctionCallback function_;
6930 TEST(NativeFunctionDeclaration) {
6931 v8::HandleScope handle_scope(CcTest::isolate());
6932 const char* name = "nativedecl";
6933 v8::RegisterExtension(new NativeFunctionExtension(name,
6934 "native function foo();"));
6935 const char* extension_names[] = { name };
6936 v8::ExtensionConfiguration extensions(1, extension_names);
6937 v8::Handle<Context> context =
6938 Context::New(CcTest::isolate(), &extensions);
6939 Context::Scope lock(context);
6940 v8::Handle<Value> result = CompileRun("foo(42);");
6941 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6945 TEST(NativeFunctionDeclarationError) {
6946 v8::HandleScope handle_scope(CcTest::isolate());
6947 const char* name = "nativedeclerr";
6948 // Syntax error in extension code.
6949 v8::RegisterExtension(new NativeFunctionExtension(name,
6950 "native\nfunction foo();"));
6951 const char* extension_names[] = { name };
6952 v8::ExtensionConfiguration extensions(1, extension_names);
6953 v8::Handle<Context> context =
6954 Context::New(CcTest::isolate(), &extensions);
6955 CHECK(context.IsEmpty());
6959 TEST(NativeFunctionDeclarationErrorEscape) {
6960 v8::HandleScope handle_scope(CcTest::isolate());
6961 const char* name = "nativedeclerresc";
6962 // Syntax error in extension code - escape code in "native" means that
6963 // it's not treated as a keyword.
6964 v8::RegisterExtension(new NativeFunctionExtension(
6966 "nativ\\u0065 function foo();"));
6967 const char* extension_names[] = { name };
6968 v8::ExtensionConfiguration extensions(1, extension_names);
6969 v8::Handle<Context> context =
6970 Context::New(CcTest::isolate(), &extensions);
6971 CHECK(context.IsEmpty());
6975 static void CheckDependencies(const char* name, const char* expected) {
6976 v8::HandleScope handle_scope(CcTest::isolate());
6977 v8::ExtensionConfiguration config(1, &name);
6978 LocalContext context(&config);
6979 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6980 context->Global()->Get(v8_str("loaded")));
6991 THREADED_TEST(ExtensionDependency) {
6992 static const char* kEDeps[] = { "D" };
6993 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6994 static const char* kDDeps[] = { "B", "C" };
6995 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6996 static const char* kBCDeps[] = { "A" };
6997 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6998 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6999 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7000 CheckDependencies("A", "undefinedA");
7001 CheckDependencies("B", "undefinedAB");
7002 CheckDependencies("C", "undefinedAC");
7003 CheckDependencies("D", "undefinedABCD");
7004 CheckDependencies("E", "undefinedABCDE");
7005 v8::HandleScope handle_scope(CcTest::isolate());
7006 static const char* exts[2] = { "C", "E" };
7007 v8::ExtensionConfiguration config(2, exts);
7008 LocalContext context(&config);
7009 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7013 static const char* kExtensionTestScript =
7014 "native function A();"
7015 "native function B();"
7016 "native function C();"
7018 " if (i == 0) return A();"
7019 " if (i == 1) return B();"
7020 " if (i == 2) return C();"
7024 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7025 ApiTestFuzzer::Fuzz();
7026 if (args.IsConstructCall()) {
7027 args.This()->Set(v8_str("data"), args.Data());
7028 args.GetReturnValue().SetNull();
7031 args.GetReturnValue().Set(args.Data());
7035 class FunctionExtension : public Extension {
7037 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7038 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7039 v8::Isolate* isolate,
7040 v8::Handle<String> name);
7044 static int lookup_count = 0;
7045 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7046 v8::Isolate* isolate, v8::Handle<String> name) {
7048 if (name->Equals(v8_str("A"))) {
7049 return v8::FunctionTemplate::New(
7050 isolate, CallFun, v8::Integer::New(isolate, 8));
7051 } else if (name->Equals(v8_str("B"))) {
7052 return v8::FunctionTemplate::New(
7053 isolate, CallFun, v8::Integer::New(isolate, 7));
7054 } else if (name->Equals(v8_str("C"))) {
7055 return v8::FunctionTemplate::New(
7056 isolate, CallFun, v8::Integer::New(isolate, 6));
7058 return v8::Handle<v8::FunctionTemplate>();
7063 THREADED_TEST(FunctionLookup) {
7064 v8::RegisterExtension(new FunctionExtension());
7065 v8::HandleScope handle_scope(CcTest::isolate());
7066 static const char* exts[1] = { "functiontest" };
7067 v8::ExtensionConfiguration config(1, exts);
7068 LocalContext context(&config);
7069 CHECK_EQ(3, lookup_count);
7070 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7071 CompileRun("Foo(0)"));
7072 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7073 CompileRun("Foo(1)"));
7074 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7075 CompileRun("Foo(2)"));
7079 THREADED_TEST(NativeFunctionConstructCall) {
7080 v8::RegisterExtension(new FunctionExtension());
7081 v8::HandleScope handle_scope(CcTest::isolate());
7082 static const char* exts[1] = { "functiontest" };
7083 v8::ExtensionConfiguration config(1, exts);
7084 LocalContext context(&config);
7085 for (int i = 0; i < 10; i++) {
7086 // Run a few times to ensure that allocation of objects doesn't
7087 // change behavior of a constructor function.
7088 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7089 CompileRun("(new A()).data"));
7090 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7091 CompileRun("(new B()).data"));
7092 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7093 CompileRun("(new C()).data"));
7098 static const char* last_location;
7099 static const char* last_message;
7100 void StoringErrorCallback(const char* location, const char* message) {
7101 if (last_location == NULL) {
7102 last_location = location;
7103 last_message = message;
7108 // ErrorReporting creates a circular extensions configuration and
7109 // tests that the fatal error handler gets called. This renders V8
7110 // unusable and therefore this test cannot be run in parallel.
7111 TEST(ErrorReporting) {
7112 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7113 static const char* aDeps[] = { "B" };
7114 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7115 static const char* bDeps[] = { "A" };
7116 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7117 last_location = NULL;
7118 v8::ExtensionConfiguration config(1, bDeps);
7119 v8::Handle<Context> context =
7120 Context::New(CcTest::isolate(), &config);
7121 CHECK(context.IsEmpty());
7122 CHECK_NE(last_location, NULL);
7126 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7127 v8::Handle<Value> data) {
7128 CHECK(message->GetScriptResourceName()->IsUndefined());
7129 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7130 message->GetLineNumber();
7131 message->GetSourceLine();
7135 THREADED_TEST(ErrorWithMissingScriptInfo) {
7136 LocalContext context;
7137 v8::HandleScope scope(context->GetIsolate());
7138 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7139 CompileRun("throw Error()");
7140 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7144 struct FlagAndPersistent {
7146 v8::Persistent<v8::Object> handle;
7150 static void DisposeAndSetFlag(
7151 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7152 data.GetParameter()->handle.Reset();
7153 data.GetParameter()->flag = true;
7157 THREADED_TEST(IndependentWeakHandle) {
7158 v8::Isolate* iso = CcTest::isolate();
7159 v8::HandleScope scope(iso);
7160 v8::Handle<Context> context = Context::New(iso);
7161 Context::Scope context_scope(context);
7163 FlagAndPersistent object_a, object_b;
7166 v8::HandleScope handle_scope(iso);
7167 object_a.handle.Reset(iso, v8::Object::New(iso));
7168 object_b.handle.Reset(iso, v8::Object::New(iso));
7171 object_a.flag = false;
7172 object_b.flag = false;
7173 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7174 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7175 CHECK(!object_b.handle.IsIndependent());
7176 object_a.handle.MarkIndependent();
7177 object_b.handle.MarkIndependent();
7178 CHECK(object_b.handle.IsIndependent());
7179 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7180 CHECK(object_a.flag);
7181 CHECK(object_b.flag);
7185 static void InvokeScavenge() {
7186 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7190 static void InvokeMarkSweep() {
7191 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7195 static void ForceScavenge(
7196 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7197 data.GetParameter()->handle.Reset();
7198 data.GetParameter()->flag = true;
7203 static void ForceMarkSweep(
7204 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7205 data.GetParameter()->handle.Reset();
7206 data.GetParameter()->flag = true;
7211 THREADED_TEST(GCFromWeakCallbacks) {
7212 v8::Isolate* isolate = CcTest::isolate();
7213 v8::HandleScope scope(isolate);
7214 v8::Handle<Context> context = Context::New(isolate);
7215 Context::Scope context_scope(context);
7217 static const int kNumberOfGCTypes = 2;
7218 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7220 Callback gc_forcing_callback[kNumberOfGCTypes] =
7221 {&ForceScavenge, &ForceMarkSweep};
7223 typedef void (*GCInvoker)();
7224 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7226 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7227 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7228 FlagAndPersistent object;
7230 v8::HandleScope handle_scope(isolate);
7231 object.handle.Reset(isolate, v8::Object::New(isolate));
7233 object.flag = false;
7234 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7235 object.handle.MarkIndependent();
7236 invoke_gc[outer_gc]();
7243 static void RevivingCallback(
7244 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7245 data.GetParameter()->handle.ClearWeak();
7246 data.GetParameter()->flag = true;
7250 THREADED_TEST(IndependentHandleRevival) {
7251 v8::Isolate* isolate = CcTest::isolate();
7252 v8::HandleScope scope(isolate);
7253 v8::Handle<Context> context = Context::New(isolate);
7254 Context::Scope context_scope(context);
7256 FlagAndPersistent object;
7258 v8::HandleScope handle_scope(isolate);
7259 v8::Local<v8::Object> o = v8::Object::New(isolate);
7260 object.handle.Reset(isolate, o);
7261 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7262 v8::Local<String> y_str = v8_str("y");
7263 o->Set(y_str, y_str);
7265 object.flag = false;
7266 object.handle.SetWeak(&object, &RevivingCallback);
7267 object.handle.MarkIndependent();
7268 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7270 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7272 v8::HandleScope handle_scope(isolate);
7273 v8::Local<v8::Object> o =
7274 v8::Local<v8::Object>::New(isolate, object.handle);
7275 v8::Local<String> y_str = v8_str("y");
7276 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7277 CHECK(o->Get(y_str)->Equals(y_str));
7282 v8::Handle<Function> args_fun;
7285 static void ArgumentsTestCallback(
7286 const v8::FunctionCallbackInfo<v8::Value>& args) {
7287 ApiTestFuzzer::Fuzz();
7288 v8::Isolate* isolate = args.GetIsolate();
7289 CHECK_EQ(args_fun, args.Callee());
7290 CHECK_EQ(3, args.Length());
7291 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7292 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7293 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7294 CHECK_EQ(v8::Undefined(isolate), args[3]);
7295 v8::HandleScope scope(args.GetIsolate());
7296 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7300 THREADED_TEST(Arguments) {
7301 v8::Isolate* isolate = CcTest::isolate();
7302 v8::HandleScope scope(isolate);
7303 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7304 global->Set(v8_str("f"),
7305 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7306 LocalContext context(NULL, global);
7307 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7308 v8_compile("f(1, 2, 3)")->Run();
7312 static void NoBlockGetterX(Local<String> name,
7313 const v8::PropertyCallbackInfo<v8::Value>&) {
7317 static void NoBlockGetterI(uint32_t index,
7318 const v8::PropertyCallbackInfo<v8::Value>&) {
7322 static void PDeleter(Local<String> name,
7323 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7324 if (!name->Equals(v8_str("foo"))) {
7325 return; // not intercepted
7328 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7332 static void IDeleter(uint32_t index,
7333 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7335 return; // not intercepted
7338 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7342 THREADED_TEST(Deleter) {
7343 v8::Isolate* isolate = CcTest::isolate();
7344 v8::HandleScope scope(isolate);
7345 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7346 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7347 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7348 LocalContext context;
7349 context->Global()->Set(v8_str("k"), obj->NewInstance());
7355 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7356 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7358 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7359 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7361 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7362 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7364 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7365 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7369 static void GetK(Local<String> name,
7370 const v8::PropertyCallbackInfo<v8::Value>& info) {
7371 ApiTestFuzzer::Fuzz();
7372 if (name->Equals(v8_str("foo")) ||
7373 name->Equals(v8_str("bar")) ||
7374 name->Equals(v8_str("baz"))) {
7375 info.GetReturnValue().SetUndefined();
7380 static void IndexedGetK(uint32_t index,
7381 const v8::PropertyCallbackInfo<v8::Value>& info) {
7382 ApiTestFuzzer::Fuzz();
7383 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7387 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7388 ApiTestFuzzer::Fuzz();
7389 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7390 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7391 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7392 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7393 info.GetReturnValue().Set(result);
7397 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7398 ApiTestFuzzer::Fuzz();
7399 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7400 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7401 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7402 info.GetReturnValue().Set(result);
7406 THREADED_TEST(Enumerators) {
7407 v8::Isolate* isolate = CcTest::isolate();
7408 v8::HandleScope scope(isolate);
7409 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7410 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7411 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7412 LocalContext context;
7413 context->Global()->Set(v8_str("k"), obj->NewInstance());
7414 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7419 "k[4294967295] = 0;"
7421 "k[4294967296] = 0;"
7425 "k[30000000000] = 0;"
7428 "for (var prop in k) {"
7429 " result.push(prop);"
7432 // Check that we get all the property names returned including the
7433 // ones from the enumerators in the right order: indexed properties
7434 // in numerical order, indexed interceptor properties, named
7435 // properties in insertion order, named interceptor properties.
7436 // This order is not mandated by the spec, so this test is just
7437 // documenting our behavior.
7438 CHECK_EQ(17, result->Length());
7439 // Indexed properties in numerical order.
7440 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7441 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7442 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7443 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7444 // Indexed interceptor properties in the order they are returned
7445 // from the enumerator interceptor.
7446 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7447 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7448 // Named properties in insertion order.
7449 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7450 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7451 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7452 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7453 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7454 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7455 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7456 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7457 // Named interceptor properties.
7458 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7459 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7460 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7465 int p_getter_count2;
7468 static void PGetter(Local<String> name,
7469 const v8::PropertyCallbackInfo<v8::Value>& info) {
7470 ApiTestFuzzer::Fuzz();
7472 v8::Handle<v8::Object> global =
7473 info.GetIsolate()->GetCurrentContext()->Global();
7474 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7475 if (name->Equals(v8_str("p1"))) {
7476 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7477 } else if (name->Equals(v8_str("p2"))) {
7478 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7479 } else if (name->Equals(v8_str("p3"))) {
7480 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7481 } else if (name->Equals(v8_str("p4"))) {
7482 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7487 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7488 ApiTestFuzzer::Fuzz();
7489 LocalContext context;
7490 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7492 "o1.__proto__ = { };"
7493 "var o2 = { __proto__: o1 };"
7494 "var o3 = { __proto__: o2 };"
7495 "var o4 = { __proto__: o3 };"
7496 "for (var i = 0; i < 10; i++) o4.p4;"
7497 "for (var i = 0; i < 10; i++) o3.p3;"
7498 "for (var i = 0; i < 10; i++) o2.p2;"
7499 "for (var i = 0; i < 10; i++) o1.p1;");
7503 static void PGetter2(Local<String> name,
7504 const v8::PropertyCallbackInfo<v8::Value>& info) {
7505 ApiTestFuzzer::Fuzz();
7507 v8::Handle<v8::Object> global =
7508 info.GetIsolate()->GetCurrentContext()->Global();
7509 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7510 if (name->Equals(v8_str("p1"))) {
7511 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7512 } else if (name->Equals(v8_str("p2"))) {
7513 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7514 } else if (name->Equals(v8_str("p3"))) {
7515 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7516 } else if (name->Equals(v8_str("p4"))) {
7517 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7522 THREADED_TEST(GetterHolders) {
7523 v8::Isolate* isolate = CcTest::isolate();
7524 v8::HandleScope scope(isolate);
7525 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7526 obj->SetAccessor(v8_str("p1"), PGetter);
7527 obj->SetAccessor(v8_str("p2"), PGetter);
7528 obj->SetAccessor(v8_str("p3"), PGetter);
7529 obj->SetAccessor(v8_str("p4"), PGetter);
7532 CHECK_EQ(40, p_getter_count);
7536 THREADED_TEST(PreInterceptorHolders) {
7537 v8::Isolate* isolate = CcTest::isolate();
7538 v8::HandleScope scope(isolate);
7539 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7540 obj->SetNamedPropertyHandler(PGetter2);
7541 p_getter_count2 = 0;
7543 CHECK_EQ(40, p_getter_count2);
7547 THREADED_TEST(ObjectInstantiation) {
7548 v8::Isolate* isolate = CcTest::isolate();
7549 v8::HandleScope scope(isolate);
7550 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7551 templ->SetAccessor(v8_str("t"), PGetter2);
7552 LocalContext context;
7553 context->Global()->Set(v8_str("o"), templ->NewInstance());
7554 for (int i = 0; i < 100; i++) {
7555 v8::HandleScope inner_scope(CcTest::isolate());
7556 v8::Handle<v8::Object> obj = templ->NewInstance();
7557 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7558 context->Global()->Set(v8_str("o2"), obj);
7559 v8::Handle<Value> value =
7560 CompileRun("o.__proto__ === o2.__proto__");
7561 CHECK_EQ(v8::True(isolate), value);
7562 context->Global()->Set(v8_str("o"), obj);
7567 static int StrCmp16(uint16_t* a, uint16_t* b) {
7569 if (*a == 0 && *b == 0) return 0;
7570 if (*a != *b) return 0 + *a - *b;
7577 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7579 if (n-- == 0) return 0;
7580 if (*a == 0 && *b == 0) return 0;
7581 if (*a != *b) return 0 + *a - *b;
7588 int GetUtf8Length(Handle<String> str) {
7589 int len = str->Utf8Length();
7591 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7592 i::String::Flatten(istr);
7593 len = str->Utf8Length();
7599 THREADED_TEST(StringWrite) {
7600 LocalContext context;
7601 v8::HandleScope scope(context->GetIsolate());
7602 v8::Handle<String> str = v8_str("abcde");
7603 // abc<Icelandic eth><Unicode snowman>.
7604 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7605 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7606 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7607 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7608 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7609 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7610 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7611 // single lead surrogate
7612 uint16_t lead[1] = { 0xd800 };
7613 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7614 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7615 // single trail surrogate
7616 uint16_t trail[1] = { 0xdc00 };
7617 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7618 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7620 uint16_t pair[2] = { 0xd800, 0xdc00 };
7621 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7622 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7623 const int kStride = 4; // Must match stride in for loops in JS below.
7626 "for (var i = 0; i < 0xd800; i += 4) {"
7627 " left = left + String.fromCharCode(i);"
7631 "for (var i = 0; i < 0xd800; i += 4) {"
7632 " right = String.fromCharCode(i) + right;"
7634 v8::Handle<v8::Object> global = context->Global();
7635 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7636 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7638 CHECK_EQ(5, str2->Length());
7639 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7640 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7643 char utf8buf[0xd800 * 3];
7648 memset(utf8buf, 0x1, 1000);
7649 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7651 CHECK_EQ(5, charlen);
7652 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7654 memset(utf8buf, 0x1, 1000);
7655 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7657 CHECK_EQ(5, charlen);
7658 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7660 memset(utf8buf, 0x1, 1000);
7661 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7663 CHECK_EQ(4, charlen);
7664 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7666 memset(utf8buf, 0x1, 1000);
7667 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7669 CHECK_EQ(4, charlen);
7670 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7672 memset(utf8buf, 0x1, 1000);
7673 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7675 CHECK_EQ(4, charlen);
7676 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7678 memset(utf8buf, 0x1, 1000);
7679 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7681 CHECK_EQ(3, charlen);
7682 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7684 memset(utf8buf, 0x1, 1000);
7685 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7687 CHECK_EQ(3, charlen);
7688 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7690 memset(utf8buf, 0x1, 1000);
7691 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7693 CHECK_EQ(2, charlen);
7694 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7696 // allow orphan surrogates by default
7697 memset(utf8buf, 0x1, 1000);
7698 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7700 CHECK_EQ(8, charlen);
7701 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7703 // replace orphan surrogates with unicode replacement character
7704 memset(utf8buf, 0x1, 1000);
7705 len = orphans_str->WriteUtf8(utf8buf,
7708 String::REPLACE_INVALID_UTF8);
7710 CHECK_EQ(8, charlen);
7711 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7713 // replace single lead surrogate with unicode replacement character
7714 memset(utf8buf, 0x1, 1000);
7715 len = lead_str->WriteUtf8(utf8buf,
7718 String::REPLACE_INVALID_UTF8);
7720 CHECK_EQ(1, charlen);
7721 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7723 // replace single trail surrogate with unicode replacement character
7724 memset(utf8buf, 0x1, 1000);
7725 len = trail_str->WriteUtf8(utf8buf,
7728 String::REPLACE_INVALID_UTF8);
7730 CHECK_EQ(1, charlen);
7731 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7733 // do not replace / write anything if surrogate pair does not fit the buffer
7735 memset(utf8buf, 0x1, 1000);
7736 len = pair_str->WriteUtf8(utf8buf,
7739 String::REPLACE_INVALID_UTF8);
7741 CHECK_EQ(0, charlen);
7743 memset(utf8buf, 0x1, sizeof(utf8buf));
7744 len = GetUtf8Length(left_tree);
7746 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7747 CHECK_EQ(utf8_expected, len);
7748 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7749 CHECK_EQ(utf8_expected, len);
7750 CHECK_EQ(0xd800 / kStride, charlen);
7751 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7752 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7753 CHECK_EQ(0xc0 - kStride,
7754 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7755 CHECK_EQ(1, utf8buf[utf8_expected]);
7757 memset(utf8buf, 0x1, sizeof(utf8buf));
7758 len = GetUtf8Length(right_tree);
7759 CHECK_EQ(utf8_expected, len);
7760 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7761 CHECK_EQ(utf8_expected, len);
7762 CHECK_EQ(0xd800 / kStride, charlen);
7763 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7764 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7765 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7766 CHECK_EQ(1, utf8buf[utf8_expected]);
7768 memset(buf, 0x1, sizeof(buf));
7769 memset(wbuf, 0x1, sizeof(wbuf));
7770 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7772 len = str->Write(wbuf);
7774 CHECK_EQ(0, strcmp("abcde", buf));
7775 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7776 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7778 memset(buf, 0x1, sizeof(buf));
7779 memset(wbuf, 0x1, sizeof(wbuf));
7780 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7782 len = str->Write(wbuf, 0, 4);
7784 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7785 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7786 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7788 memset(buf, 0x1, sizeof(buf));
7789 memset(wbuf, 0x1, sizeof(wbuf));
7790 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7792 len = str->Write(wbuf, 0, 5);
7794 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7795 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7796 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7798 memset(buf, 0x1, sizeof(buf));
7799 memset(wbuf, 0x1, sizeof(wbuf));
7800 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7802 len = str->Write(wbuf, 0, 6);
7804 CHECK_EQ(0, strcmp("abcde", buf));
7805 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7806 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7808 memset(buf, 0x1, sizeof(buf));
7809 memset(wbuf, 0x1, sizeof(wbuf));
7810 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7812 len = str->Write(wbuf, 4, -1);
7814 CHECK_EQ(0, strcmp("e", buf));
7815 uint16_t answer5[] = {'e', '\0'};
7816 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7818 memset(buf, 0x1, sizeof(buf));
7819 memset(wbuf, 0x1, sizeof(wbuf));
7820 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7822 len = str->Write(wbuf, 4, 6);
7824 CHECK_EQ(0, strcmp("e", buf));
7825 CHECK_EQ(0, StrCmp16(answer5, 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, strncmp("e\1", buf, 2));
7834 uint16_t answer6[] = {'e', 0x101};
7835 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7837 memset(buf, 0x1, sizeof(buf));
7838 memset(wbuf, 0x1, sizeof(wbuf));
7839 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7841 len = str->Write(wbuf, 3, 1);
7843 CHECK_EQ(0, strncmp("d\1", buf, 2));
7844 uint16_t answer7[] = {'d', 0x101};
7845 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7847 memset(wbuf, 0x1, sizeof(wbuf));
7849 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7851 CHECK_EQ('X', wbuf[5]);
7852 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7853 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7854 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7855 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7857 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7859 memset(buf, 0x1, sizeof(buf));
7861 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7864 String::NO_NULL_TERMINATION);
7866 CHECK_EQ('X', buf[5]);
7867 CHECK_EQ(0, strncmp("abcde", buf, 5));
7868 CHECK_NE(0, strcmp("abcde", buf));
7870 CHECK_EQ(0, strcmp("abcde", buf));
7872 memset(utf8buf, 0x1, sizeof(utf8buf));
7874 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7875 String::NO_NULL_TERMINATION);
7877 CHECK_EQ('X', utf8buf[8]);
7878 CHECK_EQ(5, charlen);
7879 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7880 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7882 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7884 memset(utf8buf, 0x1, sizeof(utf8buf));
7886 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7887 String::NO_NULL_TERMINATION);
7889 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7890 CHECK_EQ(5, charlen);
7892 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7894 memset(buf, 0x1, sizeof(buf));
7895 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7897 CHECK_EQ(0, strcmp("abc", buf));
7898 CHECK_EQ(0, buf[3]);
7899 CHECK_EQ(0, strcmp("def", buf + 4));
7901 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7902 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7903 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7907 static void Utf16Helper(
7908 LocalContext& context,
7910 const char* lengths_name,
7912 Local<v8::Array> a =
7913 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7914 Local<v8::Array> alens =
7915 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7916 for (int i = 0; i < len; i++) {
7917 Local<v8::String> string =
7918 Local<v8::String>::Cast(a->Get(i));
7919 Local<v8::Number> expected_len =
7920 Local<v8::Number>::Cast(alens->Get(i));
7921 int length = GetUtf8Length(string);
7922 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7927 static uint16_t StringGet(Handle<String> str, int index) {
7928 i::Handle<i::String> istring =
7929 v8::Utils::OpenHandle(String::Cast(*str));
7930 return istring->Get(index);
7934 static void WriteUtf8Helper(
7935 LocalContext& context,
7937 const char* lengths_name,
7939 Local<v8::Array> b =
7940 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7941 Local<v8::Array> alens =
7942 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7945 for (int i = 0; i < len; i++) {
7946 Local<v8::String> string =
7947 Local<v8::String>::Cast(b->Get(i));
7948 Local<v8::Number> expected_len =
7949 Local<v8::Number>::Cast(alens->Get(i));
7950 int utf8_length = static_cast<int>(expected_len->Value());
7951 for (int j = utf8_length + 1; j >= 0; j--) {
7952 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7953 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7956 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7958 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7959 CHECK_GE(utf8_length + 1, utf8_written);
7960 CHECK_GE(utf8_length, utf8_written2);
7961 for (int k = 0; k < utf8_written2; k++) {
7962 CHECK_EQ(buffer[k], buffer2[k]);
7964 CHECK(nchars * 3 >= utf8_written - 1);
7965 CHECK(nchars <= utf8_written);
7966 if (j == utf8_length + 1) {
7967 CHECK_EQ(utf8_written2, utf8_length);
7968 CHECK_EQ(utf8_written2 + 1, utf8_written);
7970 CHECK_EQ(buffer[utf8_written], 42);
7971 if (j > utf8_length) {
7972 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7973 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7974 Handle<String> roundtrip = v8_str(buffer);
7975 CHECK(roundtrip->Equals(string));
7977 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7979 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7981 uint16_t trail = StringGet(string, nchars - 1);
7982 uint16_t lead = StringGet(string, nchars - 2);
7983 if (((lead & 0xfc00) == 0xd800) &&
7984 ((trail & 0xfc00) == 0xdc00)) {
7985 unsigned char u1 = buffer2[utf8_written2 - 4];
7986 unsigned char u2 = buffer2[utf8_written2 - 3];
7987 unsigned char u3 = buffer2[utf8_written2 - 2];
7988 unsigned char u4 = buffer2[utf8_written2 - 1];
7989 CHECK_EQ((u1 & 0xf8), 0xf0);
7990 CHECK_EQ((u2 & 0xc0), 0x80);
7991 CHECK_EQ((u3 & 0xc0), 0x80);
7992 CHECK_EQ((u4 & 0xc0), 0x80);
7993 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7994 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7995 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7996 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7997 CHECK_EQ((u1 & 0x3), c >> 18);
8005 THREADED_TEST(Utf16) {
8006 LocalContext context;
8007 v8::HandleScope scope(context->GetIsolate());
8009 "var pad = '01234567890123456789';"
8011 "var plens = [20, 3, 3];"
8012 "p.push('01234567890123456789');"
8013 "var lead = 0xd800;"
8014 "var trail = 0xdc00;"
8015 "p.push(String.fromCharCode(0xd800));"
8016 "p.push(String.fromCharCode(0xdc00));"
8021 "for (var i = 0; i < 3; i++) {"
8022 " p[1] = String.fromCharCode(lead++);"
8023 " for (var j = 0; j < 3; j++) {"
8024 " p[2] = String.fromCharCode(trail++);"
8025 " a.push(p[i] + p[j]);"
8026 " b.push(p[i] + p[j]);"
8027 " c.push(p[i] + p[j]);"
8028 " alens.push(plens[i] + plens[j]);"
8031 "alens[5] -= 2;" // Here the surrogate pairs match up.
8036 "for (var m = 0; m < 9; m++) {"
8037 " for (var n = 0; n < 9; n++) {"
8038 " a2.push(a[m] + a[n]);"
8039 " b2.push(b[m] + b[n]);"
8040 " var newc = 'x' + c[m] + c[n] + 'y';"
8041 " c2.push(newc.substring(1, newc.length - 1));"
8042 " var utf = alens[m] + alens[n];" // And here.
8043 // The 'n's that start with 0xdc.. are 6-8
8044 // The 'm's that end with 0xd8.. are 1, 4 and 7
8045 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8046 " a2lens.push(utf);"
8049 Utf16Helper(context, "a", "alens", 9);
8050 Utf16Helper(context, "a2", "a2lens", 81);
8051 WriteUtf8Helper(context, "b", "alens", 9);
8052 WriteUtf8Helper(context, "b2", "a2lens", 81);
8053 WriteUtf8Helper(context, "c2", "a2lens", 81);
8057 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8058 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8059 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8060 return *is1 == *is2;
8063 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8065 Handle<String> symbol1 =
8066 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8067 Handle<String> symbol2 =
8068 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8069 CHECK(SameSymbol(symbol1, symbol2));
8073 THREADED_TEST(Utf16Symbol) {
8074 LocalContext context;
8075 v8::HandleScope scope(context->GetIsolate());
8077 Handle<String> symbol1 = v8::String::NewFromUtf8(
8078 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8079 Handle<String> symbol2 = v8::String::NewFromUtf8(
8080 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8081 CHECK(SameSymbol(symbol1, symbol2));
8083 SameSymbolHelper(context->GetIsolate(),
8084 "\360\220\220\205", // 4 byte encoding.
8085 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8086 SameSymbolHelper(context->GetIsolate(),
8087 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8088 "\360\220\220\206"); // 4 byte encoding.
8089 SameSymbolHelper(context->GetIsolate(),
8090 "x\360\220\220\205", // 4 byte encoding.
8091 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8092 SameSymbolHelper(context->GetIsolate(),
8093 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8094 "x\360\220\220\206"); // 4 byte encoding.
8096 "var sym0 = 'benedictus';"
8097 "var sym0b = 'S\303\270ren';"
8098 "var sym1 = '\355\240\201\355\260\207';"
8099 "var sym2 = '\360\220\220\210';"
8100 "var sym3 = 'x\355\240\201\355\260\207';"
8101 "var sym4 = 'x\360\220\220\210';"
8102 "if (sym1.length != 2) throw sym1;"
8103 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8104 "if (sym2.length != 2) throw sym2;"
8105 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8106 "if (sym3.length != 3) throw sym3;"
8107 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8108 "if (sym4.length != 3) throw sym4;"
8109 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8110 Handle<String> sym0 = v8::String::NewFromUtf8(
8111 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8112 Handle<String> sym0b = v8::String::NewFromUtf8(
8113 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8114 Handle<String> sym1 =
8115 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8116 v8::String::kInternalizedString);
8117 Handle<String> sym2 =
8118 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8119 v8::String::kInternalizedString);
8120 Handle<String> sym3 = v8::String::NewFromUtf8(
8121 context->GetIsolate(), "x\355\240\201\355\260\207",
8122 v8::String::kInternalizedString);
8123 Handle<String> sym4 =
8124 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8125 v8::String::kInternalizedString);
8126 v8::Local<v8::Object> global = context->Global();
8127 Local<Value> s0 = global->Get(v8_str("sym0"));
8128 Local<Value> s0b = global->Get(v8_str("sym0b"));
8129 Local<Value> s1 = global->Get(v8_str("sym1"));
8130 Local<Value> s2 = global->Get(v8_str("sym2"));
8131 Local<Value> s3 = global->Get(v8_str("sym3"));
8132 Local<Value> s4 = global->Get(v8_str("sym4"));
8133 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8134 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8135 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8136 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8137 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8138 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8142 THREADED_TEST(ToArrayIndex) {
8143 LocalContext context;
8144 v8::Isolate* isolate = context->GetIsolate();
8145 v8::HandleScope scope(isolate);
8147 v8::Handle<String> str = v8_str("42");
8148 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8149 CHECK(!index.IsEmpty());
8150 CHECK_EQ(42.0, index->Uint32Value());
8151 str = v8_str("42asdf");
8152 index = str->ToArrayIndex();
8153 CHECK(index.IsEmpty());
8154 str = v8_str("-42");
8155 index = str->ToArrayIndex();
8156 CHECK(index.IsEmpty());
8157 str = v8_str("4294967295");
8158 index = str->ToArrayIndex();
8159 CHECK(!index.IsEmpty());
8160 CHECK_EQ(4294967295.0, index->Uint32Value());
8161 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8162 index = num->ToArrayIndex();
8163 CHECK(!index.IsEmpty());
8164 CHECK_EQ(1.0, index->Uint32Value());
8165 num = v8::Number::New(isolate, -1);
8166 index = num->ToArrayIndex();
8167 CHECK(index.IsEmpty());
8168 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8169 index = obj->ToArrayIndex();
8170 CHECK(index.IsEmpty());
8174 THREADED_TEST(ErrorConstruction) {
8175 LocalContext context;
8176 v8::HandleScope scope(context->GetIsolate());
8178 v8::Handle<String> foo = v8_str("foo");
8179 v8::Handle<String> message = v8_str("message");
8180 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8181 CHECK(range_error->IsObject());
8182 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8183 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8184 CHECK(reference_error->IsObject());
8185 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8186 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8187 CHECK(syntax_error->IsObject());
8188 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8189 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8190 CHECK(type_error->IsObject());
8191 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8192 v8::Handle<Value> error = v8::Exception::Error(foo);
8193 CHECK(error->IsObject());
8194 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8198 static void YGetter(Local<String> name,
8199 const v8::PropertyCallbackInfo<v8::Value>& info) {
8200 ApiTestFuzzer::Fuzz();
8201 info.GetReturnValue().Set(v8_num(10));
8205 static void YSetter(Local<String> name,
8207 const v8::PropertyCallbackInfo<void>& info) {
8208 Local<Object> this_obj = Local<Object>::Cast(info.This());
8209 if (this_obj->Has(name)) this_obj->Delete(name);
8210 this_obj->Set(name, value);
8214 THREADED_TEST(DeleteAccessor) {
8215 v8::Isolate* isolate = CcTest::isolate();
8216 v8::HandleScope scope(isolate);
8217 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8218 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8219 LocalContext context;
8220 v8::Handle<v8::Object> holder = obj->NewInstance();
8221 context->Global()->Set(v8_str("holder"), holder);
8222 v8::Handle<Value> result = CompileRun(
8223 "holder.y = 11; holder.y = 12; holder.y");
8224 CHECK_EQ(12, result->Uint32Value());
8228 THREADED_TEST(TypeSwitch) {
8229 v8::Isolate* isolate = CcTest::isolate();
8230 v8::HandleScope scope(isolate);
8231 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8232 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8233 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8234 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8235 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8236 LocalContext context;
8237 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8238 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8239 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8240 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8241 for (int i = 0; i < 10; i++) {
8242 CHECK_EQ(0, type_switch->match(obj0));
8243 CHECK_EQ(1, type_switch->match(obj1));
8244 CHECK_EQ(2, type_switch->match(obj2));
8245 CHECK_EQ(3, type_switch->match(obj3));
8246 CHECK_EQ(3, type_switch->match(obj3));
8247 CHECK_EQ(2, type_switch->match(obj2));
8248 CHECK_EQ(1, type_switch->match(obj1));
8249 CHECK_EQ(0, type_switch->match(obj0));
8254 static int trouble_nesting = 0;
8255 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8256 ApiTestFuzzer::Fuzz();
8259 // Call a JS function that throws an uncaught exception.
8260 Local<v8::Object> arg_this =
8261 args.GetIsolate()->GetCurrentContext()->Global();
8262 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8263 arg_this->Get(v8_str("trouble_callee")) :
8264 arg_this->Get(v8_str("trouble_caller"));
8265 CHECK(trouble_callee->IsFunction());
8266 args.GetReturnValue().Set(
8267 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8271 static int report_count = 0;
8272 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8273 v8::Handle<Value>) {
8278 // Counts uncaught exceptions, but other tests running in parallel
8279 // also have uncaught exceptions.
8280 TEST(ApiUncaughtException) {
8283 v8::Isolate* isolate = env->GetIsolate();
8284 v8::HandleScope scope(isolate);
8285 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8287 Local<v8::FunctionTemplate> fun =
8288 v8::FunctionTemplate::New(isolate, TroubleCallback);
8289 v8::Local<v8::Object> global = env->Global();
8290 global->Set(v8_str("trouble"), fun->GetFunction());
8293 "function trouble_callee() {"
8297 "function trouble_caller() {"
8300 Local<Value> trouble = global->Get(v8_str("trouble"));
8301 CHECK(trouble->IsFunction());
8302 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8303 CHECK(trouble_callee->IsFunction());
8304 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8305 CHECK(trouble_caller->IsFunction());
8306 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8307 CHECK_EQ(1, report_count);
8308 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8311 static const char* script_resource_name = "ExceptionInNativeScript.js";
8312 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8313 v8::Handle<Value>) {
8314 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8315 CHECK(!name_val.IsEmpty() && name_val->IsString());
8316 v8::String::Utf8Value name(message->GetScriptResourceName());
8317 CHECK_EQ(script_resource_name, *name);
8318 CHECK_EQ(3, message->GetLineNumber());
8319 v8::String::Utf8Value source_line(message->GetSourceLine());
8320 CHECK_EQ(" new o.foo();", *source_line);
8324 TEST(ExceptionInNativeScript) {
8326 v8::Isolate* isolate = env->GetIsolate();
8327 v8::HandleScope scope(isolate);
8328 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8330 Local<v8::FunctionTemplate> fun =
8331 v8::FunctionTemplate::New(isolate, TroubleCallback);
8332 v8::Local<v8::Object> global = env->Global();
8333 global->Set(v8_str("trouble"), fun->GetFunction());
8335 CompileRunWithOrigin(
8336 "function trouble() {\n"
8340 script_resource_name);
8341 Local<Value> trouble = global->Get(v8_str("trouble"));
8342 CHECK(trouble->IsFunction());
8343 Function::Cast(*trouble)->Call(global, 0, NULL);
8344 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8348 TEST(CompilationErrorUsingTryCatchHandler) {
8350 v8::HandleScope scope(env->GetIsolate());
8351 v8::TryCatch try_catch;
8352 v8_compile("This doesn't &*&@#$&*^ compile.");
8353 CHECK_NE(NULL, *try_catch.Exception());
8354 CHECK(try_catch.HasCaught());
8358 TEST(TryCatchFinallyUsingTryCatchHandler) {
8360 v8::HandleScope scope(env->GetIsolate());
8361 v8::TryCatch try_catch;
8362 CompileRun("try { throw ''; } catch (e) {}");
8363 CHECK(!try_catch.HasCaught());
8364 CompileRun("try { throw ''; } finally {}");
8365 CHECK(try_catch.HasCaught());
8369 "try { throw ''; } finally { return; }"
8371 CHECK(!try_catch.HasCaught());
8374 " { try { throw ''; } finally { throw 0; }"
8376 CHECK(try_catch.HasCaught());
8380 // For use within the TestSecurityHandler() test.
8381 static bool g_security_callback_result = false;
8382 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8384 v8::AccessType type,
8385 Local<Value> data) {
8387 // Always allow read access.
8388 if (type == v8::ACCESS_GET)
8391 // Sometimes allow other access.
8392 return g_security_callback_result;
8396 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8398 v8::AccessType type,
8399 Local<Value> data) {
8401 // Always allow read access.
8402 if (type == v8::ACCESS_GET)
8405 // Sometimes allow other access.
8406 return g_security_callback_result;
8410 // SecurityHandler can't be run twice
8411 TEST(SecurityHandler) {
8412 v8::Isolate* isolate = CcTest::isolate();
8413 v8::HandleScope scope0(isolate);
8414 v8::Handle<v8::ObjectTemplate> global_template =
8415 v8::ObjectTemplate::New(isolate);
8416 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8417 IndexedSecurityTestCallback);
8418 // Create an environment
8419 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8422 v8::Handle<v8::Object> global0 = context0->Global();
8423 v8::Handle<Script> script0 = v8_compile("foo = 111");
8425 global0->Set(v8_str("0"), v8_num(999));
8426 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8427 CHECK_EQ(111, foo0->Int32Value());
8428 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8429 CHECK_EQ(999, z0->Int32Value());
8431 // Create another environment, should fail security checks.
8432 v8::HandleScope scope1(isolate);
8434 v8::Handle<Context> context1 =
8435 Context::New(isolate, NULL, global_template);
8438 v8::Handle<v8::Object> global1 = context1->Global();
8439 global1->Set(v8_str("othercontext"), global0);
8440 // This set will fail the security check.
8441 v8::Handle<Script> script1 =
8442 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8444 // This read will pass the security check.
8445 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8446 CHECK_EQ(111, foo1->Int32Value());
8447 // This read will pass the security check.
8448 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8449 CHECK_EQ(999, z1->Int32Value());
8451 // Create another environment, should pass security checks.
8452 { g_security_callback_result = true; // allow security handler to pass.
8453 v8::HandleScope scope2(isolate);
8454 LocalContext context2;
8455 v8::Handle<v8::Object> global2 = context2->Global();
8456 global2->Set(v8_str("othercontext"), global0);
8457 v8::Handle<Script> script2 =
8458 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8460 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8461 CHECK_EQ(333, foo2->Int32Value());
8462 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8463 CHECK_EQ(888, z2->Int32Value());
8471 THREADED_TEST(SecurityChecks) {
8473 v8::HandleScope handle_scope(env1->GetIsolate());
8474 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8476 Local<Value> foo = v8_str("foo");
8477 Local<Value> bar = v8_str("bar");
8479 // Set to the same domain.
8480 env1->SetSecurityToken(foo);
8482 // Create a function in env1.
8483 CompileRun("spy=function(){return spy;}");
8484 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8485 CHECK(spy->IsFunction());
8487 // Create another function accessing global objects.
8488 CompileRun("spy2=function(){return new this.Array();}");
8489 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8490 CHECK(spy2->IsFunction());
8492 // Switch to env2 in the same domain and invoke spy on env2.
8494 env2->SetSecurityToken(foo);
8496 Context::Scope scope_env2(env2);
8497 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8498 CHECK(result->IsFunction());
8502 env2->SetSecurityToken(bar);
8503 Context::Scope scope_env2(env2);
8505 // Call cross_domain_call, it should throw an exception
8506 v8::TryCatch try_catch;
8507 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8508 CHECK(try_catch.HasCaught());
8513 // Regression test case for issue 1183439.
8514 THREADED_TEST(SecurityChecksForPrototypeChain) {
8515 LocalContext current;
8516 v8::HandleScope scope(current->GetIsolate());
8517 v8::Handle<Context> other = Context::New(current->GetIsolate());
8519 // Change context to be able to get to the Object function in the
8520 // other context without hitting the security checks.
8521 v8::Local<Value> other_object;
8522 { Context::Scope scope(other);
8523 other_object = other->Global()->Get(v8_str("Object"));
8524 other->Global()->Set(v8_num(42), v8_num(87));
8527 current->Global()->Set(v8_str("other"), other->Global());
8528 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8530 // Make sure the security check fails here and we get an undefined
8531 // result instead of getting the Object function. Repeat in a loop
8532 // to make sure to exercise the IC code.
8533 v8::Local<Script> access_other0 = v8_compile("other.Object");
8534 v8::Local<Script> access_other1 = v8_compile("other[42]");
8535 for (int i = 0; i < 5; i++) {
8536 CHECK(!access_other0->Run()->Equals(other_object));
8537 CHECK(access_other0->Run()->IsUndefined());
8538 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8539 CHECK(access_other1->Run()->IsUndefined());
8542 // Create an object that has 'other' in its prototype chain and make
8543 // sure we cannot access the Object function indirectly through
8544 // that. Repeat in a loop to make sure to exercise the IC code.
8545 v8_compile("function F() { };"
8546 "F.prototype = other;"
8547 "var f = new F();")->Run();
8548 v8::Local<Script> access_f0 = v8_compile("f.Object");
8549 v8::Local<Script> access_f1 = v8_compile("f[42]");
8550 for (int j = 0; j < 5; j++) {
8551 CHECK(!access_f0->Run()->Equals(other_object));
8552 CHECK(access_f0->Run()->IsUndefined());
8553 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8554 CHECK(access_f1->Run()->IsUndefined());
8557 // Now it gets hairy: Set the prototype for the other global object
8558 // to be the current global object. The prototype chain for 'f' now
8559 // goes through 'other' but ends up in the current global object.
8560 { Context::Scope scope(other);
8561 other->Global()->Set(v8_str("__proto__"), current->Global());
8563 // Set a named and an index property on the current global
8564 // object. To force the lookup to go through the other global object,
8565 // the properties must not exist in the other global object.
8566 current->Global()->Set(v8_str("foo"), v8_num(100));
8567 current->Global()->Set(v8_num(99), v8_num(101));
8568 // Try to read the properties from f and make sure that the access
8569 // gets stopped by the security checks on the other global object.
8570 Local<Script> access_f2 = v8_compile("f.foo");
8571 Local<Script> access_f3 = v8_compile("f[99]");
8572 for (int k = 0; k < 5; k++) {
8573 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8574 CHECK(access_f2->Run()->IsUndefined());
8575 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8576 CHECK(access_f3->Run()->IsUndefined());
8581 static bool named_security_check_with_gc_called;
8583 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8585 v8::AccessType type,
8586 Local<Value> data) {
8587 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8588 named_security_check_with_gc_called = true;
8593 static bool indexed_security_check_with_gc_called;
8595 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8597 v8::AccessType type,
8598 Local<Value> data) {
8599 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8600 indexed_security_check_with_gc_called = true;
8605 TEST(SecurityTestGCAllowed) {
8606 v8::Isolate* isolate = CcTest::isolate();
8607 v8::HandleScope handle_scope(isolate);
8608 v8::Handle<v8::ObjectTemplate> object_template =
8609 v8::ObjectTemplate::New(isolate);
8610 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8611 IndexedSecurityTestCallbackWithGC);
8613 v8::Handle<Context> context = Context::New(isolate);
8614 v8::Context::Scope context_scope(context);
8616 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8618 named_security_check_with_gc_called = false;
8619 CompileRun("obj.foo = new String(1001);");
8620 CHECK(named_security_check_with_gc_called);
8622 indexed_security_check_with_gc_called = false;
8623 CompileRun("obj[0] = new String(1002);");
8624 CHECK(indexed_security_check_with_gc_called);
8626 named_security_check_with_gc_called = false;
8627 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8628 CHECK(named_security_check_with_gc_called);
8630 indexed_security_check_with_gc_called = false;
8631 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8632 CHECK(indexed_security_check_with_gc_called);
8636 THREADED_TEST(CrossDomainDelete) {
8638 v8::HandleScope handle_scope(env1->GetIsolate());
8639 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8641 Local<Value> foo = v8_str("foo");
8642 Local<Value> bar = v8_str("bar");
8644 // Set to the same domain.
8645 env1->SetSecurityToken(foo);
8646 env2->SetSecurityToken(foo);
8648 env1->Global()->Set(v8_str("prop"), v8_num(3));
8649 env2->Global()->Set(v8_str("env1"), env1->Global());
8651 // Change env2 to a different domain and delete env1.prop.
8652 env2->SetSecurityToken(bar);
8654 Context::Scope scope_env2(env2);
8655 Local<Value> result =
8656 CompileRun("delete env1.prop");
8657 CHECK(result->IsFalse());
8660 // Check that env1.prop still exists.
8661 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8662 CHECK(v->IsNumber());
8663 CHECK_EQ(3, v->Int32Value());
8667 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8669 v8::HandleScope handle_scope(env1->GetIsolate());
8670 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8672 Local<Value> foo = v8_str("foo");
8673 Local<Value> bar = v8_str("bar");
8675 // Set to the same domain.
8676 env1->SetSecurityToken(foo);
8677 env2->SetSecurityToken(foo);
8679 env1->Global()->Set(v8_str("prop"), v8_num(3));
8680 env2->Global()->Set(v8_str("env1"), env1->Global());
8682 // env1.prop is enumerable in env2.
8683 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8685 Context::Scope scope_env2(env2);
8686 Local<Value> result = CompileRun(test);
8687 CHECK(result->IsTrue());
8690 // Change env2 to a different domain and test again.
8691 env2->SetSecurityToken(bar);
8693 Context::Scope scope_env2(env2);
8694 Local<Value> result = CompileRun(test);
8695 CHECK(result->IsFalse());
8700 THREADED_TEST(CrossDomainForIn) {
8702 v8::HandleScope handle_scope(env1->GetIsolate());
8703 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8705 Local<Value> foo = v8_str("foo");
8706 Local<Value> bar = v8_str("bar");
8708 // Set to the same domain.
8709 env1->SetSecurityToken(foo);
8710 env2->SetSecurityToken(foo);
8712 env1->Global()->Set(v8_str("prop"), v8_num(3));
8713 env2->Global()->Set(v8_str("env1"), env1->Global());
8715 // Change env2 to a different domain and set env1's global object
8716 // as the __proto__ of an object in env2 and enumerate properties
8717 // in for-in. It shouldn't enumerate properties on env1's global
8719 env2->SetSecurityToken(bar);
8721 Context::Scope scope_env2(env2);
8722 Local<Value> result =
8723 CompileRun("(function(){var obj = {'__proto__':env1};"
8724 "for (var p in obj)"
8725 " if (p == 'prop') return false;"
8726 "return true;})()");
8727 CHECK(result->IsTrue());
8732 TEST(ContextDetachGlobal) {
8734 v8::HandleScope handle_scope(env1->GetIsolate());
8735 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8737 Local<v8::Object> global1 = env1->Global();
8739 Local<Value> foo = v8_str("foo");
8741 // Set to the same domain.
8742 env1->SetSecurityToken(foo);
8743 env2->SetSecurityToken(foo);
8748 // Create a function in env2 and add a reference to it in env1.
8749 Local<v8::Object> global2 = env2->Global();
8750 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8751 CompileRun("function getProp() {return prop;}");
8753 env1->Global()->Set(v8_str("getProp"),
8754 global2->Get(v8_str("getProp")));
8756 // Detach env2's global, and reuse the global object of env2
8758 env2->DetachGlobal();
8760 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8762 v8::Handle<v8::ObjectTemplate>(),
8764 env3->SetSecurityToken(v8_str("bar"));
8767 Local<v8::Object> global3 = env3->Global();
8768 CHECK_EQ(global2, global3);
8769 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8770 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8771 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8772 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8775 // Call getProp in env1, and it should return the value 1
8777 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8778 CHECK(get_prop->IsFunction());
8779 v8::TryCatch try_catch;
8780 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8781 CHECK(!try_catch.HasCaught());
8782 CHECK_EQ(1, r->Int32Value());
8785 // Check that env3 is not accessible from env1
8787 Local<Value> r = global3->Get(v8_str("prop2"));
8788 CHECK(r->IsUndefined());
8793 TEST(DetachGlobal) {
8795 v8::HandleScope scope(env1->GetIsolate());
8797 // Create second environment.
8798 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8800 Local<Value> foo = v8_str("foo");
8802 // Set same security token for env1 and env2.
8803 env1->SetSecurityToken(foo);
8804 env2->SetSecurityToken(foo);
8806 // Create a property on the global object in env2.
8808 v8::Context::Scope scope(env2);
8809 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8812 // Create a reference to env2 global from env1 global.
8813 env1->Global()->Set(v8_str("other"), env2->Global());
8815 // Check that we have access to other.p in env2 from env1.
8816 Local<Value> result = CompileRun("other.p");
8817 CHECK(result->IsInt32());
8818 CHECK_EQ(42, result->Int32Value());
8820 // Hold on to global from env2 and detach global from env2.
8821 Local<v8::Object> global2 = env2->Global();
8822 env2->DetachGlobal();
8824 // Check that the global has been detached. No other.p property can
8826 result = CompileRun("other.p");
8827 CHECK(result->IsUndefined());
8829 // Reuse global2 for env3.
8830 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8832 v8::Handle<v8::ObjectTemplate>(),
8834 CHECK_EQ(global2, env3->Global());
8836 // Start by using the same security token for env3 as for env1 and env2.
8837 env3->SetSecurityToken(foo);
8839 // Create a property on the global object in env3.
8841 v8::Context::Scope scope(env3);
8842 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8845 // Check that other.p is now the property in env3 and that we have access.
8846 result = CompileRun("other.p");
8847 CHECK(result->IsInt32());
8848 CHECK_EQ(24, result->Int32Value());
8850 // Change security token for env3 to something different from env1 and env2.
8851 env3->SetSecurityToken(v8_str("bar"));
8853 // Check that we do not have access to other.p in env1. |other| is now
8854 // the global object for env3 which has a different security token,
8855 // so access should be blocked.
8856 result = CompileRun("other.p");
8857 CHECK(result->IsUndefined());
8861 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8862 info.GetReturnValue().Set(
8863 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8867 TEST(DetachedAccesses) {
8869 v8::HandleScope scope(env1->GetIsolate());
8871 // Create second environment.
8872 Local<ObjectTemplate> inner_global_template =
8873 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8874 inner_global_template ->SetAccessorProperty(
8875 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8876 v8::Local<Context> env2 =
8877 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8879 Local<Value> foo = v8_str("foo");
8881 // Set same security token for env1 and env2.
8882 env1->SetSecurityToken(foo);
8883 env2->SetSecurityToken(foo);
8885 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8888 v8::Context::Scope scope(env2);
8889 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8891 "function bound_x() { return x; }"
8892 "function get_x() { return this.x; }"
8893 "function get_x_w() { return (function() {return this.x;})(); }");
8894 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8895 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8896 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8897 env1->Global()->Set(
8899 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8902 Local<Object> env2_global = env2->Global();
8903 env2_global->TurnOnAccessCheck();
8904 env2->DetachGlobal();
8906 Local<Value> result;
8907 result = CompileRun("bound_x()");
8908 CHECK_EQ(v8_str("env2_x"), result);
8909 result = CompileRun("get_x()");
8910 CHECK(result->IsUndefined());
8911 result = CompileRun("get_x_w()");
8912 CHECK(result->IsUndefined());
8913 result = CompileRun("this_x()");
8914 CHECK_EQ(v8_str("env2_x"), result);
8916 // Reattach env2's proxy
8917 env2 = Context::New(env1->GetIsolate(),
8919 v8::Handle<v8::ObjectTemplate>(),
8921 env2->SetSecurityToken(foo);
8923 v8::Context::Scope scope(env2);
8924 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8925 env2->Global()->Set(v8_str("env1"), env1->Global());
8926 result = CompileRun(
8928 "for (var i = 0; i < 4; i++ ) {"
8929 " results.push(env1.bound_x());"
8930 " results.push(env1.get_x());"
8931 " results.push(env1.get_x_w());"
8932 " results.push(env1.this_x());"
8935 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8936 CHECK_EQ(16, results->Length());
8937 for (int i = 0; i < 16; i += 4) {
8938 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8939 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8940 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8941 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8945 result = CompileRun(
8947 "for (var i = 0; i < 4; i++ ) {"
8948 " results.push(bound_x());"
8949 " results.push(get_x());"
8950 " results.push(get_x_w());"
8951 " results.push(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("env3_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));
8963 result = CompileRun(
8965 "for (var i = 0; i < 4; i++ ) {"
8966 " results.push(this.bound_x());"
8967 " results.push(this.get_x());"
8968 " results.push(this.get_x_w());"
8969 " results.push(this.this_x());"
8972 results = Local<v8::Array>::Cast(result);
8973 CHECK_EQ(16, results->Length());
8974 for (int i = 0; i < 16; i += 4) {
8975 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8976 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8977 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8978 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8983 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8984 static bool NamedAccessBlocker(Local<v8::Object> global,
8986 v8::AccessType type,
8987 Local<Value> data) {
8988 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8989 allowed_access_type[type];
8993 static bool IndexedAccessBlocker(Local<v8::Object> global,
8995 v8::AccessType type,
8996 Local<Value> data) {
8997 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8998 allowed_access_type[type];
9002 static int g_echo_value_1 = -1;
9003 static int g_echo_value_2 = -1;
9006 static void EchoGetter(
9008 const v8::PropertyCallbackInfo<v8::Value>& info) {
9009 info.GetReturnValue().Set(v8_num(g_echo_value_1));
9013 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9014 info.GetReturnValue().Set(v8_num(g_echo_value_2));
9018 static void EchoSetter(Local<String> name,
9020 const v8::PropertyCallbackInfo<void>&) {
9021 if (value->IsNumber())
9022 g_echo_value_1 = value->Int32Value();
9026 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9027 v8::Handle<v8::Value> value = info[0];
9028 if (value->IsNumber())
9029 g_echo_value_2 = value->Int32Value();
9033 static void UnreachableGetter(
9035 const v8::PropertyCallbackInfo<v8::Value>& info) {
9036 CHECK(false); // This function should not be called..
9040 static void UnreachableSetter(Local<String>,
9042 const v8::PropertyCallbackInfo<void>&) {
9043 CHECK(false); // This function should nto be called.
9047 static void UnreachableFunction(
9048 const v8::FunctionCallbackInfo<v8::Value>& info) {
9049 CHECK(false); // This function should not be called..
9053 TEST(AccessControl) {
9054 v8::Isolate* isolate = CcTest::isolate();
9055 v8::HandleScope handle_scope(isolate);
9056 v8::Handle<v8::ObjectTemplate> global_template =
9057 v8::ObjectTemplate::New(isolate);
9059 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9060 IndexedAccessBlocker);
9062 // Add an accessor accessible by cross-domain JS code.
9063 global_template->SetAccessor(
9064 v8_str("accessible_prop"),
9065 EchoGetter, EchoSetter,
9066 v8::Handle<Value>(),
9067 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9070 global_template->SetAccessorProperty(
9071 v8_str("accessible_js_prop"),
9072 v8::FunctionTemplate::New(isolate, EchoGetter),
9073 v8::FunctionTemplate::New(isolate, EchoSetter),
9075 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9077 // Add an accessor that is not accessible by cross-domain JS code.
9078 global_template->SetAccessor(v8_str("blocked_prop"),
9079 UnreachableGetter, UnreachableSetter,
9080 v8::Handle<Value>(),
9083 global_template->SetAccessorProperty(
9084 v8_str("blocked_js_prop"),
9085 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9086 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9090 // Create an environment
9091 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9094 v8::Handle<v8::Object> global0 = context0->Global();
9096 // Define a property with JS getter and setter.
9098 "function getter() { return 'getter'; };\n"
9099 "function setter() { return 'setter'; }\n"
9100 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9102 Local<Value> getter = global0->Get(v8_str("getter"));
9103 Local<Value> setter = global0->Get(v8_str("setter"));
9105 // And define normal element.
9106 global0->Set(239, v8_str("239"));
9108 // Define an element with JS getter and setter.
9110 "function el_getter() { return 'el_getter'; };\n"
9111 "function el_setter() { return 'el_setter'; };\n"
9112 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9114 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9115 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9117 v8::HandleScope scope1(isolate);
9119 v8::Local<Context> context1 = Context::New(isolate);
9122 v8::Handle<v8::Object> global1 = context1->Global();
9123 global1->Set(v8_str("other"), global0);
9125 // Access blocked property.
9126 CompileRun("other.blocked_prop = 1");
9128 ExpectUndefined("other.blocked_prop");
9130 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9131 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9133 // Enable ACCESS_HAS
9134 allowed_access_type[v8::ACCESS_HAS] = true;
9135 ExpectUndefined("other.blocked_prop");
9136 // ... and now we can get the descriptor...
9138 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9139 // ... and enumerate the property.
9140 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9141 allowed_access_type[v8::ACCESS_HAS] = false;
9143 // Access blocked element.
9144 CompileRun("other[239] = 1");
9146 ExpectUndefined("other[239]");
9147 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9148 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9150 // Enable ACCESS_HAS
9151 allowed_access_type[v8::ACCESS_HAS] = true;
9152 ExpectUndefined("other[239]");
9153 // ... and now we can get the descriptor...
9154 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9155 // ... and enumerate the property.
9156 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9157 allowed_access_type[v8::ACCESS_HAS] = false;
9159 // Access a property with JS accessor.
9160 CompileRun("other.js_accessor_p = 2");
9162 ExpectUndefined("other.js_accessor_p");
9164 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9166 // Enable ACCESS_HAS.
9167 allowed_access_type[v8::ACCESS_HAS] = true;
9168 ExpectUndefined("other.js_accessor_p");
9170 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9172 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9174 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9175 allowed_access_type[v8::ACCESS_HAS] = false;
9177 // Enable both ACCESS_HAS and ACCESS_GET.
9178 allowed_access_type[v8::ACCESS_HAS] = true;
9179 allowed_access_type[v8::ACCESS_GET] = true;
9181 ExpectString("other.js_accessor_p", "getter");
9183 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9185 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9187 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9189 allowed_access_type[v8::ACCESS_GET] = false;
9190 allowed_access_type[v8::ACCESS_HAS] = false;
9192 // Enable both ACCESS_HAS and ACCESS_SET.
9193 allowed_access_type[v8::ACCESS_HAS] = true;
9194 allowed_access_type[v8::ACCESS_SET] = true;
9196 ExpectUndefined("other.js_accessor_p");
9198 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9200 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9202 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9204 allowed_access_type[v8::ACCESS_SET] = false;
9205 allowed_access_type[v8::ACCESS_HAS] = false;
9207 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9208 allowed_access_type[v8::ACCESS_HAS] = true;
9209 allowed_access_type[v8::ACCESS_GET] = true;
9210 allowed_access_type[v8::ACCESS_SET] = true;
9212 ExpectString("other.js_accessor_p", "getter");
9214 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9216 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9218 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9220 allowed_access_type[v8::ACCESS_SET] = false;
9221 allowed_access_type[v8::ACCESS_GET] = false;
9222 allowed_access_type[v8::ACCESS_HAS] = false;
9224 // Access an element with JS accessor.
9225 CompileRun("other[42] = 2");
9227 ExpectUndefined("other[42]");
9228 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9230 // Enable ACCESS_HAS.
9231 allowed_access_type[v8::ACCESS_HAS] = true;
9232 ExpectUndefined("other[42]");
9233 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9234 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9235 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9236 allowed_access_type[v8::ACCESS_HAS] = false;
9238 // Enable both ACCESS_HAS and ACCESS_GET.
9239 allowed_access_type[v8::ACCESS_HAS] = true;
9240 allowed_access_type[v8::ACCESS_GET] = true;
9242 ExpectString("other[42]", "el_getter");
9243 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9244 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9245 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9247 allowed_access_type[v8::ACCESS_GET] = false;
9248 allowed_access_type[v8::ACCESS_HAS] = false;
9250 // Enable both ACCESS_HAS and ACCESS_SET.
9251 allowed_access_type[v8::ACCESS_HAS] = true;
9252 allowed_access_type[v8::ACCESS_SET] = true;
9254 ExpectUndefined("other[42]");
9255 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9256 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9257 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9259 allowed_access_type[v8::ACCESS_SET] = false;
9260 allowed_access_type[v8::ACCESS_HAS] = false;
9262 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9263 allowed_access_type[v8::ACCESS_HAS] = true;
9264 allowed_access_type[v8::ACCESS_GET] = true;
9265 allowed_access_type[v8::ACCESS_SET] = true;
9267 ExpectString("other[42]", "el_getter");
9268 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9269 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9270 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9272 allowed_access_type[v8::ACCESS_SET] = false;
9273 allowed_access_type[v8::ACCESS_GET] = false;
9274 allowed_access_type[v8::ACCESS_HAS] = false;
9276 v8::Handle<Value> value;
9278 // Access accessible property
9279 value = CompileRun("other.accessible_prop = 3");
9280 CHECK(value->IsNumber());
9281 CHECK_EQ(3, value->Int32Value());
9282 CHECK_EQ(3, g_echo_value_1);
9284 // Access accessible js property
9285 value = CompileRun("other.accessible_js_prop = 3");
9286 CHECK(value->IsNumber());
9287 CHECK_EQ(3, value->Int32Value());
9288 CHECK_EQ(3, g_echo_value_2);
9290 value = CompileRun("other.accessible_prop");
9291 CHECK(value->IsNumber());
9292 CHECK_EQ(3, value->Int32Value());
9294 value = CompileRun("other.accessible_js_prop");
9295 CHECK(value->IsNumber());
9296 CHECK_EQ(3, value->Int32Value());
9299 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9300 CHECK(value->IsNumber());
9301 CHECK_EQ(3, value->Int32Value());
9304 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9305 CHECK(value->IsNumber());
9306 CHECK_EQ(3, value->Int32Value());
9308 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9309 CHECK(value->IsTrue());
9311 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9312 CHECK(value->IsTrue());
9314 // Enumeration doesn't enumerate accessors from inaccessible objects in
9315 // the prototype chain even if the accessors are in themselves accessible.
9317 CompileRun("(function(){var obj = {'__proto__':other};"
9318 "for (var p in obj)"
9319 " if (p == 'accessible_prop' ||"
9320 " p == 'accessible_js_prop' ||"
9321 " p == 'blocked_js_prop' ||"
9322 " p == 'blocked_js_prop') {"
9325 "return true;})()");
9326 CHECK(value->IsTrue());
9333 TEST(AccessControlES5) {
9334 v8::Isolate* isolate = CcTest::isolate();
9335 v8::HandleScope handle_scope(isolate);
9336 v8::Handle<v8::ObjectTemplate> global_template =
9337 v8::ObjectTemplate::New(isolate);
9339 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9340 IndexedAccessBlocker);
9342 // Add accessible accessor.
9343 global_template->SetAccessor(
9344 v8_str("accessible_prop"),
9345 EchoGetter, EchoSetter,
9346 v8::Handle<Value>(),
9347 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9350 // Add an accessor that is not accessible by cross-domain JS code.
9351 global_template->SetAccessor(v8_str("blocked_prop"),
9352 UnreachableGetter, UnreachableSetter,
9353 v8::Handle<Value>(),
9356 // Create an environment
9357 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9360 v8::Handle<v8::Object> global0 = context0->Global();
9362 v8::Local<Context> context1 = Context::New(isolate);
9364 v8::Handle<v8::Object> global1 = context1->Global();
9365 global1->Set(v8_str("other"), global0);
9367 // Regression test for issue 1154.
9368 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9370 ExpectUndefined("other.blocked_prop");
9372 // Regression test for issue 1027.
9373 CompileRun("Object.defineProperty(\n"
9374 " other, 'blocked_prop', {configurable: false})");
9375 ExpectUndefined("other.blocked_prop");
9377 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9379 // Regression test for issue 1171.
9380 ExpectTrue("Object.isExtensible(other)");
9381 CompileRun("Object.preventExtensions(other)");
9382 ExpectTrue("Object.isExtensible(other)");
9384 // Object.seal and Object.freeze.
9385 CompileRun("Object.freeze(other)");
9386 ExpectTrue("Object.isExtensible(other)");
9388 CompileRun("Object.seal(other)");
9389 ExpectTrue("Object.isExtensible(other)");
9391 // Regression test for issue 1250.
9392 // Make sure that we can set the accessible accessors value using normal
9394 CompileRun("other.accessible_prop = 42");
9395 CHECK_EQ(42, g_echo_value_1);
9397 v8::Handle<Value> value;
9398 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9399 value = CompileRun("other.accessible_prop == 42");
9400 CHECK(value->IsTrue());
9404 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9406 v8::AccessType type,
9407 Local<Value> data) {
9412 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9414 v8::AccessType type,
9415 Local<Value> data) {
9420 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9421 v8::Isolate* isolate = CcTest::isolate();
9422 v8::HandleScope handle_scope(isolate);
9423 v8::Handle<v8::ObjectTemplate> obj_template =
9424 v8::ObjectTemplate::New(isolate);
9426 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9427 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9428 GetOwnPropertyNamesIndexedBlocker);
9430 // Create an environment
9431 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9434 v8::Handle<v8::Object> global0 = context0->Global();
9436 v8::HandleScope scope1(CcTest::isolate());
9438 v8::Local<Context> context1 = Context::New(isolate);
9441 v8::Handle<v8::Object> global1 = context1->Global();
9442 global1->Set(v8_str("other"), global0);
9443 global1->Set(v8_str("object"), obj_template->NewInstance());
9445 v8::Handle<Value> value;
9447 // Attempt to get the property names of the other global object and
9448 // of an object that requires access checks. Accessing the other
9449 // global object should be blocked by access checks on the global
9450 // proxy object. Accessing the object that requires access checks
9451 // is blocked by the access checks on the object itself.
9452 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9453 CHECK(value->IsTrue());
9455 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9456 CHECK(value->IsTrue());
9463 static void IndexedPropertyEnumerator(
9464 const v8::PropertyCallbackInfo<v8::Array>& info) {
9465 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9466 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9467 result->Set(1, v8::Object::New(info.GetIsolate()));
9468 info.GetReturnValue().Set(result);
9472 static void NamedPropertyEnumerator(
9473 const v8::PropertyCallbackInfo<v8::Array>& info) {
9474 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9475 result->Set(0, v8_str("x"));
9476 result->Set(1, v8::Object::New(info.GetIsolate()));
9477 info.GetReturnValue().Set(result);
9481 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9482 v8::Isolate* isolate = CcTest::isolate();
9483 v8::HandleScope handle_scope(isolate);
9484 v8::Handle<v8::ObjectTemplate> obj_template =
9485 v8::ObjectTemplate::New(isolate);
9487 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9488 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9489 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9490 IndexedPropertyEnumerator);
9491 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9492 NamedPropertyEnumerator);
9494 LocalContext context;
9495 v8::Handle<v8::Object> global = context->Global();
9496 global->Set(v8_str("object"), obj_template->NewInstance());
9498 v8::Handle<v8::Value> result =
9499 CompileRun("Object.getOwnPropertyNames(object)");
9500 CHECK(result->IsArray());
9501 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9502 CHECK_EQ(3, result_array->Length());
9503 CHECK(result_array->Get(0)->IsString());
9504 CHECK(result_array->Get(1)->IsString());
9505 CHECK(result_array->Get(2)->IsString());
9506 CHECK_EQ(v8_str("7"), result_array->Get(0));
9507 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9508 CHECK_EQ(v8_str("x"), result_array->Get(2));
9512 static void ConstTenGetter(Local<String> name,
9513 const v8::PropertyCallbackInfo<v8::Value>& info) {
9514 info.GetReturnValue().Set(v8_num(10));
9518 THREADED_TEST(CrossDomainAccessors) {
9519 v8::Isolate* isolate = CcTest::isolate();
9520 v8::HandleScope handle_scope(isolate);
9522 v8::Handle<v8::FunctionTemplate> func_template =
9523 v8::FunctionTemplate::New(isolate);
9525 v8::Handle<v8::ObjectTemplate> global_template =
9526 func_template->InstanceTemplate();
9528 v8::Handle<v8::ObjectTemplate> proto_template =
9529 func_template->PrototypeTemplate();
9531 // Add an accessor to proto that's accessible by cross-domain JS code.
9532 proto_template->SetAccessor(v8_str("accessible"),
9534 v8::Handle<Value>(),
9537 // Add an accessor that is not accessible by cross-domain JS code.
9538 global_template->SetAccessor(v8_str("unreachable"),
9539 UnreachableGetter, 0,
9540 v8::Handle<Value>(),
9543 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9546 Local<v8::Object> global = context0->Global();
9547 // Add a normal property that shadows 'accessible'
9548 global->Set(v8_str("accessible"), v8_num(11));
9550 // Enter a new context.
9551 v8::HandleScope scope1(CcTest::isolate());
9552 v8::Local<Context> context1 = Context::New(isolate);
9555 v8::Handle<v8::Object> global1 = context1->Global();
9556 global1->Set(v8_str("other"), global);
9558 // Should return 10, instead of 11
9559 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9560 CHECK(value->IsNumber());
9561 CHECK_EQ(10, value->Int32Value());
9563 value = v8_compile("other.unreachable")->Run();
9564 CHECK(value->IsUndefined());
9571 static int named_access_count = 0;
9572 static int indexed_access_count = 0;
9574 static bool NamedAccessCounter(Local<v8::Object> global,
9576 v8::AccessType type,
9577 Local<Value> data) {
9578 named_access_count++;
9583 static bool IndexedAccessCounter(Local<v8::Object> global,
9585 v8::AccessType type,
9586 Local<Value> data) {
9587 indexed_access_count++;
9592 // This one is too easily disturbed by other tests.
9593 TEST(AccessControlIC) {
9594 named_access_count = 0;
9595 indexed_access_count = 0;
9597 v8::Isolate* isolate = CcTest::isolate();
9598 v8::HandleScope handle_scope(isolate);
9600 // Create an environment.
9601 v8::Local<Context> context0 = Context::New(isolate);
9604 // Create an object that requires access-check functions to be
9605 // called for cross-domain access.
9606 v8::Handle<v8::ObjectTemplate> object_template =
9607 v8::ObjectTemplate::New(isolate);
9608 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9609 IndexedAccessCounter);
9610 Local<v8::Object> object = object_template->NewInstance();
9612 v8::HandleScope scope1(isolate);
9614 // Create another environment.
9615 v8::Local<Context> context1 = Context::New(isolate);
9618 // Make easy access to the object from the other environment.
9619 v8::Handle<v8::Object> global1 = context1->Global();
9620 global1->Set(v8_str("obj"), object);
9622 v8::Handle<Value> value;
9624 // Check that the named access-control function is called every time.
9625 CompileRun("function testProp(obj) {"
9626 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9627 " for (var j = 0; j < 10; j++) obj.prop;"
9630 value = CompileRun("testProp(obj)");
9631 CHECK(value->IsNumber());
9632 CHECK_EQ(1, value->Int32Value());
9633 CHECK_EQ(21, named_access_count);
9635 // Check that the named access-control function is called every time.
9636 CompileRun("var p = 'prop';"
9637 "function testKeyed(obj) {"
9638 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9639 " for (var j = 0; j < 10; j++) obj[p];"
9642 // Use obj which requires access checks. No inline caching is used
9644 value = CompileRun("testKeyed(obj)");
9645 CHECK(value->IsNumber());
9646 CHECK_EQ(1, value->Int32Value());
9647 CHECK_EQ(42, named_access_count);
9648 // Force the inline caches into generic state and try again.
9649 CompileRun("testKeyed({ a: 0 })");
9650 CompileRun("testKeyed({ b: 0 })");
9651 value = CompileRun("testKeyed(obj)");
9652 CHECK(value->IsNumber());
9653 CHECK_EQ(1, value->Int32Value());
9654 CHECK_EQ(63, named_access_count);
9656 // Check that the indexed access-control function is called every time.
9657 CompileRun("function testIndexed(obj) {"
9658 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9659 " for (var j = 0; j < 10; j++) obj[0];"
9662 value = CompileRun("testIndexed(obj)");
9663 CHECK(value->IsNumber());
9664 CHECK_EQ(1, value->Int32Value());
9665 CHECK_EQ(21, indexed_access_count);
9666 // Force the inline caches into generic state.
9667 CompileRun("testIndexed(new Array(1))");
9668 // Test that the indexed access check is called.
9669 value = CompileRun("testIndexed(obj)");
9670 CHECK(value->IsNumber());
9671 CHECK_EQ(1, value->Int32Value());
9672 CHECK_EQ(42, indexed_access_count);
9674 // Check that the named access check is called when invoking
9675 // functions on an object that requires access checks.
9676 CompileRun("obj.f = function() {}");
9677 CompileRun("function testCallNormal(obj) {"
9678 " for (var i = 0; i < 10; i++) obj.f();"
9680 CompileRun("testCallNormal(obj)");
9681 CHECK_EQ(74, named_access_count);
9683 // Force obj into slow case.
9684 value = CompileRun("delete obj.prop");
9685 CHECK(value->BooleanValue());
9686 // Force inline caches into dictionary probing mode.
9687 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9688 // Test that the named access check is called.
9689 value = CompileRun("testProp(obj);");
9690 CHECK(value->IsNumber());
9691 CHECK_EQ(1, value->Int32Value());
9692 CHECK_EQ(96, named_access_count);
9694 // Force the call inline cache into dictionary probing mode.
9695 CompileRun("o.f = function() {}; testCallNormal(o)");
9696 // Test that the named access check is still called for each
9697 // invocation of the function.
9698 value = CompileRun("testCallNormal(obj)");
9699 CHECK_EQ(106, named_access_count);
9706 static bool NamedAccessFlatten(Local<v8::Object> global,
9708 v8::AccessType type,
9709 Local<Value> data) {
9713 CHECK(name->IsString());
9715 memset(buf, 0x1, sizeof(buf));
9716 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9721 memset(buf, 0x1, sizeof(buf));
9722 len = name.As<String>()->Write(buf2);
9729 static bool IndexedAccessFlatten(Local<v8::Object> global,
9731 v8::AccessType type,
9732 Local<Value> data) {
9737 // Regression test. In access checks, operations that may cause
9738 // garbage collection are not allowed. It used to be the case that
9739 // using the Write operation on a string could cause a garbage
9740 // collection due to flattening of the string. This is no longer the
9742 THREADED_TEST(AccessControlFlatten) {
9743 named_access_count = 0;
9744 indexed_access_count = 0;
9746 v8::Isolate* isolate = CcTest::isolate();
9747 v8::HandleScope handle_scope(isolate);
9749 // Create an environment.
9750 v8::Local<Context> context0 = Context::New(isolate);
9753 // Create an object that requires access-check functions to be
9754 // called for cross-domain access.
9755 v8::Handle<v8::ObjectTemplate> object_template =
9756 v8::ObjectTemplate::New(isolate);
9757 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9758 IndexedAccessFlatten);
9759 Local<v8::Object> object = object_template->NewInstance();
9761 v8::HandleScope scope1(isolate);
9763 // Create another environment.
9764 v8::Local<Context> context1 = Context::New(isolate);
9767 // Make easy access to the object from the other environment.
9768 v8::Handle<v8::Object> global1 = context1->Global();
9769 global1->Set(v8_str("obj"), object);
9771 v8::Handle<Value> value;
9773 value = v8_compile("var p = 'as' + 'df';")->Run();
9774 value = v8_compile("obj[p];")->Run();
9781 static void AccessControlNamedGetter(
9783 const v8::PropertyCallbackInfo<v8::Value>& info) {
9784 info.GetReturnValue().Set(42);
9788 static void AccessControlNamedSetter(
9791 const v8::PropertyCallbackInfo<v8::Value>& info) {
9792 info.GetReturnValue().Set(value);
9796 static void AccessControlIndexedGetter(
9798 const v8::PropertyCallbackInfo<v8::Value>& info) {
9799 info.GetReturnValue().Set(v8_num(42));
9803 static void AccessControlIndexedSetter(
9806 const v8::PropertyCallbackInfo<v8::Value>& info) {
9807 info.GetReturnValue().Set(value);
9811 THREADED_TEST(AccessControlInterceptorIC) {
9812 named_access_count = 0;
9813 indexed_access_count = 0;
9815 v8::Isolate* isolate = CcTest::isolate();
9816 v8::HandleScope handle_scope(isolate);
9818 // Create an environment.
9819 v8::Local<Context> context0 = Context::New(isolate);
9822 // Create an object that requires access-check functions to be
9823 // called for cross-domain access. The object also has interceptors
9825 v8::Handle<v8::ObjectTemplate> object_template =
9826 v8::ObjectTemplate::New(isolate);
9827 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9828 IndexedAccessCounter);
9829 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9830 AccessControlNamedSetter);
9831 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9832 AccessControlIndexedSetter);
9833 Local<v8::Object> object = object_template->NewInstance();
9835 v8::HandleScope scope1(isolate);
9837 // Create another environment.
9838 v8::Local<Context> context1 = Context::New(isolate);
9841 // Make easy access to the object from the other environment.
9842 v8::Handle<v8::Object> global1 = context1->Global();
9843 global1->Set(v8_str("obj"), object);
9845 v8::Handle<Value> value;
9847 // Check that the named access-control function is called every time
9848 // eventhough there is an interceptor on the object.
9849 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9850 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9852 CHECK(value->IsNumber());
9853 CHECK_EQ(42, value->Int32Value());
9854 CHECK_EQ(21, named_access_count);
9856 value = v8_compile("var p = 'x';")->Run();
9857 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9858 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9860 CHECK(value->IsNumber());
9861 CHECK_EQ(42, value->Int32Value());
9862 CHECK_EQ(42, named_access_count);
9864 // Check that the indexed access-control function is called every
9865 // time eventhough there is an interceptor on the object.
9866 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9867 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9869 CHECK(value->IsNumber());
9870 CHECK_EQ(42, value->Int32Value());
9871 CHECK_EQ(21, indexed_access_count);
9878 THREADED_TEST(Version) {
9879 v8::V8::GetVersion();
9883 static void InstanceFunctionCallback(
9884 const v8::FunctionCallbackInfo<v8::Value>& args) {
9885 ApiTestFuzzer::Fuzz();
9886 args.GetReturnValue().Set(v8_num(12));
9890 THREADED_TEST(InstanceProperties) {
9891 LocalContext context;
9892 v8::Isolate* isolate = context->GetIsolate();
9893 v8::HandleScope handle_scope(isolate);
9895 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9896 Local<ObjectTemplate> instance = t->InstanceTemplate();
9898 instance->Set(v8_str("x"), v8_num(42));
9899 instance->Set(v8_str("f"),
9900 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9902 Local<Value> o = t->GetFunction()->NewInstance();
9904 context->Global()->Set(v8_str("i"), o);
9905 Local<Value> value = CompileRun("i.x");
9906 CHECK_EQ(42, value->Int32Value());
9908 value = CompileRun("i.f()");
9909 CHECK_EQ(12, value->Int32Value());
9913 static void GlobalObjectInstancePropertiesGet(
9915 const v8::PropertyCallbackInfo<v8::Value>&) {
9916 ApiTestFuzzer::Fuzz();
9920 THREADED_TEST(GlobalObjectInstanceProperties) {
9921 v8::Isolate* isolate = CcTest::isolate();
9922 v8::HandleScope handle_scope(isolate);
9924 Local<Value> global_object;
9926 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9927 t->InstanceTemplate()->SetNamedPropertyHandler(
9928 GlobalObjectInstancePropertiesGet);
9929 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9930 instance_template->Set(v8_str("x"), v8_num(42));
9931 instance_template->Set(v8_str("f"),
9932 v8::FunctionTemplate::New(isolate,
9933 InstanceFunctionCallback));
9935 // The script to check how Crankshaft compiles missing global function
9936 // invocations. function g is not defined and should throw on call.
9937 const char* script =
9938 "function wrapper(call) {"
9939 " var x = 0, y = 1;"
9940 " for (var i = 0; i < 1000; i++) {"
9946 "for (var i = 0; i < 17; i++) wrapper(false);"
9948 "try { wrapper(true); } catch (e) { thrown = 1; };"
9952 LocalContext env(NULL, instance_template);
9953 // Hold on to the global object so it can be used again in another
9954 // environment initialization.
9955 global_object = env->Global();
9957 Local<Value> value = CompileRun("x");
9958 CHECK_EQ(42, value->Int32Value());
9959 value = CompileRun("f()");
9960 CHECK_EQ(12, value->Int32Value());
9961 value = CompileRun(script);
9962 CHECK_EQ(1, value->Int32Value());
9966 // Create new environment reusing the global object.
9967 LocalContext env(NULL, instance_template, global_object);
9968 Local<Value> value = CompileRun("x");
9969 CHECK_EQ(42, value->Int32Value());
9970 value = CompileRun("f()");
9971 CHECK_EQ(12, value->Int32Value());
9972 value = CompileRun(script);
9973 CHECK_EQ(1, value->Int32Value());
9978 THREADED_TEST(CallKnownGlobalReceiver) {
9979 v8::Isolate* isolate = CcTest::isolate();
9980 v8::HandleScope handle_scope(isolate);
9982 Local<Value> global_object;
9984 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9985 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9987 // The script to check that we leave global object not
9988 // global object proxy on stack when we deoptimize from inside
9989 // arguments evaluation.
9990 // To provoke error we need to both force deoptimization
9991 // from arguments evaluation and to force CallIC to take
9992 // CallIC_Miss code path that can't cope with global proxy.
9993 const char* script =
9994 "function bar(x, y) { try { } finally { } }"
9995 "function baz(x) { try { } finally { } }"
9996 "function bom(x) { try { } finally { } }"
9997 "function foo(x) { bar([x], bom(2)); }"
9998 "for (var i = 0; i < 10000; i++) foo(1);"
10003 LocalContext env(NULL, instance_template);
10004 // Hold on to the global object so it can be used again in another
10005 // environment initialization.
10006 global_object = env->Global();
10007 foo = CompileRun(script);
10011 // Create new environment reusing the global object.
10012 LocalContext env(NULL, instance_template, global_object);
10013 env->Global()->Set(v8_str("foo"), foo);
10014 CompileRun("foo()");
10019 static void ShadowFunctionCallback(
10020 const v8::FunctionCallbackInfo<v8::Value>& args) {
10021 ApiTestFuzzer::Fuzz();
10022 args.GetReturnValue().Set(v8_num(42));
10026 static int shadow_y;
10027 static int shadow_y_setter_call_count;
10028 static int shadow_y_getter_call_count;
10031 static void ShadowYSetter(Local<String>,
10033 const v8::PropertyCallbackInfo<void>&) {
10034 shadow_y_setter_call_count++;
10039 static void ShadowYGetter(Local<String> name,
10040 const v8::PropertyCallbackInfo<v8::Value>& info) {
10041 ApiTestFuzzer::Fuzz();
10042 shadow_y_getter_call_count++;
10043 info.GetReturnValue().Set(v8_num(shadow_y));
10047 static void ShadowIndexedGet(uint32_t index,
10048 const v8::PropertyCallbackInfo<v8::Value>&) {
10052 static void ShadowNamedGet(Local<String> key,
10053 const v8::PropertyCallbackInfo<v8::Value>&) {
10057 THREADED_TEST(ShadowObject) {
10058 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10059 v8::Isolate* isolate = CcTest::isolate();
10060 v8::HandleScope handle_scope(isolate);
10062 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10063 LocalContext context(NULL, global_template);
10065 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10066 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10067 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10068 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10069 Local<ObjectTemplate> instance = t->InstanceTemplate();
10071 proto->Set(v8_str("f"),
10072 v8::FunctionTemplate::New(isolate,
10073 ShadowFunctionCallback,
10075 proto->Set(v8_str("x"), v8_num(12));
10077 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10079 Local<Value> o = t->GetFunction()->NewInstance();
10080 context->Global()->Set(v8_str("__proto__"), o);
10082 Local<Value> value =
10083 CompileRun("this.propertyIsEnumerable(0)");
10084 CHECK(value->IsBoolean());
10085 CHECK(!value->BooleanValue());
10087 value = CompileRun("x");
10088 CHECK_EQ(12, value->Int32Value());
10090 value = CompileRun("f()");
10091 CHECK_EQ(42, value->Int32Value());
10093 CompileRun("y = 43");
10094 CHECK_EQ(1, shadow_y_setter_call_count);
10095 value = CompileRun("y");
10096 CHECK_EQ(1, shadow_y_getter_call_count);
10097 CHECK_EQ(42, value->Int32Value());
10101 THREADED_TEST(HiddenPrototype) {
10102 LocalContext context;
10103 v8::Isolate* isolate = context->GetIsolate();
10104 v8::HandleScope handle_scope(isolate);
10106 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10107 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10108 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10109 t1->SetHiddenPrototype(true);
10110 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10111 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10112 t2->SetHiddenPrototype(true);
10113 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10114 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10115 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10117 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10118 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10119 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10120 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10122 // Setting the prototype on an object skips hidden prototypes.
10123 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10124 o0->Set(v8_str("__proto__"), o1);
10125 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10126 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10127 o0->Set(v8_str("__proto__"), o2);
10128 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10129 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10130 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10131 o0->Set(v8_str("__proto__"), o3);
10132 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10133 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10134 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10135 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10137 // Getting the prototype of o0 should get the first visible one
10138 // which is o3. Therefore, z should not be defined on the prototype
10140 Local<Value> proto = o0->Get(v8_str("__proto__"));
10141 CHECK(proto->IsObject());
10142 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10146 THREADED_TEST(HiddenPrototypeSet) {
10147 LocalContext context;
10148 v8::Isolate* isolate = context->GetIsolate();
10149 v8::HandleScope handle_scope(isolate);
10151 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10152 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10153 ht->SetHiddenPrototype(true);
10154 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10155 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10157 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10158 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10159 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10160 o->Set(v8_str("__proto__"), h);
10161 h->Set(v8_str("__proto__"), p);
10163 // Setting a property that exists on the hidden prototype goes there.
10164 o->Set(v8_str("x"), v8_num(7));
10165 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10166 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10167 CHECK(p->Get(v8_str("x"))->IsUndefined());
10169 // Setting a new property should not be forwarded to the hidden prototype.
10170 o->Set(v8_str("y"), v8_num(6));
10171 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10172 CHECK(h->Get(v8_str("y"))->IsUndefined());
10173 CHECK(p->Get(v8_str("y"))->IsUndefined());
10175 // Setting a property that only exists on a prototype of the hidden prototype
10176 // is treated normally again.
10177 p->Set(v8_str("z"), v8_num(8));
10178 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10179 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10180 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10181 o->Set(v8_str("z"), v8_num(9));
10182 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10183 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10184 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10188 // Regression test for issue 2457.
10189 THREADED_TEST(HiddenPrototypeIdentityHash) {
10190 LocalContext context;
10191 v8::HandleScope handle_scope(context->GetIsolate());
10193 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10194 t->SetHiddenPrototype(true);
10195 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10196 Handle<Object> p = t->GetFunction()->NewInstance();
10197 Handle<Object> o = Object::New(context->GetIsolate());
10198 o->SetPrototype(p);
10200 int hash = o->GetIdentityHash();
10202 o->Set(v8_str("foo"), v8_num(42));
10203 ASSERT_EQ(hash, o->GetIdentityHash());
10207 THREADED_TEST(SetPrototype) {
10208 LocalContext context;
10209 v8::Isolate* isolate = context->GetIsolate();
10210 v8::HandleScope handle_scope(isolate);
10212 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10213 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10214 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10215 t1->SetHiddenPrototype(true);
10216 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10217 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10218 t2->SetHiddenPrototype(true);
10219 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10220 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10221 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10223 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10224 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10225 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10226 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10228 // Setting the prototype on an object does not skip hidden prototypes.
10229 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10230 CHECK(o0->SetPrototype(o1));
10231 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10232 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10233 CHECK(o1->SetPrototype(o2));
10234 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10235 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10236 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10237 CHECK(o2->SetPrototype(o3));
10238 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10239 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10240 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10241 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10243 // Getting the prototype of o0 should get the first visible one
10244 // which is o3. Therefore, z should not be defined on the prototype
10246 Local<Value> proto = o0->Get(v8_str("__proto__"));
10247 CHECK(proto->IsObject());
10248 CHECK_EQ(proto.As<v8::Object>(), o3);
10250 // However, Object::GetPrototype ignores hidden prototype.
10251 Local<Value> proto0 = o0->GetPrototype();
10252 CHECK(proto0->IsObject());
10253 CHECK_EQ(proto0.As<v8::Object>(), o1);
10255 Local<Value> proto1 = o1->GetPrototype();
10256 CHECK(proto1->IsObject());
10257 CHECK_EQ(proto1.As<v8::Object>(), o2);
10259 Local<Value> proto2 = o2->GetPrototype();
10260 CHECK(proto2->IsObject());
10261 CHECK_EQ(proto2.As<v8::Object>(), o3);
10265 // Getting property names of an object with a prototype chain that
10266 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10267 // crash the runtime.
10268 THREADED_TEST(Regress91517) {
10269 i::FLAG_allow_natives_syntax = true;
10270 LocalContext context;
10271 v8::Isolate* isolate = context->GetIsolate();
10272 v8::HandleScope handle_scope(isolate);
10274 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10275 t1->SetHiddenPrototype(true);
10276 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10277 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10278 t2->SetHiddenPrototype(true);
10279 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10280 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10281 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10282 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10283 t3->SetHiddenPrototype(true);
10284 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10285 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10286 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10288 // Force dictionary-based properties.
10289 i::ScopedVector<char> name_buf(1024);
10290 for (int i = 1; i <= 1000; i++) {
10291 i::OS::SNPrintF(name_buf, "sdf%d", i);
10292 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10295 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10296 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10297 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10298 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10300 // Create prototype chain of hidden prototypes.
10301 CHECK(o4->SetPrototype(o3));
10302 CHECK(o3->SetPrototype(o2));
10303 CHECK(o2->SetPrototype(o1));
10305 // Call the runtime version of GetLocalPropertyNames() on the natively
10306 // created object through JavaScript.
10307 context->Global()->Set(v8_str("obj"), o4);
10308 // PROPERTY_ATTRIBUTES_NONE = 0
10309 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10311 ExpectInt32("names.length", 1006);
10312 ExpectTrue("names.indexOf(\"baz\") >= 0");
10313 ExpectTrue("names.indexOf(\"boo\") >= 0");
10314 ExpectTrue("names.indexOf(\"foo\") >= 0");
10315 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10316 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10317 ExpectFalse("names[1005] == undefined");
10321 // Getting property names of an object with a hidden and inherited
10322 // prototype should not duplicate the accessor properties inherited.
10323 THREADED_TEST(Regress269562) {
10324 i::FLAG_allow_natives_syntax = true;
10325 LocalContext context;
10326 v8::HandleScope handle_scope(context->GetIsolate());
10328 Local<v8::FunctionTemplate> t1 =
10329 v8::FunctionTemplate::New(context->GetIsolate());
10330 t1->SetHiddenPrototype(true);
10332 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10333 i1->SetAccessor(v8_str("foo"),
10334 SimpleAccessorGetter, SimpleAccessorSetter);
10335 i1->SetAccessor(v8_str("bar"),
10336 SimpleAccessorGetter, SimpleAccessorSetter);
10337 i1->SetAccessor(v8_str("baz"),
10338 SimpleAccessorGetter, SimpleAccessorSetter);
10339 i1->Set(v8_str("n1"), v8_num(1));
10340 i1->Set(v8_str("n2"), v8_num(2));
10342 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10343 Local<v8::FunctionTemplate> t2 =
10344 v8::FunctionTemplate::New(context->GetIsolate());
10345 t2->SetHiddenPrototype(true);
10347 // Inherit from t1 and mark prototype as hidden.
10349 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10351 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10352 CHECK(o2->SetPrototype(o1));
10354 v8::Local<v8::Symbol> sym =
10355 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10356 o1->Set(sym, v8_num(3));
10357 o1->SetHiddenValue(
10358 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10360 // Call the runtime version of GetLocalPropertyNames() on
10361 // the natively created object through JavaScript.
10362 context->Global()->Set(v8_str("obj"), o2);
10363 context->Global()->Set(v8_str("sym"), sym);
10364 // PROPERTY_ATTRIBUTES_NONE = 0
10365 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10367 ExpectInt32("names.length", 7);
10368 ExpectTrue("names.indexOf(\"foo\") >= 0");
10369 ExpectTrue("names.indexOf(\"bar\") >= 0");
10370 ExpectTrue("names.indexOf(\"baz\") >= 0");
10371 ExpectTrue("names.indexOf(\"n1\") >= 0");
10372 ExpectTrue("names.indexOf(\"n2\") >= 0");
10373 ExpectTrue("names.indexOf(sym) >= 0");
10374 ExpectTrue("names.indexOf(\"mine\") >= 0");
10378 THREADED_TEST(FunctionReadOnlyPrototype) {
10379 LocalContext context;
10380 v8::Isolate* isolate = context->GetIsolate();
10381 v8::HandleScope handle_scope(isolate);
10383 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10384 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10385 t1->ReadOnlyPrototype();
10386 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10387 // Configured value of ReadOnly flag.
10390 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10391 " return (descriptor['writable'] == false);"
10392 "})()")->BooleanValue());
10393 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10395 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10397 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10398 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10399 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10400 // Default value of ReadOnly flag.
10403 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10404 " return (descriptor['writable'] == true);"
10405 "})()")->BooleanValue());
10406 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10410 THREADED_TEST(SetPrototypeThrows) {
10411 LocalContext context;
10412 v8::Isolate* isolate = context->GetIsolate();
10413 v8::HandleScope handle_scope(isolate);
10415 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10417 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10418 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10420 CHECK(o0->SetPrototype(o1));
10421 // If setting the prototype leads to the cycle, SetPrototype should
10422 // return false and keep VM in sane state.
10423 v8::TryCatch try_catch;
10424 CHECK(!o1->SetPrototype(o0));
10425 CHECK(!try_catch.HasCaught());
10426 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10428 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10432 THREADED_TEST(FunctionRemovePrototype) {
10433 LocalContext context;
10434 v8::Isolate* isolate = context->GetIsolate();
10435 v8::HandleScope handle_scope(isolate);
10437 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10438 t1->RemovePrototype();
10439 Local<v8::Function> fun = t1->GetFunction();
10440 context->Global()->Set(v8_str("fun"), fun);
10441 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10443 v8::TryCatch try_catch;
10444 CompileRun("new fun()");
10445 CHECK(try_catch.HasCaught());
10448 fun->NewInstance();
10449 CHECK(try_catch.HasCaught());
10453 THREADED_TEST(GetterSetterExceptions) {
10454 LocalContext context;
10455 v8::Isolate* isolate = context->GetIsolate();
10456 v8::HandleScope handle_scope(isolate);
10458 "function Foo() { };"
10459 "function Throw() { throw 5; };"
10461 "x.__defineSetter__('set', Throw);"
10462 "x.__defineGetter__('get', Throw);");
10463 Local<v8::Object> x =
10464 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10465 v8::TryCatch try_catch;
10466 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10467 x->Get(v8_str("get"));
10468 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10469 x->Get(v8_str("get"));
10470 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10471 x->Get(v8_str("get"));
10472 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10473 x->Get(v8_str("get"));
10477 THREADED_TEST(Constructor) {
10478 LocalContext context;
10479 v8::Isolate* isolate = context->GetIsolate();
10480 v8::HandleScope handle_scope(isolate);
10481 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10482 templ->SetClassName(v8_str("Fun"));
10483 Local<Function> cons = templ->GetFunction();
10484 context->Global()->Set(v8_str("Fun"), cons);
10485 Local<v8::Object> inst = cons->NewInstance();
10486 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10487 CHECK(obj->IsJSObject());
10488 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10489 CHECK(value->BooleanValue());
10493 static void ConstructorCallback(
10494 const v8::FunctionCallbackInfo<v8::Value>& args) {
10495 ApiTestFuzzer::Fuzz();
10496 Local<Object> This;
10498 if (args.IsConstructCall()) {
10499 Local<Object> Holder = args.Holder();
10500 This = Object::New(args.GetIsolate());
10501 Local<Value> proto = Holder->GetPrototype();
10502 if (proto->IsObject()) {
10503 This->SetPrototype(proto);
10506 This = args.This();
10509 This->Set(v8_str("a"), args[0]);
10510 args.GetReturnValue().Set(This);
10514 static void FakeConstructorCallback(
10515 const v8::FunctionCallbackInfo<v8::Value>& args) {
10516 ApiTestFuzzer::Fuzz();
10517 args.GetReturnValue().Set(args[0]);
10521 THREADED_TEST(ConstructorForObject) {
10522 LocalContext context;
10523 v8::Isolate* isolate = context->GetIsolate();
10524 v8::HandleScope handle_scope(isolate);
10526 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10527 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10528 Local<Object> instance = instance_template->NewInstance();
10529 context->Global()->Set(v8_str("obj"), instance);
10530 v8::TryCatch try_catch;
10531 Local<Value> value;
10532 CHECK(!try_catch.HasCaught());
10534 // Call the Object's constructor with a 32-bit signed integer.
10535 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10536 CHECK(!try_catch.HasCaught());
10537 CHECK(value->IsInt32());
10538 CHECK_EQ(28, value->Int32Value());
10540 Local<Value> args1[] = { v8_num(28) };
10541 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10542 CHECK(value_obj1->IsObject());
10543 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10544 value = object1->Get(v8_str("a"));
10545 CHECK(value->IsInt32());
10546 CHECK(!try_catch.HasCaught());
10547 CHECK_EQ(28, value->Int32Value());
10549 // Call the Object's constructor with a String.
10550 value = CompileRun(
10551 "(function() { var o = new obj('tipli'); return o.a; })()");
10552 CHECK(!try_catch.HasCaught());
10553 CHECK(value->IsString());
10554 String::Utf8Value string_value1(value->ToString());
10555 CHECK_EQ("tipli", *string_value1);
10557 Local<Value> args2[] = { v8_str("tipli") };
10558 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10559 CHECK(value_obj2->IsObject());
10560 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10561 value = object2->Get(v8_str("a"));
10562 CHECK(!try_catch.HasCaught());
10563 CHECK(value->IsString());
10564 String::Utf8Value string_value2(value->ToString());
10565 CHECK_EQ("tipli", *string_value2);
10567 // Call the Object's constructor with a Boolean.
10568 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10569 CHECK(!try_catch.HasCaught());
10570 CHECK(value->IsBoolean());
10571 CHECK_EQ(true, value->BooleanValue());
10573 Handle<Value> args3[] = { v8::True(isolate) };
10574 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10575 CHECK(value_obj3->IsObject());
10576 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10577 value = object3->Get(v8_str("a"));
10578 CHECK(!try_catch.HasCaught());
10579 CHECK(value->IsBoolean());
10580 CHECK_EQ(true, value->BooleanValue());
10582 // Call the Object's constructor with undefined.
10583 Handle<Value> args4[] = { v8::Undefined(isolate) };
10584 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10585 CHECK(value_obj4->IsObject());
10586 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10587 value = object4->Get(v8_str("a"));
10588 CHECK(!try_catch.HasCaught());
10589 CHECK(value->IsUndefined());
10591 // Call the Object's constructor with null.
10592 Handle<Value> args5[] = { v8::Null(isolate) };
10593 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10594 CHECK(value_obj5->IsObject());
10595 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10596 value = object5->Get(v8_str("a"));
10597 CHECK(!try_catch.HasCaught());
10598 CHECK(value->IsNull());
10601 // Check exception handling when there is no constructor set for the Object.
10602 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10603 Local<Object> instance = instance_template->NewInstance();
10604 context->Global()->Set(v8_str("obj2"), instance);
10605 v8::TryCatch try_catch;
10606 Local<Value> value;
10607 CHECK(!try_catch.HasCaught());
10609 value = CompileRun("new obj2(28)");
10610 CHECK(try_catch.HasCaught());
10611 String::Utf8Value exception_value1(try_catch.Exception());
10612 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10615 Local<Value> args[] = { v8_num(29) };
10616 value = instance->CallAsConstructor(1, args);
10617 CHECK(try_catch.HasCaught());
10618 String::Utf8Value exception_value2(try_catch.Exception());
10619 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10623 // Check the case when constructor throws exception.
10624 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10625 instance_template->SetCallAsFunctionHandler(ThrowValue);
10626 Local<Object> instance = instance_template->NewInstance();
10627 context->Global()->Set(v8_str("obj3"), instance);
10628 v8::TryCatch try_catch;
10629 Local<Value> value;
10630 CHECK(!try_catch.HasCaught());
10632 value = CompileRun("new obj3(22)");
10633 CHECK(try_catch.HasCaught());
10634 String::Utf8Value exception_value1(try_catch.Exception());
10635 CHECK_EQ("22", *exception_value1);
10638 Local<Value> args[] = { v8_num(23) };
10639 value = instance->CallAsConstructor(1, args);
10640 CHECK(try_catch.HasCaught());
10641 String::Utf8Value exception_value2(try_catch.Exception());
10642 CHECK_EQ("23", *exception_value2);
10646 // Check whether constructor returns with an object or non-object.
10647 { Local<FunctionTemplate> function_template =
10648 FunctionTemplate::New(isolate, FakeConstructorCallback);
10649 Local<Function> function = function_template->GetFunction();
10650 Local<Object> instance1 = function;
10651 context->Global()->Set(v8_str("obj4"), instance1);
10652 v8::TryCatch try_catch;
10653 Local<Value> value;
10654 CHECK(!try_catch.HasCaught());
10656 CHECK(instance1->IsObject());
10657 CHECK(instance1->IsFunction());
10659 value = CompileRun("new obj4(28)");
10660 CHECK(!try_catch.HasCaught());
10661 CHECK(value->IsObject());
10663 Local<Value> args1[] = { v8_num(28) };
10664 value = instance1->CallAsConstructor(1, args1);
10665 CHECK(!try_catch.HasCaught());
10666 CHECK(value->IsObject());
10668 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10669 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10670 Local<Object> instance2 = instance_template->NewInstance();
10671 context->Global()->Set(v8_str("obj5"), instance2);
10672 CHECK(!try_catch.HasCaught());
10674 CHECK(instance2->IsObject());
10675 CHECK(!instance2->IsFunction());
10677 value = CompileRun("new obj5(28)");
10678 CHECK(!try_catch.HasCaught());
10679 CHECK(!value->IsObject());
10681 Local<Value> args2[] = { v8_num(28) };
10682 value = instance2->CallAsConstructor(1, args2);
10683 CHECK(!try_catch.HasCaught());
10684 CHECK(!value->IsObject());
10689 THREADED_TEST(FunctionDescriptorException) {
10690 LocalContext context;
10691 v8::Isolate* isolate = context->GetIsolate();
10692 v8::HandleScope handle_scope(isolate);
10693 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10694 templ->SetClassName(v8_str("Fun"));
10695 Local<Function> cons = templ->GetFunction();
10696 context->Global()->Set(v8_str("Fun"), cons);
10697 Local<Value> value = CompileRun(
10698 "function test() {"
10700 " (new Fun()).blah()"
10702 " var str = String(e);"
10703 // " if (str.indexOf('TypeError') == -1) return 1;"
10704 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10705 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10711 CHECK_EQ(0, value->Int32Value());
10715 THREADED_TEST(EvalAliasedDynamic) {
10716 LocalContext current;
10717 v8::HandleScope scope(current->GetIsolate());
10719 // Tests where aliased eval can only be resolved dynamically.
10720 Local<Script> script = v8_compile(
10723 " with (x) { return eval('foo'); }"
10726 "result1 = f(new Object());"
10727 "result2 = f(this);"
10728 "var x = new Object();"
10729 "x.eval = function(x) { return 1; };"
10730 "result3 = f(x);");
10732 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10733 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10734 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10736 v8::TryCatch try_catch;
10737 script = v8_compile(
10740 " with (x) { return eval('bar'); }"
10742 "result4 = f(this)");
10744 CHECK(!try_catch.HasCaught());
10745 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10751 THREADED_TEST(CrossEval) {
10752 v8::HandleScope scope(CcTest::isolate());
10753 LocalContext other;
10754 LocalContext current;
10756 Local<String> token = v8_str("<security token>");
10757 other->SetSecurityToken(token);
10758 current->SetSecurityToken(token);
10760 // Set up reference from current to other.
10761 current->Global()->Set(v8_str("other"), other->Global());
10763 // Check that new variables are introduced in other context.
10764 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10766 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10767 CHECK_EQ(1234, foo->Int32Value());
10768 CHECK(!current->Global()->Has(v8_str("foo")));
10770 // Check that writing to non-existing properties introduces them in
10771 // the other context.
10772 script = v8_compile("other.eval('na = 1234')");
10774 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10775 CHECK(!current->Global()->Has(v8_str("na")));
10777 // Check that global variables in current context are not visible in other
10779 v8::TryCatch try_catch;
10780 script = v8_compile("var bar = 42; other.eval('bar');");
10781 Local<Value> result = script->Run();
10782 CHECK(try_catch.HasCaught());
10785 // Check that local variables in current context are not visible in other
10787 script = v8_compile(
10790 " return other.eval('baz');"
10792 result = script->Run();
10793 CHECK(try_catch.HasCaught());
10796 // Check that global variables in the other environment are visible
10797 // when evaluting code.
10798 other->Global()->Set(v8_str("bis"), v8_num(1234));
10799 script = v8_compile("other.eval('bis')");
10800 CHECK_EQ(1234, script->Run()->Int32Value());
10801 CHECK(!try_catch.HasCaught());
10803 // Check that the 'this' pointer points to the global object evaluating
10805 other->Global()->Set(v8_str("t"), other->Global());
10806 script = v8_compile("other.eval('this == t')");
10807 result = script->Run();
10808 CHECK(result->IsTrue());
10809 CHECK(!try_catch.HasCaught());
10811 // Check that variables introduced in with-statement are not visible in
10813 script = v8_compile("with({x:2}){other.eval('x')}");
10814 result = script->Run();
10815 CHECK(try_catch.HasCaught());
10818 // Check that you cannot use 'eval.call' with another object than the
10819 // current global object.
10820 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10821 result = script->Run();
10822 CHECK(try_catch.HasCaught());
10826 // Test that calling eval in a context which has been detached from
10827 // its global throws an exception. This behavior is consistent with
10828 // other JavaScript implementations.
10829 THREADED_TEST(EvalInDetachedGlobal) {
10830 v8::Isolate* isolate = CcTest::isolate();
10831 v8::HandleScope scope(isolate);
10833 v8::Local<Context> context0 = Context::New(isolate);
10834 v8::Local<Context> context1 = Context::New(isolate);
10836 // Set up function in context0 that uses eval from context0.
10838 v8::Handle<v8::Value> fun =
10839 CompileRun("var x = 42;"
10842 " return function(s) { return e(s); }"
10846 // Put the function into context1 and call it before and after
10847 // detaching the global. Before detaching, the call succeeds and
10848 // after detaching and exception is thrown.
10850 context1->Global()->Set(v8_str("fun"), fun);
10851 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10852 CHECK_EQ(42, x_value->Int32Value());
10853 context0->DetachGlobal();
10854 v8::TryCatch catcher;
10855 x_value = CompileRun("fun('x')");
10856 CHECK(x_value.IsEmpty());
10857 CHECK(catcher.HasCaught());
10862 THREADED_TEST(CrossLazyLoad) {
10863 v8::HandleScope scope(CcTest::isolate());
10864 LocalContext other;
10865 LocalContext current;
10867 Local<String> token = v8_str("<security token>");
10868 other->SetSecurityToken(token);
10869 current->SetSecurityToken(token);
10871 // Set up reference from current to other.
10872 current->Global()->Set(v8_str("other"), other->Global());
10874 // Trigger lazy loading in other context.
10875 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10876 Local<Value> value = script->Run();
10877 CHECK_EQ(42.0, value->NumberValue());
10881 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10882 ApiTestFuzzer::Fuzz();
10883 if (args.IsConstructCall()) {
10884 if (args[0]->IsInt32()) {
10885 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10890 args.GetReturnValue().Set(args[0]);
10894 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10895 args.GetReturnValue().Set(args.This());
10899 // Test that a call handler can be set for objects which will allow
10900 // non-function objects created through the API to be called as
10902 THREADED_TEST(CallAsFunction) {
10903 LocalContext context;
10904 v8::Isolate* isolate = context->GetIsolate();
10905 v8::HandleScope scope(isolate);
10907 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10908 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10909 instance_template->SetCallAsFunctionHandler(call_as_function);
10910 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10911 context->Global()->Set(v8_str("obj"), instance);
10912 v8::TryCatch try_catch;
10913 Local<Value> value;
10914 CHECK(!try_catch.HasCaught());
10916 value = CompileRun("obj(42)");
10917 CHECK(!try_catch.HasCaught());
10918 CHECK_EQ(42, value->Int32Value());
10920 value = CompileRun("(function(o){return o(49)})(obj)");
10921 CHECK(!try_catch.HasCaught());
10922 CHECK_EQ(49, value->Int32Value());
10924 // test special case of call as function
10925 value = CompileRun("[obj]['0'](45)");
10926 CHECK(!try_catch.HasCaught());
10927 CHECK_EQ(45, value->Int32Value());
10929 value = CompileRun("obj.call = Function.prototype.call;"
10930 "obj.call(null, 87)");
10931 CHECK(!try_catch.HasCaught());
10932 CHECK_EQ(87, value->Int32Value());
10934 // Regression tests for bug #1116356: Calling call through call/apply
10935 // must work for non-function receivers.
10936 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10937 value = CompileRun(apply_99);
10938 CHECK(!try_catch.HasCaught());
10939 CHECK_EQ(99, value->Int32Value());
10941 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10942 value = CompileRun(call_17);
10943 CHECK(!try_catch.HasCaught());
10944 CHECK_EQ(17, value->Int32Value());
10946 // Check that the call-as-function handler can be called through
10948 value = CompileRun("new obj(43)");
10949 CHECK(!try_catch.HasCaught());
10950 CHECK_EQ(-43, value->Int32Value());
10952 // Check that the call-as-function handler can be called through
10954 v8::Handle<Value> args[] = { v8_num(28) };
10955 value = instance->CallAsFunction(instance, 1, args);
10956 CHECK(!try_catch.HasCaught());
10957 CHECK_EQ(28, value->Int32Value());
10960 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10961 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10962 USE(instance_template);
10963 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10964 context->Global()->Set(v8_str("obj2"), instance);
10965 v8::TryCatch try_catch;
10966 Local<Value> value;
10967 CHECK(!try_catch.HasCaught());
10969 // Call an object without call-as-function handler through the JS
10970 value = CompileRun("obj2(28)");
10971 CHECK(value.IsEmpty());
10972 CHECK(try_catch.HasCaught());
10973 String::Utf8Value exception_value1(try_catch.Exception());
10974 // TODO(verwaest): Better message
10975 CHECK_EQ("TypeError: object is not a function",
10976 *exception_value1);
10979 // Call an object without call-as-function handler through the API
10980 value = CompileRun("obj2(28)");
10981 v8::Handle<Value> args[] = { v8_num(28) };
10982 value = instance->CallAsFunction(instance, 1, args);
10983 CHECK(value.IsEmpty());
10984 CHECK(try_catch.HasCaught());
10985 String::Utf8Value exception_value2(try_catch.Exception());
10986 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10990 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10991 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10992 instance_template->SetCallAsFunctionHandler(ThrowValue);
10993 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10994 context->Global()->Set(v8_str("obj3"), instance);
10995 v8::TryCatch try_catch;
10996 Local<Value> value;
10997 CHECK(!try_catch.HasCaught());
10999 // Catch the exception which is thrown by call-as-function handler
11000 value = CompileRun("obj3(22)");
11001 CHECK(try_catch.HasCaught());
11002 String::Utf8Value exception_value1(try_catch.Exception());
11003 CHECK_EQ("22", *exception_value1);
11006 v8::Handle<Value> args[] = { v8_num(23) };
11007 value = instance->CallAsFunction(instance, 1, args);
11008 CHECK(try_catch.HasCaught());
11009 String::Utf8Value exception_value2(try_catch.Exception());
11010 CHECK_EQ("23", *exception_value2);
11014 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11015 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11016 instance_template->SetCallAsFunctionHandler(ReturnThis);
11017 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11019 Local<v8::Value> a1 =
11020 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11021 CHECK(a1->StrictEquals(instance));
11022 Local<v8::Value> a2 =
11023 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11024 CHECK(a2->StrictEquals(instance));
11025 Local<v8::Value> a3 =
11026 instance->CallAsFunction(v8_num(42), 0, NULL);
11027 CHECK(a3->StrictEquals(instance));
11028 Local<v8::Value> a4 =
11029 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11030 CHECK(a4->StrictEquals(instance));
11031 Local<v8::Value> a5 =
11032 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11033 CHECK(a5->StrictEquals(instance));
11037 "function ReturnThisSloppy() {"
11040 "function ReturnThisStrict() {"
11044 Local<Function> ReturnThisSloppy =
11045 Local<Function>::Cast(
11046 context->Global()->Get(v8_str("ReturnThisSloppy")));
11047 Local<Function> ReturnThisStrict =
11048 Local<Function>::Cast(
11049 context->Global()->Get(v8_str("ReturnThisStrict")));
11051 Local<v8::Value> a1 =
11052 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11053 CHECK(a1->StrictEquals(context->Global()));
11054 Local<v8::Value> a2 =
11055 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11056 CHECK(a2->StrictEquals(context->Global()));
11057 Local<v8::Value> a3 =
11058 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11059 CHECK(a3->IsNumberObject());
11060 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11061 Local<v8::Value> a4 =
11062 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11063 CHECK(a4->IsStringObject());
11064 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11065 Local<v8::Value> a5 =
11066 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11067 CHECK(a5->IsBooleanObject());
11068 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11070 Local<v8::Value> a6 =
11071 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11072 CHECK(a6->IsUndefined());
11073 Local<v8::Value> a7 =
11074 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11075 CHECK(a7->IsNull());
11076 Local<v8::Value> a8 =
11077 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11078 CHECK(a8->StrictEquals(v8_num(42)));
11079 Local<v8::Value> a9 =
11080 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11081 CHECK(a9->StrictEquals(v8_str("hello")));
11082 Local<v8::Value> a10 =
11083 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11084 CHECK(a10->StrictEquals(v8::True(isolate)));
11089 // Check whether a non-function object is callable.
11090 THREADED_TEST(CallableObject) {
11091 LocalContext context;
11092 v8::Isolate* isolate = context->GetIsolate();
11093 v8::HandleScope scope(isolate);
11095 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11096 instance_template->SetCallAsFunctionHandler(call_as_function);
11097 Local<Object> instance = instance_template->NewInstance();
11098 v8::TryCatch try_catch;
11100 CHECK(instance->IsCallable());
11101 CHECK(!try_catch.HasCaught());
11104 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11105 Local<Object> instance = instance_template->NewInstance();
11106 v8::TryCatch try_catch;
11108 CHECK(!instance->IsCallable());
11109 CHECK(!try_catch.HasCaught());
11112 { Local<FunctionTemplate> function_template =
11113 FunctionTemplate::New(isolate, call_as_function);
11114 Local<Function> function = function_template->GetFunction();
11115 Local<Object> instance = function;
11116 v8::TryCatch try_catch;
11118 CHECK(instance->IsCallable());
11119 CHECK(!try_catch.HasCaught());
11122 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11123 Local<Function> function = function_template->GetFunction();
11124 Local<Object> instance = function;
11125 v8::TryCatch try_catch;
11127 CHECK(instance->IsCallable());
11128 CHECK(!try_catch.HasCaught());
11133 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11134 v8::HandleScope scope(isolate);
11135 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11136 for (int i = 0; i < iterations; i++) {
11137 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11139 return Recurse(isolate, depth - 1, iterations);
11143 THREADED_TEST(HandleIteration) {
11144 static const int kIterations = 500;
11145 static const int kNesting = 200;
11146 LocalContext context;
11147 v8::Isolate* isolate = context->GetIsolate();
11148 v8::HandleScope scope0(isolate);
11149 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11151 v8::HandleScope scope1(isolate);
11152 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11153 for (int i = 0; i < kIterations; i++) {
11154 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11155 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11158 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11160 v8::HandleScope scope2(CcTest::isolate());
11161 for (int j = 0; j < kIterations; j++) {
11162 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11163 CHECK_EQ(j + 1 + kIterations,
11164 v8::HandleScope::NumberOfHandles(isolate));
11167 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11169 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11170 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11174 static void InterceptorHasOwnPropertyGetter(
11175 Local<String> name,
11176 const v8::PropertyCallbackInfo<v8::Value>& info) {
11177 ApiTestFuzzer::Fuzz();
11181 THREADED_TEST(InterceptorHasOwnProperty) {
11182 LocalContext context;
11183 v8::Isolate* isolate = context->GetIsolate();
11184 v8::HandleScope scope(isolate);
11185 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11186 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11187 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11188 Local<Function> function = fun_templ->GetFunction();
11189 context->Global()->Set(v8_str("constructor"), function);
11190 v8::Handle<Value> value = CompileRun(
11191 "var o = new constructor();"
11192 "o.hasOwnProperty('ostehaps');");
11193 CHECK_EQ(false, value->BooleanValue());
11194 value = CompileRun(
11196 "o.hasOwnProperty('ostehaps');");
11197 CHECK_EQ(true, value->BooleanValue());
11198 value = CompileRun(
11199 "var p = new constructor();"
11200 "p.hasOwnProperty('ostehaps');");
11201 CHECK_EQ(false, value->BooleanValue());
11205 static void InterceptorHasOwnPropertyGetterGC(
11206 Local<String> name,
11207 const v8::PropertyCallbackInfo<v8::Value>& info) {
11208 ApiTestFuzzer::Fuzz();
11209 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11213 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11214 LocalContext context;
11215 v8::Isolate* isolate = context->GetIsolate();
11216 v8::HandleScope scope(isolate);
11217 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11218 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11219 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11220 Local<Function> function = fun_templ->GetFunction();
11221 context->Global()->Set(v8_str("constructor"), function);
11222 // Let's first make some stuff so we can be sure to get a good GC.
11224 "function makestr(size) {"
11226 " case 1: return 'f';"
11227 " case 2: return 'fo';"
11228 " case 3: return 'foo';"
11230 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11232 "var x = makestr(12345);"
11233 "x = makestr(31415);"
11234 "x = makestr(23456);");
11235 v8::Handle<Value> value = CompileRun(
11236 "var o = new constructor();"
11237 "o.__proto__ = new String(x);"
11238 "o.hasOwnProperty('ostehaps');");
11239 CHECK_EQ(false, value->BooleanValue());
11243 typedef void (*NamedPropertyGetter)(
11244 Local<String> property,
11245 const v8::PropertyCallbackInfo<v8::Value>& info);
11248 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11249 const char* source,
11251 v8::Isolate* isolate = CcTest::isolate();
11252 v8::HandleScope scope(isolate);
11253 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11254 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11255 LocalContext context;
11256 context->Global()->Set(v8_str("o"), templ->NewInstance());
11257 v8::Handle<Value> value = CompileRun(source);
11258 CHECK_EQ(expected, value->Int32Value());
11262 static void InterceptorLoadICGetter(
11263 Local<String> name,
11264 const v8::PropertyCallbackInfo<v8::Value>& info) {
11265 ApiTestFuzzer::Fuzz();
11266 v8::Isolate* isolate = CcTest::isolate();
11267 CHECK_EQ(isolate, info.GetIsolate());
11268 CHECK_EQ(v8_str("data"), info.Data());
11269 CHECK_EQ(v8_str("x"), name);
11270 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11274 // This test should hit the load IC for the interceptor case.
11275 THREADED_TEST(InterceptorLoadIC) {
11276 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11278 "for (var i = 0; i < 1000; i++) {"
11285 // Below go several tests which verify that JITing for various
11286 // configurations of interceptor and explicit fields works fine
11287 // (those cases are special cased to get better performance).
11289 static void InterceptorLoadXICGetter(
11290 Local<String> name,
11291 const v8::PropertyCallbackInfo<v8::Value>& info) {
11292 ApiTestFuzzer::Fuzz();
11293 info.GetReturnValue().Set(
11294 v8_str("x")->Equals(name) ?
11295 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11296 v8::Handle<v8::Value>());
11300 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11301 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11304 "for (var i = 0; i < 1000; i++) {"
11311 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11312 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11314 "o.__proto__ = { 'y': 239 };"
11315 "for (var i = 0; i < 1000; i++) {"
11316 " result = o.y + o.x;"
11322 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11323 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11325 "o.__proto__.y = 239;"
11326 "for (var i = 0; i < 1000; i++) {"
11327 " result = o.y + o.x;"
11333 THREADED_TEST(InterceptorLoadICUndefined) {
11334 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11336 "for (var i = 0; i < 1000; i++) {"
11337 " result = (o.y == undefined) ? 239 : 42;"
11343 THREADED_TEST(InterceptorLoadICWithOverride) {
11344 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11345 "fst = new Object(); fst.__proto__ = o;"
11346 "snd = new Object(); snd.__proto__ = fst;"
11348 "for (var i = 0; i < 1000; i++) {"
11349 " result1 = snd.x;"
11353 "for (var i = 0; i < 1000; i++) {"
11356 "result + result1",
11361 // Test the case when we stored field into
11362 // a stub, but interceptor produced value on its own.
11363 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11364 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11365 "proto = new Object();"
11366 "o.__proto__ = proto;"
11368 "for (var i = 0; i < 1000; i++) {"
11370 // Now it should be ICed and keep a reference to x defined on proto
11373 "for (var i = 0; i < 1000; i++) {"
11381 // Test the case when we stored field into
11382 // a stub, but it got invalidated later on.
11383 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11384 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11385 "proto1 = new Object();"
11386 "proto2 = new Object();"
11387 "o.__proto__ = proto1;"
11388 "proto1.__proto__ = proto2;"
11390 "for (var i = 0; i < 1000; i++) {"
11392 // Now it should be ICed and keep a reference to y defined on proto2
11396 "for (var i = 0; i < 1000; i++) {"
11404 static int interceptor_load_not_handled_calls = 0;
11405 static void InterceptorLoadNotHandled(
11406 Local<String> name,
11407 const v8::PropertyCallbackInfo<v8::Value>& info) {
11408 ++interceptor_load_not_handled_calls;
11412 // Test how post-interceptor lookups are done in the non-cacheable
11413 // case: the interceptor should not be invoked during this lookup.
11414 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11415 interceptor_load_not_handled_calls = 0;
11416 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11417 "receiver = new Object();"
11418 "receiver.__proto__ = o;"
11419 "proto = new Object();"
11420 "/* Make proto a slow-case object. */"
11421 "for (var i = 0; i < 1000; i++) {"
11422 " proto[\"xxxxxxxx\" + i] = [];"
11425 "o.__proto__ = proto;"
11427 "for (var i = 0; i < 1000; i++) {"
11428 " result += receiver.x;"
11432 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11436 // Test the case when we stored field into
11437 // a stub, but it got invalidated later on due to override on
11438 // global object which is between interceptor and fields' holders.
11439 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11440 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11441 "o.__proto__ = this;" // set a global to be a proto of o.
11442 "this.__proto__.y = 239;"
11443 "for (var i = 0; i < 10; i++) {"
11444 " if (o.y != 239) throw 'oops: ' + o.y;"
11445 // Now it should be ICed and keep a reference to y defined on field_holder.
11447 "this.y = 42;" // Assign on a global.
11449 "for (var i = 0; i < 10; i++) {"
11457 static void SetOnThis(Local<String> name,
11458 Local<Value> value,
11459 const v8::PropertyCallbackInfo<void>& info) {
11460 Local<Object>::Cast(info.This())->ForceSet(name, value);
11464 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11465 v8::Isolate* isolate = CcTest::isolate();
11466 v8::HandleScope scope(isolate);
11467 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11468 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11469 templ->SetAccessor(v8_str("y"), Return239Callback);
11470 LocalContext context;
11471 context->Global()->Set(v8_str("o"), templ->NewInstance());
11473 // Check the case when receiver and interceptor's holder
11474 // are the same objects.
11475 v8::Handle<Value> value = CompileRun(
11477 "for (var i = 0; i < 7; i++) {"
11480 CHECK_EQ(239, value->Int32Value());
11482 // Check the case when interceptor's holder is in proto chain
11484 value = CompileRun(
11485 "r = { __proto__: o };"
11487 "for (var i = 0; i < 7; i++) {"
11490 CHECK_EQ(239, value->Int32Value());
11494 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11495 v8::Isolate* isolate = CcTest::isolate();
11496 v8::HandleScope scope(isolate);
11497 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11498 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11499 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11500 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11502 LocalContext context;
11503 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11504 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11506 // Check the case when receiver and interceptor's holder
11507 // are the same objects.
11508 v8::Handle<Value> value = CompileRun(
11511 "for (var i = 0; i < 7; i++) {"
11512 " result = o.x + o.y;"
11514 CHECK_EQ(239 + 42, value->Int32Value());
11516 // Check the case when interceptor's holder is in proto chain
11518 value = CompileRun(
11519 "r = { __proto__: o };"
11521 "for (var i = 0; i < 7; i++) {"
11522 " result = r.x + r.y;"
11524 CHECK_EQ(239 + 42, value->Int32Value());
11528 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11529 v8::Isolate* isolate = CcTest::isolate();
11530 v8::HandleScope scope(isolate);
11531 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11532 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11533 templ->SetAccessor(v8_str("y"), Return239Callback);
11535 LocalContext context;
11536 context->Global()->Set(v8_str("o"), templ->NewInstance());
11538 v8::Handle<Value> value = CompileRun(
11539 "fst = new Object(); fst.__proto__ = o;"
11540 "snd = new Object(); snd.__proto__ = fst;"
11542 "for (var i = 0; i < 7; i++) {"
11543 " result1 = snd.x;"
11547 "for (var i = 0; i < 7; i++) {"
11550 "result + result1");
11551 CHECK_EQ(239 + 42, value->Int32Value());
11555 // Test the case when we stored callback into
11556 // a stub, but interceptor produced value on its own.
11557 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11558 v8::Isolate* isolate = CcTest::isolate();
11559 v8::HandleScope scope(isolate);
11560 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11561 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11562 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11563 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11565 LocalContext context;
11566 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11567 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11569 v8::Handle<Value> value = CompileRun(
11571 "for (var i = 0; i < 7; i++) {"
11573 // Now it should be ICed and keep a reference to x defined on p
11576 "for (var i = 0; i < 7; i++) {"
11580 CHECK_EQ(42 * 7, value->Int32Value());
11584 // Test the case when we stored callback into
11585 // a stub, but it got invalidated later on.
11586 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11587 v8::Isolate* isolate = CcTest::isolate();
11588 v8::HandleScope scope(isolate);
11589 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11590 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11591 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11592 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11594 LocalContext context;
11595 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11596 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11598 v8::Handle<Value> value = CompileRun(
11599 "inbetween = new Object();"
11600 "o.__proto__ = inbetween;"
11601 "inbetween.__proto__ = p;"
11602 "for (var i = 0; i < 10; i++) {"
11604 // Now it should be ICed and keep a reference to y defined on p
11606 "inbetween.y = 42;"
11608 "for (var i = 0; i < 10; i++) {"
11612 CHECK_EQ(42 * 10, value->Int32Value());
11616 // Test the case when we stored callback into
11617 // a stub, but it got invalidated later on due to override on
11618 // global object which is between interceptor and callbacks' holders.
11619 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11620 v8::Isolate* isolate = CcTest::isolate();
11621 v8::HandleScope scope(isolate);
11622 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11623 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11624 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11625 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11627 LocalContext context;
11628 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11629 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11631 v8::Handle<Value> value = CompileRun(
11632 "o.__proto__ = this;"
11633 "this.__proto__ = p;"
11634 "for (var i = 0; i < 10; i++) {"
11635 " if (o.y != 239) throw 'oops: ' + o.y;"
11636 // Now it should be ICed and keep a reference to y defined on p
11640 "for (var i = 0; i < 10; i++) {"
11644 CHECK_EQ(42 * 10, value->Int32Value());
11648 static void InterceptorLoadICGetter0(
11649 Local<String> name,
11650 const v8::PropertyCallbackInfo<v8::Value>& info) {
11651 ApiTestFuzzer::Fuzz();
11652 CHECK(v8_str("x")->Equals(name));
11653 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11657 THREADED_TEST(InterceptorReturningZero) {
11658 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11659 "o.x == undefined ? 1 : 0",
11664 static void InterceptorStoreICSetter(
11666 Local<Value> value,
11667 const v8::PropertyCallbackInfo<v8::Value>& info) {
11668 CHECK(v8_str("x")->Equals(key));
11669 CHECK_EQ(42, value->Int32Value());
11670 info.GetReturnValue().Set(value);
11674 // This test should hit the store IC for the interceptor case.
11675 THREADED_TEST(InterceptorStoreIC) {
11676 v8::Isolate* isolate = CcTest::isolate();
11677 v8::HandleScope scope(isolate);
11678 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11679 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11680 InterceptorStoreICSetter,
11681 0, 0, 0, v8_str("data"));
11682 LocalContext context;
11683 context->Global()->Set(v8_str("o"), templ->NewInstance());
11685 "for (var i = 0; i < 1000; i++) {"
11691 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11692 v8::Isolate* isolate = CcTest::isolate();
11693 v8::HandleScope scope(isolate);
11694 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11695 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11696 LocalContext context;
11697 context->Global()->Set(v8_str("o"), templ->NewInstance());
11698 v8::Handle<Value> value = CompileRun(
11699 "for (var i = 0; i < 1000; i++) {"
11703 CHECK_EQ(239 + 42, value->Int32Value());
11709 v8::Handle<Value> call_ic_function;
11710 v8::Handle<Value> call_ic_function2;
11711 v8::Handle<Value> call_ic_function3;
11713 static void InterceptorCallICGetter(
11714 Local<String> name,
11715 const v8::PropertyCallbackInfo<v8::Value>& info) {
11716 ApiTestFuzzer::Fuzz();
11717 CHECK(v8_str("x")->Equals(name));
11718 info.GetReturnValue().Set(call_ic_function);
11722 // This test should hit the call IC for the interceptor case.
11723 THREADED_TEST(InterceptorCallIC) {
11724 v8::Isolate* isolate = CcTest::isolate();
11725 v8::HandleScope scope(isolate);
11726 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11727 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11728 LocalContext context;
11729 context->Global()->Set(v8_str("o"), templ->NewInstance());
11731 v8_compile("function f(x) { return x + 1; }; f")->Run();
11732 v8::Handle<Value> value = CompileRun(
11734 "for (var i = 0; i < 1000; i++) {"
11735 " result = o.x(41);"
11737 CHECK_EQ(42, value->Int32Value());
11741 // This test checks that if interceptor doesn't provide
11742 // a value, we can fetch regular value.
11743 THREADED_TEST(InterceptorCallICSeesOthers) {
11744 v8::Isolate* isolate = CcTest::isolate();
11745 v8::HandleScope scope(isolate);
11746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11747 templ->SetNamedPropertyHandler(NoBlockGetterX);
11748 LocalContext context;
11749 context->Global()->Set(v8_str("o"), templ->NewInstance());
11750 v8::Handle<Value> value = CompileRun(
11751 "o.x = function f(x) { return x + 1; };"
11753 "for (var i = 0; i < 7; i++) {"
11754 " result = o.x(41);"
11756 CHECK_EQ(42, value->Int32Value());
11760 static v8::Handle<Value> call_ic_function4;
11761 static void InterceptorCallICGetter4(
11762 Local<String> name,
11763 const v8::PropertyCallbackInfo<v8::Value>& info) {
11764 ApiTestFuzzer::Fuzz();
11765 CHECK(v8_str("x")->Equals(name));
11766 info.GetReturnValue().Set(call_ic_function4);
11770 // This test checks that if interceptor provides a function,
11771 // even if we cached shadowed variant, interceptor's function
11773 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11774 v8::Isolate* isolate = CcTest::isolate();
11775 v8::HandleScope scope(isolate);
11776 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11777 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11778 LocalContext context;
11779 context->Global()->Set(v8_str("o"), templ->NewInstance());
11780 call_ic_function4 =
11781 v8_compile("function f(x) { return x - 1; }; f")->Run();
11782 v8::Handle<Value> value = CompileRun(
11783 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11785 "for (var i = 0; i < 1000; i++) {"
11786 " result = o.x(42);"
11788 CHECK_EQ(41, value->Int32Value());
11792 // Test the case when we stored cacheable lookup into
11793 // a stub, but it got invalidated later on
11794 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11795 v8::Isolate* isolate = CcTest::isolate();
11796 v8::HandleScope scope(isolate);
11797 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11798 templ->SetNamedPropertyHandler(NoBlockGetterX);
11799 LocalContext context;
11800 context->Global()->Set(v8_str("o"), templ->NewInstance());
11801 v8::Handle<Value> value = CompileRun(
11802 "proto1 = new Object();"
11803 "proto2 = new Object();"
11804 "o.__proto__ = proto1;"
11805 "proto1.__proto__ = proto2;"
11806 "proto2.y = function(x) { return x + 1; };"
11807 // Invoke it many times to compile a stub
11808 "for (var i = 0; i < 7; i++) {"
11811 "proto1.y = function(x) { return x - 1; };"
11813 "for (var i = 0; i < 7; i++) {"
11814 " result += o.y(42);"
11816 CHECK_EQ(41 * 7, value->Int32Value());
11820 // This test checks that if interceptor doesn't provide a function,
11821 // cached constant function is used
11822 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11823 v8::Isolate* isolate = CcTest::isolate();
11824 v8::HandleScope scope(isolate);
11825 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11826 templ->SetNamedPropertyHandler(NoBlockGetterX);
11827 LocalContext context;
11828 context->Global()->Set(v8_str("o"), templ->NewInstance());
11829 v8::Handle<Value> value = CompileRun(
11830 "function inc(x) { return x + 1; };"
11834 "for (var i = 0; i < 1000; i++) {"
11835 " result = o.x(42);"
11837 CHECK_EQ(43, value->Int32Value());
11841 static v8::Handle<Value> call_ic_function5;
11842 static void InterceptorCallICGetter5(
11843 Local<String> name,
11844 const v8::PropertyCallbackInfo<v8::Value>& info) {
11845 ApiTestFuzzer::Fuzz();
11846 if (v8_str("x")->Equals(name))
11847 info.GetReturnValue().Set(call_ic_function5);
11851 // This test checks that if interceptor provides a function,
11852 // even if we cached constant function, interceptor's function
11854 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11855 v8::Isolate* isolate = CcTest::isolate();
11856 v8::HandleScope scope(isolate);
11857 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11858 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11859 LocalContext context;
11860 context->Global()->Set(v8_str("o"), templ->NewInstance());
11861 call_ic_function5 =
11862 v8_compile("function f(x) { return x - 1; }; f")->Run();
11863 v8::Handle<Value> value = CompileRun(
11864 "function inc(x) { return x + 1; };"
11868 "for (var i = 0; i < 1000; i++) {"
11869 " result = o.x(42);"
11871 CHECK_EQ(41, value->Int32Value());
11875 static v8::Handle<Value> call_ic_function6;
11876 static void InterceptorCallICGetter6(
11877 Local<String> name,
11878 const v8::PropertyCallbackInfo<v8::Value>& info) {
11879 ApiTestFuzzer::Fuzz();
11880 if (v8_str("x")->Equals(name))
11881 info.GetReturnValue().Set(call_ic_function6);
11885 // Same test as above, except the code is wrapped in a function
11886 // to test the optimized compiler.
11887 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11888 i::FLAG_allow_natives_syntax = true;
11889 v8::Isolate* isolate = CcTest::isolate();
11890 v8::HandleScope scope(isolate);
11891 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11892 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11893 LocalContext context;
11894 context->Global()->Set(v8_str("o"), templ->NewInstance());
11895 call_ic_function6 =
11896 v8_compile("function f(x) { return x - 1; }; f")->Run();
11897 v8::Handle<Value> value = CompileRun(
11898 "function inc(x) { return x + 1; };"
11901 "function test() {"
11903 " for (var i = 0; i < 1000; i++) {"
11904 " result = o.x(42);"
11911 "%OptimizeFunctionOnNextCall(test);"
11913 CHECK_EQ(41, value->Int32Value());
11917 // Test the case when we stored constant function into
11918 // a stub, but it got invalidated later on
11919 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11920 v8::Isolate* isolate = CcTest::isolate();
11921 v8::HandleScope scope(isolate);
11922 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11923 templ->SetNamedPropertyHandler(NoBlockGetterX);
11924 LocalContext context;
11925 context->Global()->Set(v8_str("o"), templ->NewInstance());
11926 v8::Handle<Value> value = CompileRun(
11927 "function inc(x) { return x + 1; };"
11929 "proto1 = new Object();"
11930 "proto2 = new Object();"
11931 "o.__proto__ = proto1;"
11932 "proto1.__proto__ = proto2;"
11934 // Invoke it many times to compile a stub
11935 "for (var i = 0; i < 7; i++) {"
11938 "proto1.y = function(x) { return x - 1; };"
11940 "for (var i = 0; i < 7; i++) {"
11941 " result += o.y(42);"
11943 CHECK_EQ(41 * 7, value->Int32Value());
11947 // Test the case when we stored constant function into
11948 // a stub, but it got invalidated later on due to override on
11949 // global object which is between interceptor and constant function' holders.
11950 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11951 v8::Isolate* isolate = CcTest::isolate();
11952 v8::HandleScope scope(isolate);
11953 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11954 templ->SetNamedPropertyHandler(NoBlockGetterX);
11955 LocalContext context;
11956 context->Global()->Set(v8_str("o"), templ->NewInstance());
11957 v8::Handle<Value> value = CompileRun(
11958 "function inc(x) { return x + 1; };"
11960 "o.__proto__ = this;"
11961 "this.__proto__.y = inc;"
11962 // Invoke it many times to compile a stub
11963 "for (var i = 0; i < 7; i++) {"
11964 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11966 "this.y = function(x) { return x - 1; };"
11968 "for (var i = 0; i < 7; i++) {"
11969 " result += o.y(42);"
11971 CHECK_EQ(41 * 7, value->Int32Value());
11975 // Test the case when actual function to call sits on global object.
11976 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11977 v8::Isolate* isolate = CcTest::isolate();
11978 v8::HandleScope scope(isolate);
11979 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11980 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11982 LocalContext context;
11983 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11985 v8::Handle<Value> value = CompileRun(
11987 " o.__proto__ = this;"
11988 " for (var i = 0; i < 10; i++) {"
11989 " var v = o.parseFloat('239');"
11990 " if (v != 239) throw v;"
11991 // Now it should be ICed and keep a reference to parseFloat.
11994 " for (var i = 0; i < 10; i++) {"
11995 " result += o.parseFloat('239');"
12001 CHECK_EQ(239 * 10, value->Int32Value());
12004 static void InterceptorCallICFastApi(
12005 Local<String> name,
12006 const v8::PropertyCallbackInfo<v8::Value>& info) {
12007 ApiTestFuzzer::Fuzz();
12008 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12010 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12012 if ((*call_count) % 20 == 0) {
12013 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12017 static void FastApiCallback_TrivialSignature(
12018 const v8::FunctionCallbackInfo<v8::Value>& args) {
12019 ApiTestFuzzer::Fuzz();
12020 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12021 v8::Isolate* isolate = CcTest::isolate();
12022 CHECK_EQ(isolate, args.GetIsolate());
12023 CHECK_EQ(args.This(), args.Holder());
12024 CHECK(args.Data()->Equals(v8_str("method_data")));
12025 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12028 static void FastApiCallback_SimpleSignature(
12029 const v8::FunctionCallbackInfo<v8::Value>& args) {
12030 ApiTestFuzzer::Fuzz();
12031 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12032 v8::Isolate* isolate = CcTest::isolate();
12033 CHECK_EQ(isolate, args.GetIsolate());
12034 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12035 CHECK(args.Data()->Equals(v8_str("method_data")));
12036 // Note, we're using HasRealNamedProperty instead of Has to avoid
12037 // invoking the interceptor again.
12038 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12039 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12043 // Helper to maximize the odds of object moving.
12044 static void GenerateSomeGarbage() {
12047 "for (var i = 0; i < 1000; i++) {"
12048 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12050 "garbage = undefined;");
12054 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12055 static int count = 0;
12056 if (count++ % 3 == 0) {
12057 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12058 // This should move the stub
12059 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12064 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12065 LocalContext context;
12066 v8::Isolate* isolate = context->GetIsolate();
12067 v8::HandleScope scope(isolate);
12068 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12069 v8::ObjectTemplate::New(isolate);
12070 nativeobject_templ->Set(isolate, "callback",
12071 v8::FunctionTemplate::New(isolate,
12072 DirectApiCallback));
12073 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12074 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12075 // call the api function multiple times to ensure direct call stub creation.
12078 " for (var i = 1; i <= 30; i++) {"
12079 " nativeobject.callback();"
12086 void ThrowingDirectApiCallback(
12087 const v8::FunctionCallbackInfo<v8::Value>& args) {
12088 args.GetIsolate()->ThrowException(v8_str("g"));
12092 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12093 LocalContext context;
12094 v8::Isolate* isolate = context->GetIsolate();
12095 v8::HandleScope scope(isolate);
12096 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12097 v8::ObjectTemplate::New(isolate);
12098 nativeobject_templ->Set(isolate, "callback",
12099 v8::FunctionTemplate::New(isolate,
12100 ThrowingDirectApiCallback));
12101 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12102 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12103 // call the api function multiple times to ensure direct call stub creation.
12104 v8::Handle<Value> result = CompileRun(
12107 " for (var i = 1; i <= 5; i++) {"
12108 " try { nativeobject.callback(); } catch (e) { result += e; }"
12112 CHECK_EQ(v8_str("ggggg"), result);
12116 static Handle<Value> DoDirectGetter() {
12117 if (++p_getter_count % 3 == 0) {
12118 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12119 GenerateSomeGarbage();
12121 return v8_str("Direct Getter Result");
12124 static void DirectGetterCallback(
12125 Local<String> name,
12126 const v8::PropertyCallbackInfo<v8::Value>& info) {
12127 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12128 info.GetReturnValue().Set(DoDirectGetter());
12132 template<typename Accessor>
12133 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12134 LocalContext context;
12135 v8::Isolate* isolate = context->GetIsolate();
12136 v8::HandleScope scope(isolate);
12137 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12138 obj->SetAccessor(v8_str("p1"), accessor);
12139 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12140 p_getter_count = 0;
12141 v8::Handle<v8::Value> result = CompileRun(
12143 " for (var i = 0; i < 30; i++) o1.p1;"
12147 CHECK_EQ(v8_str("Direct Getter Result"), result);
12148 CHECK_EQ(31, p_getter_count);
12152 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12153 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12157 void ThrowingDirectGetterCallback(
12158 Local<String> name,
12159 const v8::PropertyCallbackInfo<v8::Value>& info) {
12160 info.GetIsolate()->ThrowException(v8_str("g"));
12164 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12165 LocalContext context;
12166 v8::Isolate* isolate = context->GetIsolate();
12167 v8::HandleScope scope(isolate);
12168 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12169 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12170 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12171 v8::Handle<Value> result = CompileRun(
12173 "for (var i = 0; i < 5; i++) {"
12174 " try { o1.p1; } catch (e) { result += e; }"
12177 CHECK_EQ(v8_str("ggggg"), result);
12181 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12182 int interceptor_call_count = 0;
12183 v8::Isolate* isolate = CcTest::isolate();
12184 v8::HandleScope scope(isolate);
12185 v8::Handle<v8::FunctionTemplate> fun_templ =
12186 v8::FunctionTemplate::New(isolate);
12187 v8::Handle<v8::FunctionTemplate> method_templ =
12188 v8::FunctionTemplate::New(isolate,
12189 FastApiCallback_TrivialSignature,
12190 v8_str("method_data"),
12191 v8::Handle<v8::Signature>());
12192 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12193 proto_templ->Set(v8_str("method"), method_templ);
12194 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12195 templ->SetNamedPropertyHandler(
12196 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12197 v8::External::New(isolate, &interceptor_call_count));
12198 LocalContext context;
12199 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12200 GenerateSomeGarbage();
12201 context->Global()->Set(v8_str("o"), fun->NewInstance());
12204 "for (var i = 0; i < 100; i++) {"
12205 " result = o.method(41);"
12207 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12208 CHECK_EQ(100, interceptor_call_count);
12212 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12213 int interceptor_call_count = 0;
12214 v8::Isolate* isolate = CcTest::isolate();
12215 v8::HandleScope scope(isolate);
12216 v8::Handle<v8::FunctionTemplate> fun_templ =
12217 v8::FunctionTemplate::New(isolate);
12218 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12219 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12220 v8::Signature::New(isolate, fun_templ));
12221 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12222 proto_templ->Set(v8_str("method"), method_templ);
12223 fun_templ->SetHiddenPrototype(true);
12224 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12225 templ->SetNamedPropertyHandler(
12226 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12227 v8::External::New(isolate, &interceptor_call_count));
12228 LocalContext context;
12229 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12230 GenerateSomeGarbage();
12231 context->Global()->Set(v8_str("o"), fun->NewInstance());
12234 "var receiver = {};"
12235 "receiver.__proto__ = o;"
12237 "for (var i = 0; i < 100; i++) {"
12238 " result = receiver.method(41);"
12240 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12241 CHECK_EQ(100, interceptor_call_count);
12245 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12246 int interceptor_call_count = 0;
12247 v8::Isolate* isolate = CcTest::isolate();
12248 v8::HandleScope scope(isolate);
12249 v8::Handle<v8::FunctionTemplate> fun_templ =
12250 v8::FunctionTemplate::New(isolate);
12251 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12252 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12253 v8::Signature::New(isolate, fun_templ));
12254 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12255 proto_templ->Set(v8_str("method"), method_templ);
12256 fun_templ->SetHiddenPrototype(true);
12257 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12258 templ->SetNamedPropertyHandler(
12259 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12260 v8::External::New(isolate, &interceptor_call_count));
12261 LocalContext context;
12262 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12263 GenerateSomeGarbage();
12264 context->Global()->Set(v8_str("o"), fun->NewInstance());
12267 "var receiver = {};"
12268 "receiver.__proto__ = o;"
12270 "var saved_result = 0;"
12271 "for (var i = 0; i < 100; i++) {"
12272 " result = receiver.method(41);"
12274 " saved_result = result;"
12275 " receiver = {method: function(x) { return x - 1 }};"
12278 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12279 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12280 CHECK_GE(interceptor_call_count, 50);
12284 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12285 int interceptor_call_count = 0;
12286 v8::Isolate* isolate = CcTest::isolate();
12287 v8::HandleScope scope(isolate);
12288 v8::Handle<v8::FunctionTemplate> fun_templ =
12289 v8::FunctionTemplate::New(isolate);
12290 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12291 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12292 v8::Signature::New(isolate, fun_templ));
12293 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12294 proto_templ->Set(v8_str("method"), method_templ);
12295 fun_templ->SetHiddenPrototype(true);
12296 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12297 templ->SetNamedPropertyHandler(
12298 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12299 v8::External::New(isolate, &interceptor_call_count));
12300 LocalContext context;
12301 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12302 GenerateSomeGarbage();
12303 context->Global()->Set(v8_str("o"), fun->NewInstance());
12306 "var receiver = {};"
12307 "receiver.__proto__ = o;"
12309 "var saved_result = 0;"
12310 "for (var i = 0; i < 100; i++) {"
12311 " result = receiver.method(41);"
12313 " saved_result = result;"
12314 " o.method = function(x) { return x - 1 };"
12317 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12318 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12319 CHECK_GE(interceptor_call_count, 50);
12323 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12324 int interceptor_call_count = 0;
12325 v8::Isolate* isolate = CcTest::isolate();
12326 v8::HandleScope scope(isolate);
12327 v8::Handle<v8::FunctionTemplate> fun_templ =
12328 v8::FunctionTemplate::New(isolate);
12329 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12330 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12331 v8::Signature::New(isolate, fun_templ));
12332 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12333 proto_templ->Set(v8_str("method"), method_templ);
12334 fun_templ->SetHiddenPrototype(true);
12335 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12336 templ->SetNamedPropertyHandler(
12337 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12338 v8::External::New(isolate, &interceptor_call_count));
12339 LocalContext context;
12340 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12341 GenerateSomeGarbage();
12342 context->Global()->Set(v8_str("o"), fun->NewInstance());
12343 v8::TryCatch try_catch;
12346 "var receiver = {};"
12347 "receiver.__proto__ = o;"
12349 "var saved_result = 0;"
12350 "for (var i = 0; i < 100; i++) {"
12351 " result = receiver.method(41);"
12353 " saved_result = result;"
12357 CHECK(try_catch.HasCaught());
12358 // TODO(verwaest): Adjust message.
12359 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12360 try_catch.Exception()->ToString());
12361 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12362 CHECK_GE(interceptor_call_count, 50);
12366 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12367 int interceptor_call_count = 0;
12368 v8::Isolate* isolate = CcTest::isolate();
12369 v8::HandleScope scope(isolate);
12370 v8::Handle<v8::FunctionTemplate> fun_templ =
12371 v8::FunctionTemplate::New(isolate);
12372 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12373 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12374 v8::Signature::New(isolate, fun_templ));
12375 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12376 proto_templ->Set(v8_str("method"), method_templ);
12377 fun_templ->SetHiddenPrototype(true);
12378 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12379 templ->SetNamedPropertyHandler(
12380 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12381 v8::External::New(isolate, &interceptor_call_count));
12382 LocalContext context;
12383 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12384 GenerateSomeGarbage();
12385 context->Global()->Set(v8_str("o"), fun->NewInstance());
12386 v8::TryCatch try_catch;
12389 "var receiver = {};"
12390 "receiver.__proto__ = o;"
12392 "var saved_result = 0;"
12393 "for (var i = 0; i < 100; i++) {"
12394 " result = receiver.method(41);"
12396 " saved_result = result;"
12397 " receiver = {method: receiver.method};"
12400 CHECK(try_catch.HasCaught());
12401 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12402 try_catch.Exception()->ToString());
12403 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12404 CHECK_GE(interceptor_call_count, 50);
12408 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12409 v8::Isolate* isolate = CcTest::isolate();
12410 v8::HandleScope scope(isolate);
12411 v8::Handle<v8::FunctionTemplate> fun_templ =
12412 v8::FunctionTemplate::New(isolate);
12413 v8::Handle<v8::FunctionTemplate> method_templ =
12414 v8::FunctionTemplate::New(isolate,
12415 FastApiCallback_TrivialSignature,
12416 v8_str("method_data"),
12417 v8::Handle<v8::Signature>());
12418 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12419 proto_templ->Set(v8_str("method"), method_templ);
12420 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12422 LocalContext context;
12423 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12424 GenerateSomeGarbage();
12425 context->Global()->Set(v8_str("o"), fun->NewInstance());
12428 "for (var i = 0; i < 100; i++) {"
12429 " result = o.method(41);"
12432 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12436 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12437 v8::Isolate* isolate = CcTest::isolate();
12438 v8::HandleScope scope(isolate);
12439 v8::Handle<v8::FunctionTemplate> fun_templ =
12440 v8::FunctionTemplate::New(isolate);
12441 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12442 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12443 v8::Signature::New(isolate, fun_templ));
12444 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12445 proto_templ->Set(v8_str("method"), method_templ);
12446 fun_templ->SetHiddenPrototype(true);
12447 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12448 CHECK(!templ.IsEmpty());
12449 LocalContext context;
12450 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12451 GenerateSomeGarbage();
12452 context->Global()->Set(v8_str("o"), fun->NewInstance());
12455 "var receiver = {};"
12456 "receiver.__proto__ = o;"
12458 "for (var i = 0; i < 100; i++) {"
12459 " result = receiver.method(41);"
12462 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12466 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12467 v8::Isolate* isolate = CcTest::isolate();
12468 v8::HandleScope scope(isolate);
12469 v8::Handle<v8::FunctionTemplate> fun_templ =
12470 v8::FunctionTemplate::New(isolate);
12471 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12472 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12473 v8::Signature::New(isolate, fun_templ));
12474 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12475 proto_templ->Set(v8_str("method"), method_templ);
12476 fun_templ->SetHiddenPrototype(true);
12477 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12478 CHECK(!templ.IsEmpty());
12479 LocalContext context;
12480 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12481 GenerateSomeGarbage();
12482 context->Global()->Set(v8_str("o"), fun->NewInstance());
12485 "var receiver = {};"
12486 "receiver.__proto__ = o;"
12488 "var saved_result = 0;"
12489 "for (var i = 0; i < 100; i++) {"
12490 " result = receiver.method(41);"
12492 " saved_result = result;"
12493 " receiver = {method: function(x) { return x - 1 }};"
12496 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12497 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12501 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12502 v8::Isolate* isolate = CcTest::isolate();
12503 v8::HandleScope scope(isolate);
12504 v8::Handle<v8::FunctionTemplate> fun_templ =
12505 v8::FunctionTemplate::New(isolate);
12506 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12507 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12508 v8::Signature::New(isolate, fun_templ));
12509 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12510 proto_templ->Set(v8_str("method"), method_templ);
12511 fun_templ->SetHiddenPrototype(true);
12512 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12513 CHECK(!templ.IsEmpty());
12514 LocalContext context;
12515 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12516 GenerateSomeGarbage();
12517 context->Global()->Set(v8_str("o"), fun->NewInstance());
12518 v8::TryCatch try_catch;
12521 "var receiver = {};"
12522 "receiver.__proto__ = o;"
12524 "var saved_result = 0;"
12525 "for (var i = 0; i < 100; i++) {"
12526 " result = receiver.method(41);"
12528 " saved_result = result;"
12532 CHECK(try_catch.HasCaught());
12533 // TODO(verwaest): Adjust message.
12534 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12535 try_catch.Exception()->ToString());
12536 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12540 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12541 v8::Isolate* isolate = CcTest::isolate();
12542 v8::HandleScope scope(isolate);
12543 v8::Handle<v8::FunctionTemplate> fun_templ =
12544 v8::FunctionTemplate::New(isolate);
12545 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12546 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12547 v8::Signature::New(isolate, fun_templ));
12548 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12549 proto_templ->Set(v8_str("method"), method_templ);
12550 fun_templ->SetHiddenPrototype(true);
12551 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12552 CHECK(!templ.IsEmpty());
12553 LocalContext context;
12554 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12555 GenerateSomeGarbage();
12556 context->Global()->Set(v8_str("o"), fun->NewInstance());
12557 v8::TryCatch try_catch;
12560 "var receiver = {};"
12561 "receiver.__proto__ = o;"
12563 "var saved_result = 0;"
12564 "for (var i = 0; i < 100; i++) {"
12565 " result = receiver.method(41);"
12567 " saved_result = result;"
12568 " receiver = Object.create(receiver);"
12571 CHECK(try_catch.HasCaught());
12572 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12573 try_catch.Exception()->ToString());
12574 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12578 v8::Handle<Value> keyed_call_ic_function;
12580 static void InterceptorKeyedCallICGetter(
12581 Local<String> name,
12582 const v8::PropertyCallbackInfo<v8::Value>& info) {
12583 ApiTestFuzzer::Fuzz();
12584 if (v8_str("x")->Equals(name)) {
12585 info.GetReturnValue().Set(keyed_call_ic_function);
12590 // Test the case when we stored cacheable lookup into
12591 // a stub, but the function name changed (to another cacheable function).
12592 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12593 v8::Isolate* isolate = CcTest::isolate();
12594 v8::HandleScope scope(isolate);
12595 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12596 templ->SetNamedPropertyHandler(NoBlockGetterX);
12597 LocalContext context;
12598 context->Global()->Set(v8_str("o"), templ->NewInstance());
12600 "proto = new Object();"
12601 "proto.y = function(x) { return x + 1; };"
12602 "proto.z = function(x) { return x - 1; };"
12603 "o.__proto__ = proto;"
12605 "var method = 'y';"
12606 "for (var i = 0; i < 10; i++) {"
12607 " if (i == 5) { method = 'z'; };"
12608 " result += o[method](41);"
12610 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12614 // Test the case when we stored cacheable lookup into
12615 // a stub, but the function name changed (and the new function is present
12616 // both before and after the interceptor in the prototype chain).
12617 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12618 v8::Isolate* isolate = CcTest::isolate();
12619 v8::HandleScope scope(isolate);
12620 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12621 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12622 LocalContext context;
12623 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12624 keyed_call_ic_function =
12625 v8_compile("function f(x) { return x - 1; }; f")->Run();
12627 "o = new Object();"
12628 "proto2 = new Object();"
12629 "o.y = function(x) { return x + 1; };"
12630 "proto2.y = function(x) { return x + 2; };"
12631 "o.__proto__ = proto1;"
12632 "proto1.__proto__ = proto2;"
12634 "var method = 'x';"
12635 "for (var i = 0; i < 10; i++) {"
12636 " if (i == 5) { method = 'y'; };"
12637 " result += o[method](41);"
12639 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12643 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12644 // on the global object.
12645 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12646 v8::Isolate* isolate = CcTest::isolate();
12647 v8::HandleScope scope(isolate);
12648 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12649 templ->SetNamedPropertyHandler(NoBlockGetterX);
12650 LocalContext context;
12651 context->Global()->Set(v8_str("o"), templ->NewInstance());
12653 "function inc(x) { return x + 1; };"
12655 "function dec(x) { return x - 1; };"
12657 "o.__proto__ = this;"
12658 "this.__proto__.x = inc;"
12659 "this.__proto__.y = dec;"
12661 "var method = 'x';"
12662 "for (var i = 0; i < 10; i++) {"
12663 " if (i == 5) { method = 'y'; };"
12664 " result += o[method](41);"
12666 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12670 // Test the case when actual function to call sits on global object.
12671 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12672 v8::Isolate* isolate = CcTest::isolate();
12673 v8::HandleScope scope(isolate);
12674 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12675 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12676 LocalContext context;
12677 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12680 "function len(x) { return x.length; };"
12681 "o.__proto__ = this;"
12682 "var m = 'parseFloat';"
12684 "for (var i = 0; i < 10; i++) {"
12687 " saved_result = result;"
12689 " result = o[m]('239');"
12691 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12692 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12696 // Test the map transition before the interceptor.
12697 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12698 v8::Isolate* isolate = CcTest::isolate();
12699 v8::HandleScope scope(isolate);
12700 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12701 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12702 LocalContext context;
12703 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12706 "var o = new Object();"
12707 "o.__proto__ = proto;"
12708 "o.method = function(x) { return x + 1; };"
12709 "var m = 'method';"
12711 "for (var i = 0; i < 10; i++) {"
12712 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12713 " result += o[m](41);"
12715 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12719 // Test the map transition after the interceptor.
12720 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12721 v8::Isolate* isolate = CcTest::isolate();
12722 v8::HandleScope scope(isolate);
12723 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12724 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12725 LocalContext context;
12726 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12729 "var proto = new Object();"
12730 "o.__proto__ = proto;"
12731 "proto.method = function(x) { return x + 1; };"
12732 "var m = 'method';"
12734 "for (var i = 0; i < 10; i++) {"
12735 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12736 " result += o[m](41);"
12738 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12742 static int interceptor_call_count = 0;
12744 static void InterceptorICRefErrorGetter(
12745 Local<String> name,
12746 const v8::PropertyCallbackInfo<v8::Value>& info) {
12747 ApiTestFuzzer::Fuzz();
12748 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12749 info.GetReturnValue().Set(call_ic_function2);
12754 // This test should hit load and call ICs for the interceptor case.
12755 // Once in a while, the interceptor will reply that a property was not
12756 // found in which case we should get a reference error.
12757 THREADED_TEST(InterceptorICReferenceErrors) {
12758 v8::Isolate* isolate = CcTest::isolate();
12759 v8::HandleScope scope(isolate);
12760 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12762 LocalContext context(0, templ, v8::Handle<Value>());
12763 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12764 v8::Handle<Value> value = CompileRun(
12766 " for (var i = 0; i < 1000; i++) {"
12767 " try { x; } catch(e) { return true; }"
12772 CHECK_EQ(true, value->BooleanValue());
12773 interceptor_call_count = 0;
12774 value = CompileRun(
12776 " for (var i = 0; i < 1000; i++) {"
12777 " try { x(42); } catch(e) { return true; }"
12782 CHECK_EQ(true, value->BooleanValue());
12786 static int interceptor_ic_exception_get_count = 0;
12788 static void InterceptorICExceptionGetter(
12789 Local<String> name,
12790 const v8::PropertyCallbackInfo<v8::Value>& info) {
12791 ApiTestFuzzer::Fuzz();
12792 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12793 info.GetReturnValue().Set(call_ic_function3);
12795 if (interceptor_ic_exception_get_count == 20) {
12796 info.GetIsolate()->ThrowException(v8_num(42));
12802 // Test interceptor load/call IC where the interceptor throws an
12803 // exception once in a while.
12804 THREADED_TEST(InterceptorICGetterExceptions) {
12805 interceptor_ic_exception_get_count = 0;
12806 v8::Isolate* isolate = CcTest::isolate();
12807 v8::HandleScope scope(isolate);
12808 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12809 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12810 LocalContext context(0, templ, v8::Handle<Value>());
12811 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12812 v8::Handle<Value> value = CompileRun(
12814 " for (var i = 0; i < 100; i++) {"
12815 " try { x; } catch(e) { return true; }"
12820 CHECK_EQ(true, value->BooleanValue());
12821 interceptor_ic_exception_get_count = 0;
12822 value = CompileRun(
12824 " for (var i = 0; i < 100; i++) {"
12825 " try { x(42); } catch(e) { return true; }"
12830 CHECK_EQ(true, value->BooleanValue());
12834 static int interceptor_ic_exception_set_count = 0;
12836 static void InterceptorICExceptionSetter(
12838 Local<Value> value,
12839 const v8::PropertyCallbackInfo<v8::Value>& info) {
12840 ApiTestFuzzer::Fuzz();
12841 if (++interceptor_ic_exception_set_count > 20) {
12842 info.GetIsolate()->ThrowException(v8_num(42));
12847 // Test interceptor store IC where the interceptor throws an exception
12848 // once in a while.
12849 THREADED_TEST(InterceptorICSetterExceptions) {
12850 interceptor_ic_exception_set_count = 0;
12851 v8::Isolate* isolate = CcTest::isolate();
12852 v8::HandleScope scope(isolate);
12853 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12854 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12855 LocalContext context(0, templ, v8::Handle<Value>());
12856 v8::Handle<Value> value = CompileRun(
12858 " for (var i = 0; i < 100; i++) {"
12859 " try { x = 42; } catch(e) { return true; }"
12864 CHECK_EQ(true, value->BooleanValue());
12868 // Test that we ignore null interceptors.
12869 THREADED_TEST(NullNamedInterceptor) {
12870 v8::Isolate* isolate = CcTest::isolate();
12871 v8::HandleScope scope(isolate);
12872 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12873 templ->SetNamedPropertyHandler(
12874 static_cast<v8::NamedPropertyGetterCallback>(0));
12875 LocalContext context;
12876 templ->Set(CcTest::isolate(), "x", v8_num(42));
12877 v8::Handle<v8::Object> obj = templ->NewInstance();
12878 context->Global()->Set(v8_str("obj"), obj);
12879 v8::Handle<Value> value = CompileRun("obj.x");
12880 CHECK(value->IsInt32());
12881 CHECK_EQ(42, value->Int32Value());
12885 // Test that we ignore null interceptors.
12886 THREADED_TEST(NullIndexedInterceptor) {
12887 v8::Isolate* isolate = CcTest::isolate();
12888 v8::HandleScope scope(isolate);
12889 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12890 templ->SetIndexedPropertyHandler(
12891 static_cast<v8::IndexedPropertyGetterCallback>(0));
12892 LocalContext context;
12893 templ->Set(CcTest::isolate(), "42", v8_num(42));
12894 v8::Handle<v8::Object> obj = templ->NewInstance();
12895 context->Global()->Set(v8_str("obj"), obj);
12896 v8::Handle<Value> value = CompileRun("obj[42]");
12897 CHECK(value->IsInt32());
12898 CHECK_EQ(42, value->Int32Value());
12902 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12903 v8::Isolate* isolate = CcTest::isolate();
12904 v8::HandleScope scope(isolate);
12905 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12906 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12908 env->Global()->Set(v8_str("obj"),
12909 templ->GetFunction()->NewInstance());
12910 ExpectTrue("obj.x === 42");
12911 ExpectTrue("!obj.propertyIsEnumerable('x')");
12915 static void ThrowingGetter(Local<String> name,
12916 const v8::PropertyCallbackInfo<v8::Value>& info) {
12917 ApiTestFuzzer::Fuzz();
12918 info.GetIsolate()->ThrowException(Handle<Value>());
12919 info.GetReturnValue().SetUndefined();
12923 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12924 LocalContext context;
12925 HandleScope scope(context->GetIsolate());
12927 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12928 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12929 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12931 Local<Object> instance = templ->GetFunction()->NewInstance();
12933 Local<Object> another = Object::New(context->GetIsolate());
12934 another->SetPrototype(instance);
12936 Local<Object> with_js_getter = CompileRun(
12938 "o.__defineGetter__('f', function() { throw undefined; });\n"
12939 "o\n").As<Object>();
12940 CHECK(!with_js_getter.IsEmpty());
12942 TryCatch try_catch;
12944 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12945 CHECK(try_catch.HasCaught());
12947 CHECK(result.IsEmpty());
12949 result = another->GetRealNamedProperty(v8_str("f"));
12950 CHECK(try_catch.HasCaught());
12952 CHECK(result.IsEmpty());
12954 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12955 CHECK(try_catch.HasCaught());
12957 CHECK(result.IsEmpty());
12959 result = another->Get(v8_str("f"));
12960 CHECK(try_catch.HasCaught());
12962 CHECK(result.IsEmpty());
12964 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12965 CHECK(try_catch.HasCaught());
12967 CHECK(result.IsEmpty());
12969 result = with_js_getter->Get(v8_str("f"));
12970 CHECK(try_catch.HasCaught());
12972 CHECK(result.IsEmpty());
12976 static void ThrowingCallbackWithTryCatch(
12977 const v8::FunctionCallbackInfo<v8::Value>& args) {
12978 TryCatch try_catch;
12979 // Verboseness is important: it triggers message delivery which can call into
12981 try_catch.SetVerbose(true);
12982 CompileRun("throw 'from JS';");
12983 CHECK(try_catch.HasCaught());
12984 CHECK(!CcTest::i_isolate()->has_pending_exception());
12985 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12989 static int call_depth;
12992 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12993 TryCatch try_catch;
12997 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12998 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13002 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13003 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13007 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13008 Handle<String> errorMessageString = message->Get();
13009 CHECK(!errorMessageString.IsEmpty());
13010 message->GetStackTrace();
13011 message->GetScriptResourceName();
13015 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13016 LocalContext context;
13017 v8::Isolate* isolate = context->GetIsolate();
13018 HandleScope scope(isolate);
13020 Local<Function> func =
13021 FunctionTemplate::New(isolate,
13022 ThrowingCallbackWithTryCatch)->GetFunction();
13023 context->Global()->Set(v8_str("func"), func);
13025 MessageCallback callbacks[] =
13026 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13027 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13028 MessageCallback callback = callbacks[i];
13029 if (callback != NULL) {
13030 V8::AddMessageListener(callback);
13032 // Some small number to control number of times message handler should
13033 // throw an exception.
13036 "var thrown = false;\n"
13037 "try { func(); } catch(e) { thrown = true; }\n"
13039 if (callback != NULL) {
13040 V8::RemoveMessageListeners(callback);
13046 static void ParentGetter(Local<String> name,
13047 const v8::PropertyCallbackInfo<v8::Value>& info) {
13048 ApiTestFuzzer::Fuzz();
13049 info.GetReturnValue().Set(v8_num(1));
13053 static void ChildGetter(Local<String> name,
13054 const v8::PropertyCallbackInfo<v8::Value>& info) {
13055 ApiTestFuzzer::Fuzz();
13056 info.GetReturnValue().Set(v8_num(42));
13060 THREADED_TEST(Overriding) {
13061 LocalContext context;
13062 v8::Isolate* isolate = context->GetIsolate();
13063 v8::HandleScope scope(isolate);
13065 // Parent template.
13066 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13067 Local<ObjectTemplate> parent_instance_templ =
13068 parent_templ->InstanceTemplate();
13069 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13071 // Template that inherits from the parent template.
13072 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13073 Local<ObjectTemplate> child_instance_templ =
13074 child_templ->InstanceTemplate();
13075 child_templ->Inherit(parent_templ);
13076 // Override 'f'. The child version of 'f' should get called for child
13078 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13079 // Add 'g' twice. The 'g' added last should get called for instances.
13080 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13081 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13083 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13084 // so 'h' can be shadowed on the instance object.
13085 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13086 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13087 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13089 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13090 // but the attribute does not have effect because it is duplicated with
13092 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13093 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13097 // Instantiate the child template.
13098 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13100 // Check that the child function overrides the parent one.
13101 context->Global()->Set(v8_str("o"), instance);
13102 Local<Value> value = v8_compile("o.f")->Run();
13103 // Check that the 'g' that was added last is hit.
13104 CHECK_EQ(42, value->Int32Value());
13105 value = v8_compile("o.g")->Run();
13106 CHECK_EQ(42, value->Int32Value());
13108 // Check that 'h' cannot be shadowed.
13109 value = v8_compile("o.h = 3; o.h")->Run();
13110 CHECK_EQ(1, value->Int32Value());
13112 // Check that 'i' cannot be shadowed or changed.
13113 value = v8_compile("o.i = 3; o.i")->Run();
13114 CHECK_EQ(42, value->Int32Value());
13118 static void IsConstructHandler(
13119 const v8::FunctionCallbackInfo<v8::Value>& args) {
13120 ApiTestFuzzer::Fuzz();
13121 args.GetReturnValue().Set(args.IsConstructCall());
13125 THREADED_TEST(IsConstructCall) {
13126 v8::Isolate* isolate = CcTest::isolate();
13127 v8::HandleScope scope(isolate);
13129 // Function template with call handler.
13130 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13131 templ->SetCallHandler(IsConstructHandler);
13133 LocalContext context;
13135 context->Global()->Set(v8_str("f"), templ->GetFunction());
13136 Local<Value> value = v8_compile("f()")->Run();
13137 CHECK(!value->BooleanValue());
13138 value = v8_compile("new f()")->Run();
13139 CHECK(value->BooleanValue());
13143 THREADED_TEST(ObjectProtoToString) {
13144 v8::Isolate* isolate = CcTest::isolate();
13145 v8::HandleScope scope(isolate);
13146 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13147 templ->SetClassName(v8_str("MyClass"));
13149 LocalContext context;
13151 Local<String> customized_tostring = v8_str("customized toString");
13153 // Replace Object.prototype.toString
13154 v8_compile("Object.prototype.toString = function() {"
13155 " return 'customized toString';"
13158 // Normal ToString call should call replaced Object.prototype.toString
13159 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13160 Local<String> value = instance->ToString();
13161 CHECK(value->IsString() && value->Equals(customized_tostring));
13163 // ObjectProtoToString should not call replace toString function.
13164 value = instance->ObjectProtoToString();
13165 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13168 value = context->Global()->ObjectProtoToString();
13169 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13171 // Check ordinary object
13172 Local<Value> object = v8_compile("new Object()")->Run();
13173 value = object.As<v8::Object>()->ObjectProtoToString();
13174 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13178 THREADED_TEST(ObjectGetConstructorName) {
13179 LocalContext context;
13180 v8::HandleScope scope(context->GetIsolate());
13181 v8_compile("function Parent() {};"
13182 "function Child() {};"
13183 "Child.prototype = new Parent();"
13184 "var outer = { inner: function() { } };"
13185 "var p = new Parent();"
13186 "var c = new Child();"
13187 "var x = new outer.inner();")->Run();
13189 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13190 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13191 v8_str("Parent")));
13193 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13194 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13197 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13198 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13199 v8_str("outer.inner")));
13203 bool ApiTestFuzzer::fuzzing_ = false;
13204 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13205 int ApiTestFuzzer::active_tests_;
13206 int ApiTestFuzzer::tests_being_run_;
13207 int ApiTestFuzzer::current_;
13210 // We are in a callback and want to switch to another thread (if we
13211 // are currently running the thread fuzzing test).
13212 void ApiTestFuzzer::Fuzz() {
13213 if (!fuzzing_) return;
13214 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13215 test->ContextSwitch();
13219 // Let the next thread go. Since it is also waiting on the V8 lock it may
13220 // not start immediately.
13221 bool ApiTestFuzzer::NextThread() {
13222 int test_position = GetNextTestNumber();
13223 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13224 if (test_position == current_) {
13226 printf("Stay with %s\n", test_name);
13229 if (kLogThreading) {
13230 printf("Switch from %s to %s\n",
13232 RegisterThreadedTest::nth(test_position)->name());
13234 current_ = test_position;
13235 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13240 void ApiTestFuzzer::Run() {
13241 // When it is our turn...
13244 // ... get the V8 lock and start running the test.
13245 v8::Locker locker(CcTest::isolate());
13248 // This test finished.
13251 // If it was the last then signal that fact.
13252 if (active_tests_ == 0) {
13253 all_tests_done_.Signal();
13255 // Otherwise select a new test and start that.
13261 static unsigned linear_congruential_generator;
13264 void ApiTestFuzzer::SetUp(PartOfTest part) {
13265 linear_congruential_generator = i::FLAG_testing_prng_seed;
13267 int count = RegisterThreadedTest::count();
13268 int start = count * part / (LAST_PART + 1);
13269 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13270 active_tests_ = tests_being_run_ = end - start + 1;
13271 for (int i = 0; i < tests_being_run_; i++) {
13272 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13274 for (int i = 0; i < active_tests_; i++) {
13275 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13280 static void CallTestNumber(int test_number) {
13281 (RegisterThreadedTest::nth(test_number)->callback())();
13285 void ApiTestFuzzer::RunAllTests() {
13286 // Set off the first test.
13289 // Wait till they are all done.
13290 all_tests_done_.Wait();
13294 int ApiTestFuzzer::GetNextTestNumber() {
13297 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13298 linear_congruential_generator *= 1664525u;
13299 linear_congruential_generator += 1013904223u;
13300 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13305 void ApiTestFuzzer::ContextSwitch() {
13306 // If the new thread is the same as the current thread there is nothing to do.
13307 if (NextThread()) {
13308 // Now it can start.
13309 v8::Unlocker unlocker(CcTest::isolate());
13310 // Wait till someone starts us again.
13317 void ApiTestFuzzer::TearDown() {
13319 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13320 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13321 if (fuzzer != NULL) fuzzer->Join();
13326 // Lets not be needlessly self-referential.
13328 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13329 ApiTestFuzzer::RunAllTests();
13330 ApiTestFuzzer::TearDown();
13335 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13336 ApiTestFuzzer::RunAllTests();
13337 ApiTestFuzzer::TearDown();
13342 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13343 ApiTestFuzzer::RunAllTests();
13344 ApiTestFuzzer::TearDown();
13349 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13350 ApiTestFuzzer::RunAllTests();
13351 ApiTestFuzzer::TearDown();
13355 void ApiTestFuzzer::CallTest() {
13356 v8::Isolate::Scope scope(CcTest::isolate());
13358 printf("Start test %d\n", test_number_);
13359 CallTestNumber(test_number_);
13361 printf("End test %d\n", test_number_);
13365 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13366 v8::Isolate* isolate = args.GetIsolate();
13367 CHECK(v8::Locker::IsLocked(isolate));
13368 ApiTestFuzzer::Fuzz();
13369 v8::Unlocker unlocker(isolate);
13370 const char* code = "throw 7;";
13372 v8::Locker nested_locker(isolate);
13373 v8::HandleScope scope(isolate);
13374 v8::Handle<Value> exception;
13375 { v8::TryCatch try_catch;
13376 v8::Handle<Value> value = CompileRun(code);
13377 CHECK(value.IsEmpty());
13378 CHECK(try_catch.HasCaught());
13379 // Make sure to wrap the exception in a new handle because
13380 // the handle returned from the TryCatch is destroyed
13381 // when the TryCatch is destroyed.
13382 exception = Local<Value>::New(isolate, try_catch.Exception());
13384 args.GetIsolate()->ThrowException(exception);
13389 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13390 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13391 ApiTestFuzzer::Fuzz();
13392 v8::Unlocker unlocker(CcTest::isolate());
13393 const char* code = "throw 7;";
13395 v8::Locker nested_locker(CcTest::isolate());
13396 v8::HandleScope scope(args.GetIsolate());
13397 v8::Handle<Value> value = CompileRun(code);
13398 CHECK(value.IsEmpty());
13399 args.GetReturnValue().Set(v8_str("foo"));
13404 // These are locking tests that don't need to be run again
13405 // as part of the locking aggregation tests.
13406 TEST(NestedLockers) {
13407 v8::Isolate* isolate = CcTest::isolate();
13408 v8::Locker locker(isolate);
13409 CHECK(v8::Locker::IsLocked(isolate));
13411 v8::HandleScope scope(env->GetIsolate());
13412 Local<v8::FunctionTemplate> fun_templ =
13413 v8::FunctionTemplate::New(isolate, ThrowInJS);
13414 Local<Function> fun = fun_templ->GetFunction();
13415 env->Global()->Set(v8_str("throw_in_js"), fun);
13416 Local<Script> script = v8_compile("(function () {"
13424 CHECK_EQ(91, script->Run()->Int32Value());
13428 // These are locking tests that don't need to be run again
13429 // as part of the locking aggregation tests.
13430 TEST(NestedLockersNoTryCatch) {
13431 v8::Locker locker(CcTest::isolate());
13433 v8::HandleScope scope(env->GetIsolate());
13434 Local<v8::FunctionTemplate> fun_templ =
13435 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13436 Local<Function> fun = fun_templ->GetFunction();
13437 env->Global()->Set(v8_str("throw_in_js"), fun);
13438 Local<Script> script = v8_compile("(function () {"
13446 CHECK_EQ(91, script->Run()->Int32Value());
13450 THREADED_TEST(RecursiveLocking) {
13451 v8::Locker locker(CcTest::isolate());
13453 v8::Locker locker2(CcTest::isolate());
13454 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13459 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13460 ApiTestFuzzer::Fuzz();
13461 v8::Unlocker unlocker(CcTest::isolate());
13465 THREADED_TEST(LockUnlockLock) {
13467 v8::Locker locker(CcTest::isolate());
13468 v8::HandleScope scope(CcTest::isolate());
13470 Local<v8::FunctionTemplate> fun_templ =
13471 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13472 Local<Function> fun = fun_templ->GetFunction();
13473 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13474 Local<Script> script = v8_compile("(function () {"
13475 " unlock_for_a_moment();"
13478 CHECK_EQ(42, script->Run()->Int32Value());
13481 v8::Locker locker(CcTest::isolate());
13482 v8::HandleScope scope(CcTest::isolate());
13484 Local<v8::FunctionTemplate> fun_templ =
13485 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13486 Local<Function> fun = fun_templ->GetFunction();
13487 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13488 Local<Script> script = v8_compile("(function () {"
13489 " unlock_for_a_moment();"
13492 CHECK_EQ(42, script->Run()->Int32Value());
13497 static int GetGlobalObjectsCount() {
13498 CcTest::heap()->EnsureHeapIsIterable();
13500 i::HeapIterator it(CcTest::heap());
13501 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13502 if (object->IsJSGlobalObject()) count++;
13507 static void CheckSurvivingGlobalObjectsCount(int expected) {
13508 // We need to collect all garbage twice to be sure that everything
13509 // has been collected. This is because inline caches are cleared in
13510 // the first garbage collection but some of the maps have already
13511 // been marked at that point. Therefore some of the maps are not
13512 // collected until the second garbage collection.
13513 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13514 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13515 int count = GetGlobalObjectsCount();
13517 if (count != expected) CcTest::heap()->TracePathToGlobal();
13519 CHECK_EQ(expected, count);
13523 TEST(DontLeakGlobalObjects) {
13524 // Regression test for issues 1139850 and 1174891.
13526 i::FLAG_expose_gc = true;
13527 v8::V8::Initialize();
13529 for (int i = 0; i < 5; i++) {
13530 { v8::HandleScope scope(CcTest::isolate());
13531 LocalContext context;
13533 v8::V8::ContextDisposedNotification();
13534 CheckSurvivingGlobalObjectsCount(0);
13536 { v8::HandleScope scope(CcTest::isolate());
13537 LocalContext context;
13538 v8_compile("Date")->Run();
13540 v8::V8::ContextDisposedNotification();
13541 CheckSurvivingGlobalObjectsCount(0);
13543 { v8::HandleScope scope(CcTest::isolate());
13544 LocalContext context;
13545 v8_compile("/aaa/")->Run();
13547 v8::V8::ContextDisposedNotification();
13548 CheckSurvivingGlobalObjectsCount(0);
13550 { v8::HandleScope scope(CcTest::isolate());
13551 const char* extension_list[] = { "v8/gc" };
13552 v8::ExtensionConfiguration extensions(1, extension_list);
13553 LocalContext context(&extensions);
13554 v8_compile("gc();")->Run();
13556 v8::V8::ContextDisposedNotification();
13557 CheckSurvivingGlobalObjectsCount(0);
13562 TEST(CopyablePersistent) {
13563 LocalContext context;
13564 v8::Isolate* isolate = context->GetIsolate();
13565 i::GlobalHandles* globals =
13566 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13567 int initial_handles = globals->global_handles_count();
13568 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13571 CopyableObject handle1;
13573 v8::HandleScope scope(isolate);
13574 handle1.Reset(isolate, v8::Object::New(isolate));
13576 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13577 CopyableObject handle2;
13579 CHECK(handle1 == handle2);
13580 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13581 CopyableObject handle3(handle2);
13582 CHECK(handle1 == handle3);
13583 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13585 // Verify autodispose
13586 CHECK_EQ(initial_handles, globals->global_handles_count());
13590 static void WeakApiCallback(
13591 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13592 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13593 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13594 data.GetParameter()->Reset();
13595 delete data.GetParameter();
13599 TEST(WeakCallbackApi) {
13600 LocalContext context;
13601 v8::Isolate* isolate = context->GetIsolate();
13602 i::GlobalHandles* globals =
13603 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13604 int initial_handles = globals->global_handles_count();
13606 v8::HandleScope scope(isolate);
13607 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13608 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13609 v8::Persistent<v8::Object>* handle =
13610 new v8::Persistent<v8::Object>(isolate, obj);
13611 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13614 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13615 CollectAllGarbage(i::Heap::kNoGCFlags);
13616 // Verify disposed.
13617 CHECK_EQ(initial_handles, globals->global_handles_count());
13621 v8::Persistent<v8::Object> some_object;
13622 v8::Persistent<v8::Object> bad_handle;
13624 void NewPersistentHandleCallback(
13625 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13626 v8::HandleScope scope(data.GetIsolate());
13627 bad_handle.Reset(data.GetIsolate(), some_object);
13628 data.GetParameter()->Reset();
13632 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13633 LocalContext context;
13634 v8::Isolate* isolate = context->GetIsolate();
13636 v8::Persistent<v8::Object> handle1, handle2;
13638 v8::HandleScope scope(isolate);
13639 some_object.Reset(isolate, v8::Object::New(isolate));
13640 handle1.Reset(isolate, v8::Object::New(isolate));
13641 handle2.Reset(isolate, v8::Object::New(isolate));
13643 // Note: order is implementation dependent alas: currently
13644 // global handle nodes are processed by PostGarbageCollectionProcessing
13645 // in reverse allocation order, so if second allocated handle is deleted,
13646 // weak callback of the first handle would be able to 'reallocate' it.
13647 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13649 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13653 v8::Persistent<v8::Object> to_be_disposed;
13655 void DisposeAndForceGcCallback(
13656 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13657 to_be_disposed.Reset();
13658 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13659 data.GetParameter()->Reset();
13663 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13664 LocalContext context;
13665 v8::Isolate* isolate = context->GetIsolate();
13667 v8::Persistent<v8::Object> handle1, handle2;
13669 v8::HandleScope scope(isolate);
13670 handle1.Reset(isolate, v8::Object::New(isolate));
13671 handle2.Reset(isolate, v8::Object::New(isolate));
13673 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13674 to_be_disposed.Reset(isolate, handle2);
13675 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13678 void DisposingCallback(
13679 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13680 data.GetParameter()->Reset();
13683 void HandleCreatingCallback(
13684 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13685 v8::HandleScope scope(data.GetIsolate());
13686 v8::Persistent<v8::Object>(data.GetIsolate(),
13687 v8::Object::New(data.GetIsolate()));
13688 data.GetParameter()->Reset();
13692 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13693 LocalContext context;
13694 v8::Isolate* isolate = context->GetIsolate();
13696 v8::Persistent<v8::Object> handle1, handle2, handle3;
13698 v8::HandleScope scope(isolate);
13699 handle3.Reset(isolate, v8::Object::New(isolate));
13700 handle2.Reset(isolate, v8::Object::New(isolate));
13701 handle1.Reset(isolate, v8::Object::New(isolate));
13703 handle2.SetWeak(&handle2, DisposingCallback);
13704 handle3.SetWeak(&handle3, HandleCreatingCallback);
13705 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13709 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13710 v8::V8::Initialize();
13713 const char* sources[nof] = {
13714 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13718 for (int i = 0; i < nof; i++) {
13719 const char* source = sources[i];
13720 { v8::HandleScope scope(CcTest::isolate());
13721 LocalContext context;
13722 CompileRun(source);
13724 { v8::HandleScope scope(CcTest::isolate());
13725 LocalContext context;
13726 CompileRun(source);
13732 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13733 v8::EscapableHandleScope inner(env->GetIsolate());
13735 v8::Local<Value> three = v8_num(3);
13736 v8::Local<Value> value = inner.Escape(three);
13742 THREADED_TEST(NestedHandleScopeAndContexts) {
13743 v8::Isolate* isolate = CcTest::isolate();
13744 v8::HandleScope outer(isolate);
13745 v8::Local<Context> env = Context::New(isolate);
13747 v8::Handle<Value> value = NestedScope(env);
13748 v8::Handle<String> str(value->ToString());
13749 CHECK(!str.IsEmpty());
13754 static bool MatchPointers(void* key1, void* key2) {
13755 return key1 == key2;
13759 struct SymbolInfo {
13766 class SetFunctionEntryHookTest {
13768 SetFunctionEntryHookTest() {
13769 CHECK(instance_ == NULL);
13772 ~SetFunctionEntryHookTest() {
13773 CHECK(instance_ == this);
13778 symbol_locations_.clear();
13779 invocations_.clear();
13782 void OnJitEvent(const v8::JitCodeEvent* event);
13783 static void JitEvent(const v8::JitCodeEvent* event) {
13784 CHECK(instance_ != NULL);
13785 instance_->OnJitEvent(event);
13788 void OnEntryHook(uintptr_t function,
13789 uintptr_t return_addr_location);
13790 static void EntryHook(uintptr_t function,
13791 uintptr_t return_addr_location) {
13792 CHECK(instance_ != NULL);
13793 instance_->OnEntryHook(function, return_addr_location);
13796 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13797 CHECK(instance_ != NULL);
13798 args.GetReturnValue().Set(v8_num(42));
13800 void RunLoopInNewEnv(v8::Isolate* isolate);
13802 // Records addr as location of symbol.
13803 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13805 // Finds the symbol containing addr
13806 SymbolInfo* FindSymbolForAddr(i::Address addr);
13807 // Returns the number of invocations where the caller name contains
13808 // \p caller_name and the function name contains \p function_name.
13809 int CountInvocations(const char* caller_name,
13810 const char* function_name);
13812 i::Handle<i::JSFunction> foo_func_;
13813 i::Handle<i::JSFunction> bar_func_;
13815 typedef std::map<size_t, SymbolInfo> SymbolMap;
13816 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13817 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13818 SymbolMap symbols_;
13819 SymbolLocationMap symbol_locations_;
13820 InvocationMap invocations_;
13822 static SetFunctionEntryHookTest* instance_;
13824 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13827 // Returns true if addr is in the range [start, start+len).
13828 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13829 if (start <= addr && start + len > addr)
13835 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13836 SymbolInfo* symbol) {
13837 // Insert the symbol at the new location.
13838 SymbolLocationMap::iterator it =
13839 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13840 // Now erase symbols to the left and right that overlap this one.
13841 while (it != symbol_locations_.begin()) {
13842 SymbolLocationMap::iterator left = it;
13844 if (!Overlaps(left->first, left->second->size, addr))
13846 symbol_locations_.erase(left);
13849 // Now erase symbols to the left and right that overlap this one.
13851 SymbolLocationMap::iterator right = it;
13853 if (right == symbol_locations_.end())
13855 if (!Overlaps(addr, symbol->size, right->first))
13857 symbol_locations_.erase(right);
13862 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13863 switch (event->type) {
13864 case v8::JitCodeEvent::CODE_ADDED: {
13865 CHECK(event->code_start != NULL);
13866 CHECK_NE(0, static_cast<int>(event->code_len));
13867 CHECK(event->name.str != NULL);
13868 size_t symbol_id = symbols_.size();
13870 // Record the new symbol.
13871 SymbolInfo& info = symbols_[symbol_id];
13872 info.id = symbol_id;
13873 info.size = event->code_len;
13874 info.name.assign(event->name.str, event->name.str + event->name.len);
13876 // And record it's location.
13877 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13881 case v8::JitCodeEvent::CODE_MOVED: {
13882 // We would like to never see code move that we haven't seen before,
13883 // but the code creation event does not happen until the line endings
13884 // have been calculated (this is so that we can report the line in the
13885 // script at which the function source is found, see
13886 // Compiler::RecordFunctionCompilation) and the line endings
13887 // calculations can cause a GC, which can move the newly created code
13888 // before its existence can be logged.
13889 SymbolLocationMap::iterator it(
13890 symbol_locations_.find(
13891 reinterpret_cast<i::Address>(event->code_start)));
13892 if (it != symbol_locations_.end()) {
13893 // Found a symbol at this location, move it.
13894 SymbolInfo* info = it->second;
13895 symbol_locations_.erase(it);
13896 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13905 void SetFunctionEntryHookTest::OnEntryHook(
13906 uintptr_t function, uintptr_t return_addr_location) {
13907 // Get the function's code object.
13908 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13909 reinterpret_cast<i::Address>(function));
13910 CHECK(function_code != NULL);
13912 // Then try and look up the caller's code object.
13913 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13915 // Count the invocation.
13916 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13917 SymbolInfo* function_symbol =
13918 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13919 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13921 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13922 // Check that we have a symbol for the "bar" function at the right location.
13923 SymbolLocationMap::iterator it(
13924 symbol_locations_.find(function_code->instruction_start()));
13925 CHECK(it != symbol_locations_.end());
13928 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13929 // Check that we have a symbol for "foo" at the right location.
13930 SymbolLocationMap::iterator it(
13931 symbol_locations_.find(function_code->instruction_start()));
13932 CHECK(it != symbol_locations_.end());
13937 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13938 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13939 // Do we have a direct hit on a symbol?
13940 if (it != symbol_locations_.end()) {
13941 if (it->first == addr)
13945 // If not a direct hit, it'll have to be the previous symbol.
13946 if (it == symbol_locations_.begin())
13950 size_t offs = addr - it->first;
13951 if (offs < it->second->size)
13958 int SetFunctionEntryHookTest::CountInvocations(
13959 const char* caller_name, const char* function_name) {
13960 InvocationMap::iterator it(invocations_.begin());
13961 int invocations = 0;
13962 for (; it != invocations_.end(); ++it) {
13963 SymbolInfo* caller = it->first.first;
13964 SymbolInfo* function = it->first.second;
13966 // Filter out non-matching functions.
13967 if (function_name != NULL) {
13968 if (function->name.find(function_name) == std::string::npos)
13972 // Filter out non-matching callers.
13973 if (caller_name != NULL) {
13974 if (caller == NULL)
13976 if (caller->name.find(caller_name) == std::string::npos)
13980 // It matches add the invocation count to the tally.
13981 invocations += it->second;
13984 return invocations;
13988 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13989 v8::HandleScope outer(isolate);
13990 v8::Local<Context> env = Context::New(isolate);
13993 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13994 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13995 env->Global()->Set(v8_str("obj"), t->NewInstance());
13997 const char* script =
13998 "function bar() {\n"
14000 " for (i = 0; i < 100; ++i)\n"
14004 "function foo(i) { return i * i; }\n"
14005 "// Invoke on the runtime function.\n"
14007 CompileRun(script);
14008 bar_func_ = i::Handle<i::JSFunction>::cast(
14009 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14010 ASSERT(!bar_func_.is_null());
14013 i::Handle<i::JSFunction>::cast(
14014 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14015 ASSERT(!foo_func_.is_null());
14017 v8::Handle<v8::Value> value = CompileRun("bar();");
14018 CHECK(value->IsNumber());
14019 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14021 // Test the optimized codegen path.
14022 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14024 CHECK(value->IsNumber());
14025 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14031 void SetFunctionEntryHookTest::RunTest() {
14032 // Work in a new isolate throughout.
14033 v8::Isolate* isolate = v8::Isolate::New();
14035 // Test setting the entry hook on the new isolate.
14036 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14038 // Replacing the hook, once set should fail.
14039 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14042 v8::Isolate::Scope scope(isolate);
14044 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14046 RunLoopInNewEnv(isolate);
14048 // Check the exepected invocation counts.
14049 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14050 CHECK_EQ(200, CountInvocations("bar", "foo"));
14051 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14053 // Verify that we have an entry hook on some specific stubs.
14054 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14055 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14056 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14058 isolate->Dispose();
14062 // Make sure a second isolate is unaffected by the previous entry hook.
14063 isolate = v8::Isolate::New();
14065 v8::Isolate::Scope scope(isolate);
14067 // Reset the entry count to zero and set the entry hook.
14068 RunLoopInNewEnv(isolate);
14070 // We should record no invocations in this isolate.
14071 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14073 // Since the isolate has been used, we shouldn't be able to set an entry
14075 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14077 isolate->Dispose();
14081 TEST(SetFunctionEntryHook) {
14082 // FunctionEntryHook does not work well with experimental natives.
14083 // Experimental natives are compiled during snapshot deserialization.
14084 // This test breaks because InstallGetter (function from snapshot that
14085 // only gets called from experimental natives) is compiled with entry hooks.
14086 i::FLAG_allow_natives_syntax = true;
14087 i::FLAG_use_inlining = false;
14089 SetFunctionEntryHookTest test;
14094 static i::HashMap* code_map = NULL;
14095 static i::HashMap* jitcode_line_info = NULL;
14096 static int saw_bar = 0;
14097 static int move_events = 0;
14100 static bool FunctionNameIs(const char* expected,
14101 const v8::JitCodeEvent* event) {
14102 // Log lines for functions are of the general form:
14103 // "LazyCompile:<type><function_name>", where the type is one of
14105 static const char kPreamble[] = "LazyCompile:";
14106 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14108 if (event->name.len < sizeof(kPreamble) - 1 ||
14109 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14113 const char* tail = event->name.str + kPreambleLen;
14114 size_t tail_len = event->name.len - kPreambleLen;
14115 size_t expected_len = strlen(expected);
14116 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14121 // Check for tails like 'bar :1'.
14122 if (tail_len > expected_len + 2 &&
14123 tail[expected_len] == ' ' &&
14124 tail[expected_len + 1] == ':' &&
14125 tail[expected_len + 2] &&
14126 !strncmp(tail, expected, expected_len)) {
14130 if (tail_len != expected_len)
14133 return strncmp(tail, expected, expected_len) == 0;
14137 static void event_handler(const v8::JitCodeEvent* event) {
14138 CHECK(event != NULL);
14139 CHECK(code_map != NULL);
14140 CHECK(jitcode_line_info != NULL);
14142 class DummyJitCodeLineInfo {
14145 switch (event->type) {
14146 case v8::JitCodeEvent::CODE_ADDED: {
14147 CHECK(event->code_start != NULL);
14148 CHECK_NE(0, static_cast<int>(event->code_len));
14149 CHECK(event->name.str != NULL);
14150 i::HashMap::Entry* entry =
14151 code_map->Lookup(event->code_start,
14152 i::ComputePointerHash(event->code_start),
14154 entry->value = reinterpret_cast<void*>(event->code_len);
14156 if (FunctionNameIs("bar", event)) {
14162 case v8::JitCodeEvent::CODE_MOVED: {
14163 uint32_t hash = i::ComputePointerHash(event->code_start);
14164 // We would like to never see code move that we haven't seen before,
14165 // but the code creation event does not happen until the line endings
14166 // have been calculated (this is so that we can report the line in the
14167 // script at which the function source is found, see
14168 // Compiler::RecordFunctionCompilation) and the line endings
14169 // calculations can cause a GC, which can move the newly created code
14170 // before its existence can be logged.
14171 i::HashMap::Entry* entry =
14172 code_map->Lookup(event->code_start, hash, false);
14173 if (entry != NULL) {
14176 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14177 code_map->Remove(event->code_start, hash);
14179 entry = code_map->Lookup(event->new_code_start,
14180 i::ComputePointerHash(event->new_code_start),
14182 CHECK(entry != NULL);
14183 entry->value = reinterpret_cast<void*>(event->code_len);
14188 case v8::JitCodeEvent::CODE_REMOVED:
14189 // Object/code removal events are currently not dispatched from the GC.
14193 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14194 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14195 // record it in jitcode_line_info.
14196 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14197 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14198 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14199 temp_event->user_data = line_info;
14200 i::HashMap::Entry* entry =
14201 jitcode_line_info->Lookup(line_info,
14202 i::ComputePointerHash(line_info),
14204 entry->value = reinterpret_cast<void*>(line_info);
14207 // For these two events, we will check whether the event->user_data
14208 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14209 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14210 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14211 CHECK(event->user_data != NULL);
14212 uint32_t hash = i::ComputePointerHash(event->user_data);
14213 i::HashMap::Entry* entry =
14214 jitcode_line_info->Lookup(event->user_data, hash, false);
14215 CHECK(entry != NULL);
14216 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14220 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14221 CHECK(event->user_data != NULL);
14222 uint32_t hash = i::ComputePointerHash(event->user_data);
14223 i::HashMap::Entry* entry =
14224 jitcode_line_info->Lookup(event->user_data, hash, false);
14225 CHECK(entry != NULL);
14230 // Impossible event.
14237 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14238 i::FLAG_stress_compaction = true;
14239 i::FLAG_incremental_marking = false;
14240 if (i::FLAG_never_compact) return;
14241 const char* script =
14244 " for (i = 0; i < 100; ++i)"
14248 "function foo(i) { return i * i; };"
14251 // Run this test in a new isolate to make sure we don't
14252 // have remnants of state from other code.
14253 v8::Isolate* isolate = v8::Isolate::New();
14255 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14256 i::Heap* heap = i_isolate->heap();
14259 v8::HandleScope scope(isolate);
14260 i::HashMap code(MatchPointers);
14263 i::HashMap lineinfo(MatchPointers);
14264 jitcode_line_info = &lineinfo;
14269 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14271 // Generate new code objects sparsely distributed across several
14272 // different fragmented code-space pages.
14273 const int kIterations = 10;
14274 for (int i = 0; i < kIterations; ++i) {
14275 LocalContext env(isolate);
14276 i::AlwaysAllocateScope always_allocate(i_isolate);
14277 SimulateFullSpace(heap->code_space());
14278 CompileRun(script);
14280 // Keep a strong reference to the code object in the handle scope.
14281 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14282 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14283 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14284 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14286 // Clear the compilation cache to get more wastage.
14287 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14290 // Force code movement.
14291 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14293 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14295 CHECK_LE(kIterations, saw_bar);
14296 CHECK_LT(0, move_events);
14299 jitcode_line_info = NULL;
14303 isolate->Dispose();
14305 // Do this in a new isolate.
14306 isolate = v8::Isolate::New();
14309 // Verify that we get callbacks for existing code objects when we
14310 // request enumeration of existing code.
14312 v8::HandleScope scope(isolate);
14313 LocalContext env(isolate);
14314 CompileRun(script);
14316 // Now get code through initial iteration.
14317 i::HashMap code(MatchPointers);
14320 i::HashMap lineinfo(MatchPointers);
14321 jitcode_line_info = &lineinfo;
14323 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14324 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14326 jitcode_line_info = NULL;
14327 // We expect that we got some events. Note that if we could get code removal
14328 // notifications, we could compare two collections, one created by listening
14329 // from the time of creation of an isolate, and the other by subscribing
14330 // with EnumExisting.
14331 CHECK_LT(0, code.occupancy());
14337 isolate->Dispose();
14341 THREADED_TEST(ExternalAllocatedMemory) {
14342 v8::Isolate* isolate = CcTest::isolate();
14343 v8::HandleScope outer(isolate);
14344 v8::Local<Context> env(Context::New(isolate));
14345 CHECK(!env.IsEmpty());
14346 const int64_t kSize = 1024*1024;
14347 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14348 CHECK_EQ(baseline + kSize,
14349 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14351 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14355 // Regression test for issue 54, object templates with internal fields
14356 // but no accessors or interceptors did not get their internal field
14357 // count set on instances.
14358 THREADED_TEST(Regress54) {
14359 LocalContext context;
14360 v8::Isolate* isolate = context->GetIsolate();
14361 v8::HandleScope outer(isolate);
14362 static v8::Persistent<v8::ObjectTemplate> templ;
14363 if (templ.IsEmpty()) {
14364 v8::EscapableHandleScope inner(isolate);
14365 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14366 local->SetInternalFieldCount(1);
14367 templ.Reset(isolate, inner.Escape(local));
14369 v8::Handle<v8::Object> result =
14370 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14371 CHECK_EQ(1, result->InternalFieldCount());
14375 // If part of the threaded tests, this test makes ThreadingTest fail
14377 TEST(CatchStackOverflow) {
14378 LocalContext context;
14379 v8::HandleScope scope(context->GetIsolate());
14380 v8::TryCatch try_catch;
14381 v8::Handle<v8::Value> result = CompileRun(
14387 CHECK(result.IsEmpty());
14391 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14392 const char* resource_name,
14394 v8::HandleScope scope(CcTest::isolate());
14395 v8::TryCatch try_catch;
14396 v8::Handle<v8::Value> result = script->Run();
14397 CHECK(result.IsEmpty());
14398 CHECK(try_catch.HasCaught());
14399 v8::Handle<v8::Message> message = try_catch.Message();
14400 CHECK(!message.IsEmpty());
14401 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14402 CHECK_EQ(91, message->GetStartPosition());
14403 CHECK_EQ(92, message->GetEndPosition());
14404 CHECK_EQ(2, message->GetStartColumn());
14405 CHECK_EQ(3, message->GetEndColumn());
14406 v8::String::Utf8Value line(message->GetSourceLine());
14407 CHECK_EQ(" throw 'nirk';", *line);
14408 v8::String::Utf8Value name(message->GetScriptResourceName());
14409 CHECK_EQ(resource_name, *name);
14413 THREADED_TEST(TryCatchSourceInfo) {
14414 LocalContext context;
14415 v8::HandleScope scope(context->GetIsolate());
14416 v8::Local<v8::String> source = v8_str(
14417 "function Foo() {\n"
14421 "function Bar() {\n"
14425 "function Baz() {\n"
14431 const char* resource_name;
14432 v8::Handle<v8::Script> script;
14433 resource_name = "test.js";
14434 script = CompileWithOrigin(source, resource_name);
14435 CheckTryCatchSourceInfo(script, resource_name, 0);
14437 resource_name = "test1.js";
14438 v8::ScriptOrigin origin1(
14439 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14440 script = v8::Script::Compile(source, &origin1);
14441 CheckTryCatchSourceInfo(script, resource_name, 0);
14443 resource_name = "test2.js";
14444 v8::ScriptOrigin origin2(
14445 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14446 v8::Integer::New(context->GetIsolate(), 7));
14447 script = v8::Script::Compile(source, &origin2);
14448 CheckTryCatchSourceInfo(script, resource_name, 7);
14452 THREADED_TEST(CompilationCache) {
14453 LocalContext context;
14454 v8::HandleScope scope(context->GetIsolate());
14455 v8::Handle<v8::String> source0 =
14456 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14457 v8::Handle<v8::String> source1 =
14458 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14459 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14460 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14461 v8::Handle<v8::Script> script2 =
14462 v8::Script::Compile(source0); // different origin
14463 CHECK_EQ(1234, script0->Run()->Int32Value());
14464 CHECK_EQ(1234, script1->Run()->Int32Value());
14465 CHECK_EQ(1234, script2->Run()->Int32Value());
14469 static void FunctionNameCallback(
14470 const v8::FunctionCallbackInfo<v8::Value>& args) {
14471 ApiTestFuzzer::Fuzz();
14472 args.GetReturnValue().Set(v8_num(42));
14476 THREADED_TEST(CallbackFunctionName) {
14477 LocalContext context;
14478 v8::Isolate* isolate = context->GetIsolate();
14479 v8::HandleScope scope(isolate);
14480 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14481 t->Set(v8_str("asdf"),
14482 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14483 context->Global()->Set(v8_str("obj"), t->NewInstance());
14484 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14485 CHECK(value->IsString());
14486 v8::String::Utf8Value name(value);
14487 CHECK_EQ("asdf", *name);
14491 THREADED_TEST(DateAccess) {
14492 LocalContext context;
14493 v8::HandleScope scope(context->GetIsolate());
14494 v8::Handle<v8::Value> date =
14495 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14496 CHECK(date->IsDate());
14497 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14501 void CheckProperties(v8::Isolate* isolate,
14502 v8::Handle<v8::Value> val,
14504 const char* elmv[]) {
14505 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14506 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14507 CHECK_EQ(elmc, props->Length());
14508 for (int i = 0; i < elmc; i++) {
14509 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14510 CHECK_EQ(elmv[i], *elm);
14515 void CheckOwnProperties(v8::Isolate* isolate,
14516 v8::Handle<v8::Value> val,
14518 const char* elmv[]) {
14519 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14520 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14521 CHECK_EQ(elmc, props->Length());
14522 for (int i = 0; i < elmc; i++) {
14523 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14524 CHECK_EQ(elmv[i], *elm);
14529 THREADED_TEST(PropertyEnumeration) {
14530 LocalContext context;
14531 v8::Isolate* isolate = context->GetIsolate();
14532 v8::HandleScope scope(isolate);
14533 v8::Handle<v8::Value> obj = CompileRun(
14536 "result[1] = {a: 1, b: 2};"
14537 "result[2] = [1, 2, 3];"
14538 "var proto = {x: 1, y: 2, z: 3};"
14539 "var x = { __proto__: proto, w: 0, z: 1 };"
14542 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14543 CHECK_EQ(4, elms->Length());
14545 const char** elmv0 = NULL;
14547 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14548 CheckOwnProperties(
14549 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14551 const char* elmv1[] = {"a", "b"};
14553 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14554 CheckOwnProperties(
14555 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14557 const char* elmv2[] = {"0", "1", "2"};
14559 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14560 CheckOwnProperties(
14561 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14563 const char* elmv3[] = {"w", "z", "x", "y"};
14565 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14567 const char* elmv4[] = {"w", "z"};
14568 CheckOwnProperties(
14569 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14573 THREADED_TEST(PropertyEnumeration2) {
14574 LocalContext context;
14575 v8::Isolate* isolate = context->GetIsolate();
14576 v8::HandleScope scope(isolate);
14577 v8::Handle<v8::Value> obj = CompileRun(
14580 "result[1] = {a: 1, b: 2};"
14581 "result[2] = [1, 2, 3];"
14582 "var proto = {x: 1, y: 2, z: 3};"
14583 "var x = { __proto__: proto, w: 0, z: 1 };"
14586 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14587 CHECK_EQ(4, elms->Length());
14589 const char** elmv0 = NULL;
14590 CheckProperties(isolate,
14591 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14593 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14594 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14595 CHECK_EQ(0, props->Length());
14596 for (uint32_t i = 0; i < props->Length(); i++) {
14597 printf("p[%d]\n", i);
14601 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14603 v8::AccessType type,
14604 Local<Value> data) {
14605 return type != v8::ACCESS_SET;
14609 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14611 v8::AccessType type,
14612 Local<Value> data) {
14613 return type != v8::ACCESS_SET;
14617 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14618 LocalContext context;
14619 v8::Isolate* isolate = context->GetIsolate();
14620 v8::HandleScope scope(isolate);
14621 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14622 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14623 IndexedSetAccessBlocker);
14624 templ->Set(v8_str("x"), v8::True(isolate));
14625 Local<v8::Object> instance = templ->NewInstance();
14626 context->Global()->Set(v8_str("obj"), instance);
14627 Local<Value> value = CompileRun("obj.x");
14628 CHECK(value->BooleanValue());
14632 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14634 v8::AccessType type,
14635 Local<Value> data) {
14640 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14642 v8::AccessType type,
14643 Local<Value> data) {
14649 THREADED_TEST(AccessChecksReenabledCorrectly) {
14650 LocalContext context;
14651 v8::Isolate* isolate = context->GetIsolate();
14652 v8::HandleScope scope(isolate);
14653 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14654 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14655 IndexedGetAccessBlocker);
14656 templ->Set(v8_str("a"), v8_str("a"));
14657 // Add more than 8 (see kMaxFastProperties) properties
14658 // so that the constructor will force copying map.
14659 // Cannot sprintf, gcc complains unsafety.
14661 for (char i = '0'; i <= '9' ; i++) {
14663 for (char j = '0'; j <= '9'; j++) {
14665 for (char k = '0'; k <= '9'; k++) {
14668 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14673 Local<v8::Object> instance_1 = templ->NewInstance();
14674 context->Global()->Set(v8_str("obj_1"), instance_1);
14676 Local<Value> value_1 = CompileRun("obj_1.a");
14677 CHECK(value_1->IsUndefined());
14679 Local<v8::Object> instance_2 = templ->NewInstance();
14680 context->Global()->Set(v8_str("obj_2"), instance_2);
14682 Local<Value> value_2 = CompileRun("obj_2.a");
14683 CHECK(value_2->IsUndefined());
14687 // This tests that access check information remains on the global
14688 // object template when creating contexts.
14689 THREADED_TEST(AccessControlRepeatedContextCreation) {
14690 v8::Isolate* isolate = CcTest::isolate();
14691 v8::HandleScope handle_scope(isolate);
14692 v8::Handle<v8::ObjectTemplate> global_template =
14693 v8::ObjectTemplate::New(isolate);
14694 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14695 IndexedSetAccessBlocker);
14696 i::Handle<i::ObjectTemplateInfo> internal_template =
14697 v8::Utils::OpenHandle(*global_template);
14698 CHECK(!internal_template->constructor()->IsUndefined());
14699 i::Handle<i::FunctionTemplateInfo> constructor(
14700 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14701 CHECK(!constructor->access_check_info()->IsUndefined());
14702 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14703 CHECK(!context0.IsEmpty());
14704 CHECK(!constructor->access_check_info()->IsUndefined());
14708 THREADED_TEST(TurnOnAccessCheck) {
14709 v8::Isolate* isolate = CcTest::isolate();
14710 v8::HandleScope handle_scope(isolate);
14712 // Create an environment with access check to the global object disabled by
14714 v8::Handle<v8::ObjectTemplate> global_template =
14715 v8::ObjectTemplate::New(isolate);
14716 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14717 IndexedGetAccessBlocker,
14718 v8::Handle<v8::Value>(),
14720 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14721 Context::Scope context_scope(context);
14723 // Set up a property and a number of functions.
14724 context->Global()->Set(v8_str("a"), v8_num(1));
14725 CompileRun("function f1() {return a;}"
14726 "function f2() {return a;}"
14727 "function g1() {return h();}"
14728 "function g2() {return h();}"
14729 "function h() {return 1;}");
14730 Local<Function> f1 =
14731 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14732 Local<Function> f2 =
14733 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14734 Local<Function> g1 =
14735 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14736 Local<Function> g2 =
14737 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14738 Local<Function> h =
14739 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14741 // Get the global object.
14742 v8::Handle<v8::Object> global = context->Global();
14744 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14745 // uses the runtime system to retreive property a whereas f2 uses global load
14747 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14748 for (int i = 0; i < 4; i++) {
14749 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14752 // Same for g1 and g2.
14753 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14754 for (int i = 0; i < 4; i++) {
14755 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14758 // Detach the global and turn on access check.
14759 Local<Object> hidden_global = Local<Object>::Cast(
14760 context->Global()->GetPrototype());
14761 context->DetachGlobal();
14762 hidden_global->TurnOnAccessCheck();
14764 // Failing access check to property get results in undefined.
14765 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14766 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14768 // Failing access check to function call results in exception.
14769 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14770 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14772 // No failing access check when just returning a constant.
14773 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14777 static const char* kPropertyA = "a";
14778 static const char* kPropertyH = "h";
14780 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14782 v8::AccessType type,
14783 Local<Value> data) {
14784 if (!name->IsString()) return false;
14785 i::Handle<i::String> name_handle =
14786 v8::Utils::OpenHandle(String::Cast(*name));
14787 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14788 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14792 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14793 v8::Isolate* isolate = CcTest::isolate();
14794 v8::HandleScope handle_scope(isolate);
14796 // Create an environment with access check to the global object disabled by
14797 // default. When the registered access checker will block access to properties
14799 v8::Handle<v8::ObjectTemplate> global_template =
14800 v8::ObjectTemplate::New(isolate);
14801 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14802 IndexedGetAccessBlocker,
14803 v8::Handle<v8::Value>(),
14805 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14806 Context::Scope context_scope(context);
14808 // Set up a property and a number of functions.
14809 context->Global()->Set(v8_str("a"), v8_num(1));
14810 static const char* source = "function f1() {return a;}"
14811 "function f2() {return a;}"
14812 "function g1() {return h();}"
14813 "function g2() {return h();}"
14814 "function h() {return 1;}";
14816 CompileRun(source);
14817 Local<Function> f1;
14818 Local<Function> f2;
14819 Local<Function> g1;
14820 Local<Function> g2;
14822 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14823 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14824 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14825 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14826 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14828 // Get the global object.
14829 v8::Handle<v8::Object> global = context->Global();
14831 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14832 // uses the runtime system to retreive property a whereas f2 uses global load
14834 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14835 for (int i = 0; i < 4; i++) {
14836 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14839 // Same for g1 and g2.
14840 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14841 for (int i = 0; i < 4; i++) {
14842 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14845 // Detach the global and turn on access check now blocking access to property
14846 // a and function h.
14847 Local<Object> hidden_global = Local<Object>::Cast(
14848 context->Global()->GetPrototype());
14849 context->DetachGlobal();
14850 hidden_global->TurnOnAccessCheck();
14852 // Failing access check to property get results in undefined.
14853 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14854 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14856 // Failing access check to function call results in exception.
14857 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14858 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14860 // No failing access check when just returning a constant.
14861 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14863 // Now compile the source again. And get the newly compiled functions, except
14864 // for h for which access is blocked.
14865 CompileRun(source);
14866 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14867 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14868 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14869 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14870 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14872 // Failing access check to property get results in undefined.
14873 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14874 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14876 // Failing access check to function call results in exception.
14877 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14878 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14882 // Tests that ScriptData can be serialized and deserialized.
14883 TEST(PreCompileSerialization) {
14884 v8::V8::Initialize();
14886 v8::Isolate* isolate = env->GetIsolate();
14887 HandleScope handle_scope(isolate);
14889 i::FLAG_min_preparse_length = 0;
14890 const char* script = "function foo(a) { return a+1; }";
14891 v8::ScriptCompiler::Source source(v8_str(script));
14892 v8::ScriptCompiler::Compile(isolate, &source,
14893 v8::ScriptCompiler::kProduceDataToCache);
14895 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14896 char* serialized_data = i::NewArray<char>(cd->length);
14897 i::OS::MemCopy(serialized_data, cd->data, cd->length);
14900 i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
14902 // Verify that the original is the same as the deserialized.
14903 CHECK_EQ(cd->length, deserialized->Length());
14904 CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
14906 delete deserialized;
14907 i::DeleteArray(serialized_data);
14911 // Attempts to deserialize bad data.
14912 TEST(PreCompileDeserializationError) {
14913 v8::V8::Initialize();
14914 const char* data = "DONT CARE";
14915 int invalid_size = 3;
14916 i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
14917 CHECK_EQ(NULL, sd);
14921 TEST(CompileWithInvalidCachedData) {
14922 v8::V8::Initialize();
14923 v8::Isolate* isolate = CcTest::isolate();
14924 LocalContext context;
14925 v8::HandleScope scope(context->GetIsolate());
14926 i::FLAG_min_preparse_length = 0;
14928 const char* script = "function foo(){ return 5;}\n"
14929 "function bar(){ return 6 + 7;} foo();";
14930 v8::ScriptCompiler::Source source(v8_str(script));
14931 v8::ScriptCompiler::Compile(isolate, &source,
14932 v8::ScriptCompiler::kProduceDataToCache);
14933 // source owns its cached data. Create a ScriptData based on it. The user
14934 // never needs to create ScriptDatas any more; we only need it here because we
14935 // want to modify the data before passing it back.
14936 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14937 // ScriptData does not take ownership of the buffers passed to it.
14938 i::ScriptData* sd =
14939 i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14940 CHECK(!sd->HasError());
14941 // ScriptData private implementation details
14942 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14943 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14944 const int kFunctionEntryStartOffset = 0;
14945 const int kFunctionEntryEndOffset = 1;
14946 unsigned* sd_data =
14947 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14949 // Overwrite function bar's end position with 0.
14950 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14951 v8::TryCatch try_catch;
14953 // Make the script slightly different so that we don't hit the compilation
14954 // cache. Don't change the lenghts of tokens.
14955 const char* script2 = "function foo(){ return 6;}\n"
14956 "function bar(){ return 6 + 7;} foo();";
14957 v8::ScriptCompiler::Source source2(
14959 // CachedData doesn't take ownership of the buffers, Source takes
14960 // ownership of CachedData.
14961 new v8::ScriptCompiler::CachedData(
14962 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14963 Local<v8::UnboundScript> compiled_script =
14964 v8::ScriptCompiler::CompileUnbound(isolate, &source2);
14966 CHECK(try_catch.HasCaught());
14968 String::Utf8Value exception_value(try_catch.Message()->Get());
14969 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14976 // Overwrite function bar's start position with 200. The function entry will
14977 // not be found when searching for it by position, and the compilation fails.
14979 // ScriptData does not take ownership of the buffers passed to it.
14980 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14981 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14982 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14984 const char* script3 = "function foo(){ return 7;}\n"
14985 "function bar(){ return 6 + 7;} foo();";
14986 v8::ScriptCompiler::Source source3(
14988 new v8::ScriptCompiler::CachedData(
14989 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14991 v8::ScriptCompiler::CompileUnbound(isolate, &source3);
14992 CHECK(try_catch.HasCaught());
14994 String::Utf8Value exception_value(try_catch.Message()->Get());
14995 CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14998 CHECK(compiled_script.IsEmpty());
15002 // Try passing in cached data which is obviously invalid (wrong length).
15003 sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15004 const char* script4 =
15005 "function foo(){ return 8;}\n"
15006 "function bar(){ return 6 + 7;} foo();";
15007 v8::ScriptCompiler::Source source4(
15009 new v8::ScriptCompiler::CachedData(
15010 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
15012 v8::ScriptCompiler::CompileUnbound(isolate, &source4);
15013 CHECK(try_catch.HasCaught());
15015 String::Utf8Value exception_value(try_catch.Message()->Get());
15016 CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
15019 CHECK(compiled_script.IsEmpty());
15024 // This tests that we do not allow dictionary load/call inline caches
15025 // to use functions that have not yet been compiled. The potential
15026 // problem of loading a function that has not yet been compiled can
15027 // arise because we share code between contexts via the compilation
15029 THREADED_TEST(DictionaryICLoadedFunction) {
15030 v8::HandleScope scope(CcTest::isolate());
15032 for (int i = 0; i < 2; i++) {
15033 LocalContext context;
15034 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15035 context->Global()->Delete(v8_str("tmp"));
15036 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15039 for (int i = 0; i < 2; i++) {
15040 LocalContext context;
15041 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15042 context->Global()->Delete(v8_str("tmp"));
15043 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15048 // Test that cross-context new calls use the context of the callee to
15049 // create the new JavaScript object.
15050 THREADED_TEST(CrossContextNew) {
15051 v8::Isolate* isolate = CcTest::isolate();
15052 v8::HandleScope scope(isolate);
15053 v8::Local<Context> context0 = Context::New(isolate);
15054 v8::Local<Context> context1 = Context::New(isolate);
15056 // Allow cross-domain access.
15057 Local<String> token = v8_str("<security token>");
15058 context0->SetSecurityToken(token);
15059 context1->SetSecurityToken(token);
15061 // Set an 'x' property on the Object prototype and define a
15062 // constructor function in context0.
15064 CompileRun("Object.prototype.x = 42; function C() {};");
15067 // Call the constructor function from context0 and check that the
15068 // result has the 'x' property.
15070 context1->Global()->Set(v8_str("other"), context0->Global());
15071 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15072 CHECK(value->IsInt32());
15073 CHECK_EQ(42, value->Int32Value());
15078 // Verify that we can clone an object
15079 TEST(ObjectClone) {
15081 v8::Isolate* isolate = env->GetIsolate();
15082 v8::HandleScope scope(isolate);
15084 const char* sample =
15086 "rv.alpha = 'hello';" \
15090 // Create an object, verify basics.
15091 Local<Value> val = CompileRun(sample);
15092 CHECK(val->IsObject());
15093 Local<v8::Object> obj = val.As<v8::Object>();
15094 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15096 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15097 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15098 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15101 Local<v8::Object> clone = obj->Clone();
15102 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15103 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15104 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15106 // Set a property on the clone, verify each object.
15107 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15108 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15109 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15113 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15115 explicit AsciiVectorResource(i::Vector<const char> vector)
15117 virtual ~AsciiVectorResource() {}
15118 virtual size_t length() const { return data_.length(); }
15119 virtual const char* data() const { return data_.start(); }
15121 i::Vector<const char> data_;
15125 class UC16VectorResource : public v8::String::ExternalStringResource {
15127 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15129 virtual ~UC16VectorResource() {}
15130 virtual size_t length() const { return data_.length(); }
15131 virtual const i::uc16* data() const { return data_.start(); }
15133 i::Vector<const i::uc16> data_;
15137 static void MorphAString(i::String* string,
15138 AsciiVectorResource* ascii_resource,
15139 UC16VectorResource* uc16_resource) {
15140 CHECK(i::StringShape(string).IsExternal());
15141 if (string->IsOneByteRepresentation()) {
15142 // Check old map is not internalized or long.
15143 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15144 // Morph external string to be TwoByte string.
15145 string->set_map(CcTest::heap()->external_string_map());
15146 i::ExternalTwoByteString* morphed =
15147 i::ExternalTwoByteString::cast(string);
15148 morphed->set_resource(uc16_resource);
15150 // Check old map is not internalized or long.
15151 CHECK(string->map() == CcTest::heap()->external_string_map());
15152 // Morph external string to be ASCII string.
15153 string->set_map(CcTest::heap()->external_ascii_string_map());
15154 i::ExternalAsciiString* morphed =
15155 i::ExternalAsciiString::cast(string);
15156 morphed->set_resource(ascii_resource);
15161 // Test that we can still flatten a string if the components it is built up
15162 // from have been turned into 16 bit strings in the mean time.
15163 THREADED_TEST(MorphCompositeStringTest) {
15164 char utf_buffer[129];
15165 const char* c_string = "Now is the time for all good men"
15166 " to come to the aid of the party";
15167 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15170 i::Factory* factory = CcTest::i_isolate()->factory();
15171 v8::HandleScope scope(env->GetIsolate());
15172 AsciiVectorResource ascii_resource(
15173 i::Vector<const char>(c_string, i::StrLength(c_string)));
15174 UC16VectorResource uc16_resource(
15175 i::Vector<const uint16_t>(two_byte_string,
15176 i::StrLength(c_string)));
15178 Local<String> lhs(v8::Utils::ToLocal(
15179 factory->NewExternalStringFromAscii(&ascii_resource)
15180 .ToHandleChecked()));
15181 Local<String> rhs(v8::Utils::ToLocal(
15182 factory->NewExternalStringFromAscii(&ascii_resource)
15183 .ToHandleChecked()));
15185 env->Global()->Set(v8_str("lhs"), lhs);
15186 env->Global()->Set(v8_str("rhs"), rhs);
15189 "var cons = lhs + rhs;"
15190 "var slice = lhs.substring(1, lhs.length - 1);"
15191 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15193 CHECK(lhs->IsOneByte());
15194 CHECK(rhs->IsOneByte());
15196 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15197 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15199 // This should UTF-8 without flattening, since everything is ASCII.
15200 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15201 CHECK_EQ(128, cons->Utf8Length());
15203 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15204 CHECK_EQ(128, nchars);
15205 CHECK_EQ(0, strcmp(
15207 "Now is the time for all good men to come to the aid of the party"
15208 "Now is the time for all good men to come to the aid of the party"));
15210 // Now do some stuff to make sure the strings are flattened, etc.
15212 "/[^a-z]/.test(cons);"
15213 "/[^a-z]/.test(slice);"
15214 "/[^a-z]/.test(slice_on_cons);");
15215 const char* expected_cons =
15216 "Now is the time for all good men to come to the aid of the party"
15217 "Now is the time for all good men to come to the aid of the party";
15218 const char* expected_slice =
15219 "ow is the time for all good men to come to the aid of the part";
15220 const char* expected_slice_on_cons =
15221 "ow is the time for all good men to come to the aid of the party"
15222 "Now is the time for all good men to come to the aid of the part";
15223 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15224 env->Global()->Get(v8_str("cons")));
15225 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15226 env->Global()->Get(v8_str("slice")));
15227 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15228 env->Global()->Get(v8_str("slice_on_cons")));
15230 i::DeleteArray(two_byte_string);
15234 TEST(CompileExternalTwoByteSource) {
15235 LocalContext context;
15236 v8::HandleScope scope(context->GetIsolate());
15238 // This is a very short list of sources, which currently is to check for a
15239 // regression caused by r2703.
15240 const char* ascii_sources[] = {
15242 "-0.5", // This mainly testes PushBack in the Scanner.
15243 "--0.5", // This mainly testes PushBack in the Scanner.
15247 // Compile the sources as external two byte strings.
15248 for (int i = 0; ascii_sources[i] != NULL; i++) {
15249 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15250 TestResource* uc16_resource = new TestResource(two_byte_string);
15251 v8::Local<v8::String> source =
15252 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15253 v8::Script::Compile(source);
15258 #ifndef V8_INTERPRETED_REGEXP
15260 struct RegExpInterruptionData {
15262 UC16VectorResource* string_resource;
15263 v8::Persistent<v8::String> string;
15264 } regexp_interruption_data;
15267 class RegExpInterruptionThread : public i::Thread {
15269 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15270 : Thread("TimeoutThread"), isolate_(isolate) {}
15272 virtual void Run() {
15273 for (regexp_interruption_data.loop_count = 0;
15274 regexp_interruption_data.loop_count < 7;
15275 regexp_interruption_data.loop_count++) {
15276 i::OS::Sleep(50); // Wait a bit before requesting GC.
15277 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15279 i::OS::Sleep(50); // Wait a bit before terminating.
15280 v8::V8::TerminateExecution(isolate_);
15284 v8::Isolate* isolate_;
15288 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15289 if (regexp_interruption_data.loop_count != 2) return;
15290 v8::HandleScope scope(CcTest::isolate());
15291 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15292 CcTest::isolate(), regexp_interruption_data.string);
15293 string->MakeExternal(regexp_interruption_data.string_resource);
15297 // Test that RegExp execution can be interrupted. Specifically, we test
15298 // * interrupting with GC
15299 // * turn the subject string from one-byte internal to two-byte external string
15300 // * force termination
15301 TEST(RegExpInterruption) {
15302 v8::HandleScope scope(CcTest::isolate());
15305 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15307 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15308 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15309 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15310 v8::Local<v8::String> string = v8_str(ascii_content);
15312 CcTest::global()->Set(v8_str("a"), string);
15313 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15314 regexp_interruption_data.string_resource = new UC16VectorResource(
15315 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15317 v8::TryCatch try_catch;
15318 timeout_thread.Start();
15320 CompileRun("/((a*)*)*b/.exec(a)");
15321 CHECK(try_catch.HasTerminated());
15323 timeout_thread.Join();
15325 regexp_interruption_data.string.Reset();
15326 i::DeleteArray(uc16_content);
15329 #endif // V8_INTERPRETED_REGEXP
15332 // Test that we cannot set a property on the global object if there
15333 // is a read-only property in the prototype chain.
15334 TEST(ReadOnlyPropertyInGlobalProto) {
15335 v8::Isolate* isolate = CcTest::isolate();
15336 v8::HandleScope scope(isolate);
15337 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15338 LocalContext context(0, templ);
15339 v8::Handle<v8::Object> global = context->Global();
15340 v8::Handle<v8::Object> global_proto =
15341 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15342 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15343 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15344 // Check without 'eval' or 'with'.
15345 v8::Handle<v8::Value> res =
15346 CompileRun("function f() { x = 42; return x; }; f()");
15347 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15348 // Check with 'eval'.
15349 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15350 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15351 // Check with 'with'.
15352 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15353 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15356 static int force_set_set_count = 0;
15357 static int force_set_get_count = 0;
15358 bool pass_on_get = false;
15360 static void ForceSetGetter(v8::Local<v8::String> name,
15361 const v8::PropertyCallbackInfo<v8::Value>& info) {
15362 force_set_get_count++;
15366 info.GetReturnValue().Set(3);
15369 static void ForceSetSetter(v8::Local<v8::String> name,
15370 v8::Local<v8::Value> value,
15371 const v8::PropertyCallbackInfo<void>& info) {
15372 force_set_set_count++;
15375 static void ForceSetInterceptSetter(
15376 v8::Local<v8::String> name,
15377 v8::Local<v8::Value> value,
15378 const v8::PropertyCallbackInfo<v8::Value>& info) {
15379 force_set_set_count++;
15380 info.GetReturnValue().SetUndefined();
15385 force_set_get_count = 0;
15386 force_set_set_count = 0;
15387 pass_on_get = false;
15389 v8::Isolate* isolate = CcTest::isolate();
15390 v8::HandleScope scope(isolate);
15391 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15392 v8::Handle<v8::String> access_property =
15393 v8::String::NewFromUtf8(isolate, "a");
15394 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15395 LocalContext context(NULL, templ);
15396 v8::Handle<v8::Object> global = context->Global();
15398 // Ordinary properties
15399 v8::Handle<v8::String> simple_property =
15400 v8::String::NewFromUtf8(isolate, "p");
15401 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15402 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15403 // This should fail because the property is read-only
15404 global->Set(simple_property, v8::Int32::New(isolate, 5));
15405 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15406 // This should succeed even though the property is read-only
15407 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15408 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15411 CHECK_EQ(0, force_set_set_count);
15412 CHECK_EQ(0, force_set_get_count);
15413 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15414 // CHECK_EQ the property shouldn't override it, just call the setter
15415 // which in this case does nothing.
15416 global->Set(access_property, v8::Int32::New(isolate, 7));
15417 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15418 CHECK_EQ(1, force_set_set_count);
15419 CHECK_EQ(2, force_set_get_count);
15420 // Forcing the property to be set should override the accessor without
15422 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15423 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15424 CHECK_EQ(1, force_set_set_count);
15425 CHECK_EQ(2, force_set_get_count);
15429 TEST(ForceSetWithInterceptor) {
15430 force_set_get_count = 0;
15431 force_set_set_count = 0;
15432 pass_on_get = false;
15434 v8::Isolate* isolate = CcTest::isolate();
15435 v8::HandleScope scope(isolate);
15436 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15437 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15438 LocalContext context(NULL, templ);
15439 v8::Handle<v8::Object> global = context->Global();
15441 v8::Handle<v8::String> some_property =
15442 v8::String::NewFromUtf8(isolate, "a");
15443 CHECK_EQ(0, force_set_set_count);
15444 CHECK_EQ(0, force_set_get_count);
15445 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15446 // Setting the property shouldn't override it, just call the setter
15447 // which in this case does nothing.
15448 global->Set(some_property, v8::Int32::New(isolate, 7));
15449 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15450 CHECK_EQ(1, force_set_set_count);
15451 CHECK_EQ(2, force_set_get_count);
15452 // Getting the property when the interceptor returns an empty handle
15453 // should yield undefined, since the property isn't present on the
15454 // object itself yet.
15455 pass_on_get = true;
15456 CHECK(global->Get(some_property)->IsUndefined());
15457 CHECK_EQ(1, force_set_set_count);
15458 CHECK_EQ(3, force_set_get_count);
15459 // Forcing the property to be set should cause the value to be
15460 // set locally without calling the interceptor.
15461 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15462 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15463 CHECK_EQ(1, force_set_set_count);
15464 CHECK_EQ(4, force_set_get_count);
15465 // Reenabling the interceptor should cause it to take precedence over
15467 pass_on_get = false;
15468 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15469 CHECK_EQ(1, force_set_set_count);
15470 CHECK_EQ(5, force_set_get_count);
15471 // The interceptor should also work for other properties
15472 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15474 CHECK_EQ(1, force_set_set_count);
15475 CHECK_EQ(6, force_set_get_count);
15479 THREADED_TEST(ForceDelete) {
15480 v8::Isolate* isolate = CcTest::isolate();
15481 v8::HandleScope scope(isolate);
15482 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15483 LocalContext context(NULL, templ);
15484 v8::Handle<v8::Object> global = context->Global();
15486 // Ordinary properties
15487 v8::Handle<v8::String> simple_property =
15488 v8::String::NewFromUtf8(isolate, "p");
15489 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15490 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15491 // This should fail because the property is dont-delete.
15492 CHECK(!global->Delete(simple_property));
15493 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15494 // This should succeed even though the property is dont-delete.
15495 CHECK(global->ForceDelete(simple_property));
15496 CHECK(global->Get(simple_property)->IsUndefined());
15500 static int force_delete_interceptor_count = 0;
15501 static bool pass_on_delete = false;
15504 static void ForceDeleteDeleter(
15505 v8::Local<v8::String> name,
15506 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15507 force_delete_interceptor_count++;
15508 if (pass_on_delete) return;
15509 info.GetReturnValue().Set(true);
15513 THREADED_TEST(ForceDeleteWithInterceptor) {
15514 force_delete_interceptor_count = 0;
15515 pass_on_delete = false;
15517 v8::Isolate* isolate = CcTest::isolate();
15518 v8::HandleScope scope(isolate);
15519 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15520 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15521 LocalContext context(NULL, templ);
15522 v8::Handle<v8::Object> global = context->Global();
15524 v8::Handle<v8::String> some_property =
15525 v8::String::NewFromUtf8(isolate, "a");
15526 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15528 // Deleting a property should get intercepted and nothing should
15530 CHECK_EQ(0, force_delete_interceptor_count);
15531 CHECK(global->Delete(some_property));
15532 CHECK_EQ(1, force_delete_interceptor_count);
15533 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15534 // Deleting the property when the interceptor returns an empty
15535 // handle should not delete the property since it is DontDelete.
15536 pass_on_delete = true;
15537 CHECK(!global->Delete(some_property));
15538 CHECK_EQ(2, force_delete_interceptor_count);
15539 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15540 // Forcing the property to be deleted should delete the value
15541 // without calling the interceptor.
15542 CHECK(global->ForceDelete(some_property));
15543 CHECK(global->Get(some_property)->IsUndefined());
15544 CHECK_EQ(2, force_delete_interceptor_count);
15548 // Make sure that forcing a delete invalidates any IC stubs, so we
15549 // don't read the hole value.
15550 THREADED_TEST(ForceDeleteIC) {
15551 LocalContext context;
15552 v8::HandleScope scope(context->GetIsolate());
15553 // Create a DontDelete variable on the global object.
15554 CompileRun("this.__proto__ = { foo: 'horse' };"
15555 "var foo = 'fish';"
15556 "function f() { return foo.length; }");
15557 // Initialize the IC for foo in f.
15558 CompileRun("for (var i = 0; i < 4; i++) f();");
15559 // Make sure the value of foo is correct before the deletion.
15560 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15561 // Force the deletion of foo.
15562 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15563 // Make sure the value for foo is read from the prototype, and that
15564 // we don't get in trouble with reading the deleted cell value
15566 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15570 TEST(InlinedFunctionAcrossContexts) {
15571 i::FLAG_allow_natives_syntax = true;
15572 v8::Isolate* isolate = CcTest::isolate();
15573 v8::HandleScope outer_scope(isolate);
15574 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15575 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15579 v8::HandleScope inner_scope(CcTest::isolate());
15580 CompileRun("var G = 42; function foo() { return G; }");
15581 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15583 ctx2->Global()->Set(v8_str("o"), foo);
15584 v8::Local<v8::Value> res = CompileRun(
15585 "function f() { return o(); }"
15586 "for (var i = 0; i < 10; ++i) f();"
15587 "%OptimizeFunctionOnNextCall(f);"
15589 CHECK_EQ(42, res->Int32Value());
15591 v8::Handle<v8::String> G_property =
15592 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15593 CHECK(ctx1->Global()->ForceDelete(G_property));
15600 " return e.toString();"
15603 "ReferenceError: G is not defined");
15610 static v8::Local<Context> calling_context0;
15611 static v8::Local<Context> calling_context1;
15612 static v8::Local<Context> calling_context2;
15615 // Check that the call to the callback is initiated in
15616 // calling_context2, the directly calling context is calling_context1
15617 // and the callback itself is in calling_context0.
15618 static void GetCallingContextCallback(
15619 const v8::FunctionCallbackInfo<v8::Value>& args) {
15620 ApiTestFuzzer::Fuzz();
15621 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15622 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15623 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15624 args.GetReturnValue().Set(42);
15628 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15629 i::Isolate* isolate = CcTest::i_isolate();
15630 CHECK(isolate != NULL);
15631 CHECK(isolate->context() == NULL);
15632 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15633 v8::HandleScope scope(v8_isolate);
15634 // The following should not crash, but return an empty handle.
15635 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15636 CHECK(current.IsEmpty());
15640 THREADED_TEST(GetCallingContext) {
15641 v8::Isolate* isolate = CcTest::isolate();
15642 v8::HandleScope scope(isolate);
15644 Local<Context> calling_context0(Context::New(isolate));
15645 Local<Context> calling_context1(Context::New(isolate));
15646 Local<Context> calling_context2(Context::New(isolate));
15647 ::calling_context0 = calling_context0;
15648 ::calling_context1 = calling_context1;
15649 ::calling_context2 = calling_context2;
15651 // Allow cross-domain access.
15652 Local<String> token = v8_str("<security token>");
15653 calling_context0->SetSecurityToken(token);
15654 calling_context1->SetSecurityToken(token);
15655 calling_context2->SetSecurityToken(token);
15657 // Create an object with a C++ callback in context0.
15658 calling_context0->Enter();
15659 Local<v8::FunctionTemplate> callback_templ =
15660 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15661 calling_context0->Global()->Set(v8_str("callback"),
15662 callback_templ->GetFunction());
15663 calling_context0->Exit();
15665 // Expose context0 in context1 and set up a function that calls the
15666 // callback function.
15667 calling_context1->Enter();
15668 calling_context1->Global()->Set(v8_str("context0"),
15669 calling_context0->Global());
15670 CompileRun("function f() { context0.callback() }");
15671 calling_context1->Exit();
15673 // Expose context1 in context2 and call the callback function in
15674 // context0 indirectly through f in context1.
15675 calling_context2->Enter();
15676 calling_context2->Global()->Set(v8_str("context1"),
15677 calling_context1->Global());
15678 CompileRun("context1.f()");
15679 calling_context2->Exit();
15680 ::calling_context0.Clear();
15681 ::calling_context1.Clear();
15682 ::calling_context2.Clear();
15686 // Check that a variable declaration with no explicit initialization
15687 // value does shadow an existing property in the prototype chain.
15688 THREADED_TEST(InitGlobalVarInProtoChain) {
15689 LocalContext context;
15690 v8::HandleScope scope(context->GetIsolate());
15691 // Introduce a variable in the prototype chain.
15692 CompileRun("__proto__.x = 42");
15693 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15694 CHECK(!result->IsUndefined());
15695 CHECK_EQ(43, result->Int32Value());
15699 // Regression test for issue 398.
15700 // If a function is added to an object, creating a constant function
15701 // field, and the result is cloned, replacing the constant function on the
15702 // original should not affect the clone.
15703 // See http://code.google.com/p/v8/issues/detail?id=398
15704 THREADED_TEST(ReplaceConstantFunction) {
15705 LocalContext context;
15706 v8::Isolate* isolate = context->GetIsolate();
15707 v8::HandleScope scope(isolate);
15708 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15709 v8::Handle<v8::FunctionTemplate> func_templ =
15710 v8::FunctionTemplate::New(isolate);
15711 v8::Handle<v8::String> foo_string =
15712 v8::String::NewFromUtf8(isolate, "foo");
15713 obj->Set(foo_string, func_templ->GetFunction());
15714 v8::Handle<v8::Object> obj_clone = obj->Clone();
15715 obj_clone->Set(foo_string,
15716 v8::String::NewFromUtf8(isolate, "Hello"));
15717 CHECK(!obj->Get(foo_string)->IsUndefined());
15721 static void CheckElementValue(i::Isolate* isolate,
15723 i::Handle<i::Object> obj,
15725 i::Object* element =
15726 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15727 CHECK_EQ(expected, i::Smi::cast(element)->value());
15731 THREADED_TEST(PixelArray) {
15732 LocalContext context;
15733 i::Isolate* isolate = CcTest::i_isolate();
15734 i::Factory* factory = isolate->factory();
15735 v8::HandleScope scope(context->GetIsolate());
15736 const int kElementCount = 260;
15737 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15738 i::Handle<i::ExternalUint8ClampedArray> pixels =
15739 i::Handle<i::ExternalUint8ClampedArray>::cast(
15740 factory->NewExternalArray(kElementCount,
15741 v8::kExternalUint8ClampedArray,
15743 // Force GC to trigger verification.
15744 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15745 for (int i = 0; i < kElementCount; i++) {
15746 pixels->set(i, i % 256);
15748 // Force GC to trigger verification.
15749 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15750 for (int i = 0; i < kElementCount; i++) {
15751 CHECK_EQ(i % 256, pixels->get_scalar(i));
15752 CHECK_EQ(i % 256, pixel_data[i]);
15755 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15756 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15757 // Set the elements to be the pixels.
15758 // jsobj->set_elements(*pixels);
15759 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15760 CheckElementValue(isolate, 1, jsobj, 1);
15761 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15762 context->Global()->Set(v8_str("pixels"), obj);
15763 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15764 CHECK_EQ(1503, result->Int32Value());
15765 result = CompileRun("pixels[1]");
15766 CHECK_EQ(1, result->Int32Value());
15768 result = CompileRun("var sum = 0;"
15769 "for (var i = 0; i < 8; i++) {"
15770 " sum += pixels[i] = pixels[i] = -i;"
15773 CHECK_EQ(-28, result->Int32Value());
15775 result = CompileRun("var sum = 0;"
15776 "for (var i = 0; i < 8; i++) {"
15777 " sum += pixels[i] = pixels[i] = 0;"
15780 CHECK_EQ(0, result->Int32Value());
15782 result = CompileRun("var sum = 0;"
15783 "for (var i = 0; i < 8; i++) {"
15784 " sum += pixels[i] = pixels[i] = 255;"
15787 CHECK_EQ(8 * 255, result->Int32Value());
15789 result = CompileRun("var sum = 0;"
15790 "for (var i = 0; i < 8; i++) {"
15791 " sum += pixels[i] = pixels[i] = 256 + i;"
15794 CHECK_EQ(2076, result->Int32Value());
15796 result = CompileRun("var sum = 0;"
15797 "for (var i = 0; i < 8; i++) {"
15798 " sum += pixels[i] = pixels[i] = i;"
15801 CHECK_EQ(28, result->Int32Value());
15803 result = CompileRun("var sum = 0;"
15804 "for (var i = 0; i < 8; i++) {"
15805 " sum += pixels[i];"
15808 CHECK_EQ(28, result->Int32Value());
15810 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15811 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15812 i::Handle<i::Object> no_failure;
15813 no_failure = i::JSObject::SetElement(
15814 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15815 ASSERT(!no_failure.is_null());
15816 i::USE(no_failure);
15817 CheckElementValue(isolate, 2, jsobj, 1);
15818 *value.location() = i::Smi::FromInt(256);
15819 no_failure = i::JSObject::SetElement(
15820 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15821 ASSERT(!no_failure.is_null());
15822 i::USE(no_failure);
15823 CheckElementValue(isolate, 255, jsobj, 1);
15824 *value.location() = i::Smi::FromInt(-1);
15825 no_failure = i::JSObject::SetElement(
15826 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15827 ASSERT(!no_failure.is_null());
15828 i::USE(no_failure);
15829 CheckElementValue(isolate, 0, jsobj, 1);
15831 result = CompileRun("for (var i = 0; i < 8; i++) {"
15832 " pixels[i] = (i * 65) - 109;"
15834 "pixels[1] + pixels[6];");
15835 CHECK_EQ(255, result->Int32Value());
15836 CheckElementValue(isolate, 0, jsobj, 0);
15837 CheckElementValue(isolate, 0, jsobj, 1);
15838 CheckElementValue(isolate, 21, jsobj, 2);
15839 CheckElementValue(isolate, 86, jsobj, 3);
15840 CheckElementValue(isolate, 151, jsobj, 4);
15841 CheckElementValue(isolate, 216, jsobj, 5);
15842 CheckElementValue(isolate, 255, jsobj, 6);
15843 CheckElementValue(isolate, 255, jsobj, 7);
15844 result = CompileRun("var sum = 0;"
15845 "for (var i = 0; i < 8; i++) {"
15846 " sum += pixels[i];"
15849 CHECK_EQ(984, result->Int32Value());
15851 result = CompileRun("for (var i = 0; i < 8; i++) {"
15852 " pixels[i] = (i * 1.1);"
15854 "pixels[1] + pixels[6];");
15855 CHECK_EQ(8, result->Int32Value());
15856 CheckElementValue(isolate, 0, jsobj, 0);
15857 CheckElementValue(isolate, 1, jsobj, 1);
15858 CheckElementValue(isolate, 2, jsobj, 2);
15859 CheckElementValue(isolate, 3, jsobj, 3);
15860 CheckElementValue(isolate, 4, jsobj, 4);
15861 CheckElementValue(isolate, 6, jsobj, 5);
15862 CheckElementValue(isolate, 7, jsobj, 6);
15863 CheckElementValue(isolate, 8, jsobj, 7);
15865 result = CompileRun("for (var i = 0; i < 8; i++) {"
15866 " pixels[7] = undefined;"
15869 CHECK_EQ(0, result->Int32Value());
15870 CheckElementValue(isolate, 0, jsobj, 7);
15872 result = CompileRun("for (var i = 0; i < 8; i++) {"
15873 " pixels[6] = '2.3';"
15876 CHECK_EQ(2, result->Int32Value());
15877 CheckElementValue(isolate, 2, jsobj, 6);
15879 result = CompileRun("for (var i = 0; i < 8; i++) {"
15880 " pixels[5] = NaN;"
15883 CHECK_EQ(0, result->Int32Value());
15884 CheckElementValue(isolate, 0, jsobj, 5);
15886 result = CompileRun("for (var i = 0; i < 8; i++) {"
15887 " pixels[8] = Infinity;"
15890 CHECK_EQ(255, result->Int32Value());
15891 CheckElementValue(isolate, 255, jsobj, 8);
15893 result = CompileRun("for (var i = 0; i < 8; i++) {"
15894 " pixels[9] = -Infinity;"
15897 CHECK_EQ(0, result->Int32Value());
15898 CheckElementValue(isolate, 0, jsobj, 9);
15900 result = CompileRun("pixels[3] = 33;"
15901 "delete pixels[3];"
15903 CHECK_EQ(33, result->Int32Value());
15905 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15906 "pixels[2] = 12; pixels[3] = 13;"
15907 "pixels.__defineGetter__('2',"
15908 "function() { return 120; });"
15910 CHECK_EQ(12, result->Int32Value());
15912 result = CompileRun("var js_array = new Array(40);"
15913 "js_array[0] = 77;"
15915 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15917 result = CompileRun("pixels[1] = 23;"
15918 "pixels.__proto__ = [];"
15919 "js_array.__proto__ = pixels;"
15920 "js_array.concat(pixels);");
15921 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15922 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15924 result = CompileRun("pixels[1] = 23;");
15925 CHECK_EQ(23, result->Int32Value());
15927 // Test for index greater than 255. Regression test for:
15928 // http://code.google.com/p/chromium/issues/detail?id=26337.
15929 result = CompileRun("pixels[256] = 255;");
15930 CHECK_EQ(255, result->Int32Value());
15931 result = CompileRun("var i = 0;"
15932 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15934 CHECK_EQ(255, result->Int32Value());
15936 // Make sure that pixel array ICs recognize when a non-pixel array
15937 // is passed to it.
15938 result = CompileRun("function pa_load(p) {"
15940 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15943 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15944 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15945 "just_ints = new Object();"
15946 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15947 "for (var i = 0; i < 10; ++i) {"
15948 " result = pa_load(just_ints);"
15951 CHECK_EQ(32640, result->Int32Value());
15953 // Make sure that pixel array ICs recognize out-of-bound accesses.
15954 result = CompileRun("function pa_load(p, start) {"
15956 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15959 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15960 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15961 "for (var i = 0; i < 10; ++i) {"
15962 " result = pa_load(pixels,-10);"
15965 CHECK_EQ(0, result->Int32Value());
15967 // Make sure that generic ICs properly handles a pixel array.
15968 result = CompileRun("function pa_load(p) {"
15970 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15973 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15974 "just_ints = new Object();"
15975 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15976 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15977 "for (var i = 0; i < 10; ++i) {"
15978 " result = pa_load(pixels);"
15981 CHECK_EQ(32640, result->Int32Value());
15983 // Make sure that generic load ICs recognize out-of-bound accesses in
15985 result = CompileRun("function pa_load(p, start) {"
15987 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15990 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15991 "just_ints = new Object();"
15992 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15993 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15994 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15995 "for (var i = 0; i < 10; ++i) {"
15996 " result = pa_load(pixels,-10);"
15999 CHECK_EQ(0, result->Int32Value());
16001 // Make sure that generic ICs properly handles other types than pixel
16002 // arrays (that the inlined fast pixel array test leaves the right information
16003 // in the right registers).
16004 result = CompileRun("function pa_load(p) {"
16006 " for (var j = 0; 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); }"
16013 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16014 "sparse_array = new Object();"
16015 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16016 "sparse_array[1000000] = 3;"
16017 "for (var i = 0; i < 10; ++i) {"
16018 " result = pa_load(sparse_array);"
16021 CHECK_EQ(32640, result->Int32Value());
16023 // Make sure that pixel array store ICs clamp values correctly.
16024 result = CompileRun("function pa_store(p) {"
16025 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16027 "pa_store(pixels);"
16029 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16031 CHECK_EQ(48896, result->Int32Value());
16033 // Make sure that pixel array stores correctly handle accesses outside
16034 // of the pixel array..
16035 result = CompileRun("function pa_store(p,start) {"
16036 " for (var j = 0; j < 256; j++) {"
16037 " p[j+start] = j * 2;"
16040 "pa_store(pixels,0);"
16041 "pa_store(pixels,-128);"
16043 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16045 CHECK_EQ(65280, result->Int32Value());
16047 // Make sure that the generic store stub correctly handle accesses outside
16048 // of the pixel array..
16049 result = CompileRun("function pa_store(p,start) {"
16050 " for (var j = 0; j < 256; j++) {"
16051 " p[j+start] = j * 2;"
16054 "pa_store(pixels,0);"
16055 "just_ints = new Object();"
16056 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16057 "pa_store(just_ints, 0);"
16058 "pa_store(pixels,-128);"
16060 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16062 CHECK_EQ(65280, result->Int32Value());
16064 // Make sure that the generic keyed store stub clamps pixel array values
16066 result = CompileRun("function pa_store(p) {"
16067 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16069 "pa_store(pixels);"
16070 "just_ints = new Object();"
16071 "pa_store(just_ints);"
16072 "pa_store(pixels);"
16074 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16076 CHECK_EQ(48896, result->Int32Value());
16078 // Make sure that pixel array loads are optimized by crankshaft.
16079 result = CompileRun("function pa_load(p) {"
16081 " for (var i=0; i<256; ++i) {"
16086 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16087 "for (var i = 0; i < 5000; ++i) {"
16088 " result = pa_load(pixels);"
16091 CHECK_EQ(32640, result->Int32Value());
16093 // Make sure that pixel array stores are optimized by crankshaft.
16094 result = CompileRun("function pa_init(p) {"
16095 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16097 "function pa_load(p) {"
16099 " for (var i=0; i<256; ++i) {"
16104 "for (var i = 0; i < 5000; ++i) {"
16105 " pa_init(pixels);"
16107 "result = pa_load(pixels);"
16109 CHECK_EQ(32640, result->Int32Value());
16115 THREADED_TEST(PixelArrayInfo) {
16116 LocalContext context;
16117 v8::HandleScope scope(context->GetIsolate());
16118 for (int size = 0; size < 100; size += 10) {
16119 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16120 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16121 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16122 CHECK(obj->HasIndexedPropertiesInPixelData());
16123 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16124 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16130 static void NotHandledIndexedPropertyGetter(
16132 const v8::PropertyCallbackInfo<v8::Value>& info) {
16133 ApiTestFuzzer::Fuzz();
16137 static void NotHandledIndexedPropertySetter(
16139 Local<Value> value,
16140 const v8::PropertyCallbackInfo<v8::Value>& info) {
16141 ApiTestFuzzer::Fuzz();
16145 THREADED_TEST(PixelArrayWithInterceptor) {
16146 LocalContext context;
16147 i::Factory* factory = CcTest::i_isolate()->factory();
16148 v8::Isolate* isolate = context->GetIsolate();
16149 v8::HandleScope scope(isolate);
16150 const int kElementCount = 260;
16151 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16152 i::Handle<i::ExternalUint8ClampedArray> pixels =
16153 i::Handle<i::ExternalUint8ClampedArray>::cast(
16154 factory->NewExternalArray(kElementCount,
16155 v8::kExternalUint8ClampedArray,
16157 for (int i = 0; i < kElementCount; i++) {
16158 pixels->set(i, i % 256);
16160 v8::Handle<v8::ObjectTemplate> templ =
16161 v8::ObjectTemplate::New(context->GetIsolate());
16162 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16163 NotHandledIndexedPropertySetter);
16164 v8::Handle<v8::Object> obj = templ->NewInstance();
16165 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16166 context->Global()->Set(v8_str("pixels"), obj);
16167 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16168 CHECK_EQ(1, result->Int32Value());
16169 result = CompileRun("var sum = 0;"
16170 "for (var i = 0; i < 8; i++) {"
16171 " sum += pixels[i] = pixels[i] = -i;"
16174 CHECK_EQ(-28, result->Int32Value());
16175 result = CompileRun("pixels.hasOwnProperty('1')");
16176 CHECK(result->BooleanValue());
16181 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16182 switch (array_type) {
16183 case v8::kExternalInt8Array:
16184 case v8::kExternalUint8Array:
16185 case v8::kExternalUint8ClampedArray:
16188 case v8::kExternalInt16Array:
16189 case v8::kExternalUint16Array:
16192 case v8::kExternalInt32Array:
16193 case v8::kExternalUint32Array:
16194 case v8::kExternalFloat32Array:
16197 case v8::kExternalFloat64Array:
16209 template <class ExternalArrayClass, class ElementType>
16210 static void ObjectWithExternalArrayTestHelper(
16211 Handle<Context> context,
16212 v8::Handle<Object> obj,
16214 v8::ExternalArrayType array_type,
16215 int64_t low, int64_t high) {
16216 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16217 i::Isolate* isolate = jsobj->GetIsolate();
16218 obj->Set(v8_str("field"),
16219 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16220 context->Global()->Set(v8_str("ext_array"), obj);
16221 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16222 CHECK_EQ(1503, result->Int32Value());
16223 result = CompileRun("ext_array[1]");
16224 CHECK_EQ(1, result->Int32Value());
16226 // Check assigned smis
16227 result = CompileRun("for (var i = 0; i < 8; i++) {"
16228 " ext_array[i] = i;"
16231 "for (var i = 0; i < 8; i++) {"
16232 " sum += ext_array[i];"
16236 CHECK_EQ(28, result->Int32Value());
16237 // Check pass through of assigned smis
16238 result = CompileRun("var sum = 0;"
16239 "for (var i = 0; i < 8; i++) {"
16240 " sum += ext_array[i] = ext_array[i] = -i;"
16243 CHECK_EQ(-28, result->Int32Value());
16246 // Check assigned smis in reverse order
16247 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16248 " ext_array[i] = i;"
16251 "for (var i = 0; i < 8; i++) {"
16252 " sum += ext_array[i];"
16255 CHECK_EQ(28, result->Int32Value());
16257 // Check pass through of assigned HeapNumbers
16258 result = CompileRun("var sum = 0;"
16259 "for (var i = 0; i < 16; i+=2) {"
16260 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16263 CHECK_EQ(-28, result->Int32Value());
16265 // Check assigned HeapNumbers
16266 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16267 " ext_array[i] = (i * 0.5);"
16270 "for (var i = 0; i < 16; i+=2) {"
16271 " sum += ext_array[i];"
16274 CHECK_EQ(28, result->Int32Value());
16276 // Check assigned HeapNumbers in reverse order
16277 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16278 " ext_array[i] = (i * 0.5);"
16281 "for (var i = 0; i < 16; i+=2) {"
16282 " sum += ext_array[i];"
16285 CHECK_EQ(28, result->Int32Value());
16287 i::ScopedVector<char> test_buf(1024);
16289 // Check legal boundary conditions.
16290 // The repeated loads and stores ensure the ICs are exercised.
16291 const char* boundary_program =
16293 "for (var i = 0; i < 16; i++) {"
16294 " ext_array[i] = %lld;"
16296 " res = ext_array[i];"
16300 i::OS::SNPrintF(test_buf,
16303 result = CompileRun(test_buf.start());
16304 CHECK_EQ(low, result->IntegerValue());
16306 i::OS::SNPrintF(test_buf,
16309 result = CompileRun(test_buf.start());
16310 CHECK_EQ(high, result->IntegerValue());
16312 // Check misprediction of type in IC.
16313 result = CompileRun("var tmp_array = ext_array;"
16315 "for (var i = 0; i < 8; i++) {"
16316 " tmp_array[i] = i;"
16317 " sum += tmp_array[i];"
16323 // Force GC to trigger verification.
16324 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16325 CHECK_EQ(28, result->Int32Value());
16327 // Make sure out-of-range loads do not throw.
16328 i::OS::SNPrintF(test_buf,
16329 "var caught_exception = false;"
16333 " caught_exception = true;"
16335 "caught_exception;",
16337 result = CompileRun(test_buf.start());
16338 CHECK_EQ(false, result->BooleanValue());
16340 // Make sure out-of-range stores do not throw.
16341 i::OS::SNPrintF(test_buf,
16342 "var caught_exception = false;"
16344 " ext_array[%d] = 1;"
16346 " caught_exception = true;"
16348 "caught_exception;",
16350 result = CompileRun(test_buf.start());
16351 CHECK_EQ(false, result->BooleanValue());
16353 // Check other boundary conditions, values and operations.
16354 result = CompileRun("for (var i = 0; i < 8; i++) {"
16355 " ext_array[7] = undefined;"
16358 CHECK_EQ(0, result->Int32Value());
16359 if (array_type == v8::kExternalFloat64Array ||
16360 array_type == v8::kExternalFloat32Array) {
16361 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16363 i::Object::GetElement(
16364 isolate, jsobj, 7).ToHandleChecked()->Number()));
16366 CheckElementValue(isolate, 0, jsobj, 7);
16369 result = CompileRun("for (var i = 0; i < 8; i++) {"
16370 " ext_array[6] = '2.3';"
16373 CHECK_EQ(2, result->Int32Value());
16376 i::Object::GetElement(
16377 isolate, jsobj, 6).ToHandleChecked()->Number()));
16379 if (array_type != v8::kExternalFloat32Array &&
16380 array_type != v8::kExternalFloat64Array) {
16381 // Though the specification doesn't state it, be explicit about
16382 // converting NaNs and +/-Infinity to zero.
16383 result = CompileRun("for (var i = 0; i < 8; i++) {"
16384 " ext_array[i] = 5;"
16386 "for (var i = 0; i < 8; i++) {"
16387 " ext_array[i] = NaN;"
16390 CHECK_EQ(0, result->Int32Value());
16391 CheckElementValue(isolate, 0, jsobj, 5);
16393 result = CompileRun("for (var i = 0; i < 8; i++) {"
16394 " ext_array[i] = 5;"
16396 "for (var i = 0; i < 8; i++) {"
16397 " ext_array[i] = Infinity;"
16400 int expected_value =
16401 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16402 CHECK_EQ(expected_value, result->Int32Value());
16403 CheckElementValue(isolate, expected_value, jsobj, 5);
16405 result = CompileRun("for (var i = 0; i < 8; i++) {"
16406 " ext_array[i] = 5;"
16408 "for (var i = 0; i < 8; i++) {"
16409 " ext_array[i] = -Infinity;"
16412 CHECK_EQ(0, result->Int32Value());
16413 CheckElementValue(isolate, 0, jsobj, 5);
16415 // Check truncation behavior of integral arrays.
16416 const char* unsigned_data =
16417 "var source_data = [0.6, 10.6];"
16418 "var expected_results = [0, 10];";
16419 const char* signed_data =
16420 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16421 "var expected_results = [0, 10, 0, -10];";
16422 const char* pixel_data =
16423 "var source_data = [0.6, 10.6];"
16424 "var expected_results = [1, 11];";
16426 (array_type == v8::kExternalUint8Array ||
16427 array_type == v8::kExternalUint16Array ||
16428 array_type == v8::kExternalUint32Array);
16429 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16431 i::OS::SNPrintF(test_buf,
16433 "var all_passed = true;"
16434 "for (var i = 0; i < source_data.length; i++) {"
16435 " for (var j = 0; j < 8; j++) {"
16436 " ext_array[j] = source_data[i];"
16438 " all_passed = all_passed &&"
16439 " (ext_array[5] == expected_results[i]);"
16444 (is_pixel_data ? pixel_data : signed_data)));
16445 result = CompileRun(test_buf.start());
16446 CHECK_EQ(true, result->BooleanValue());
16449 i::Handle<ExternalArrayClass> array(
16450 ExternalArrayClass::cast(jsobj->elements()));
16451 for (int i = 0; i < element_count; i++) {
16452 array->set(i, static_cast<ElementType>(i));
16455 // Test complex assignments
16456 result = CompileRun("function ee_op_test_complex_func(sum) {"
16457 " for (var i = 0; i < 40; ++i) {"
16458 " sum += (ext_array[i] += 1);"
16459 " sum += (ext_array[i] -= 1);"
16464 "for (var i=0;i<10000;++i) {"
16465 " sum=ee_op_test_complex_func(sum);"
16468 CHECK_EQ(16000000, result->Int32Value());
16470 // Test count operations
16471 result = CompileRun("function ee_op_test_count_func(sum) {"
16472 " for (var i = 0; i < 40; ++i) {"
16473 " sum += (++ext_array[i]);"
16474 " sum += (--ext_array[i]);"
16479 "for (var i=0;i<10000;++i) {"
16480 " sum=ee_op_test_count_func(sum);"
16483 CHECK_EQ(16000000, result->Int32Value());
16485 result = CompileRun("ext_array[3] = 33;"
16486 "delete ext_array[3];"
16488 CHECK_EQ(33, result->Int32Value());
16490 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16491 "ext_array[2] = 12; ext_array[3] = 13;"
16492 "ext_array.__defineGetter__('2',"
16493 "function() { return 120; });"
16495 CHECK_EQ(12, result->Int32Value());
16497 result = CompileRun("var js_array = new Array(40);"
16498 "js_array[0] = 77;"
16500 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16502 result = CompileRun("ext_array[1] = 23;"
16503 "ext_array.__proto__ = [];"
16504 "js_array.__proto__ = ext_array;"
16505 "js_array.concat(ext_array);");
16506 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16507 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16509 result = CompileRun("ext_array[1] = 23;");
16510 CHECK_EQ(23, result->Int32Value());
16514 template <class FixedTypedArrayClass,
16515 i::ElementsKind elements_kind,
16517 static void FixedTypedArrayTestHelper(
16518 v8::ExternalArrayType array_type,
16520 ElementType high) {
16521 i::FLAG_allow_natives_syntax = true;
16522 LocalContext context;
16523 i::Isolate* isolate = CcTest::i_isolate();
16524 i::Factory* factory = isolate->factory();
16525 v8::HandleScope scope(context->GetIsolate());
16526 const int kElementCount = 260;
16527 i::Handle<FixedTypedArrayClass> fixed_array =
16528 i::Handle<FixedTypedArrayClass>::cast(
16529 factory->NewFixedTypedArray(kElementCount, array_type));
16530 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16531 fixed_array->map()->instance_type());
16532 CHECK_EQ(kElementCount, fixed_array->length());
16533 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16534 for (int i = 0; i < kElementCount; i++) {
16535 fixed_array->set(i, static_cast<ElementType>(i));
16537 // Force GC to trigger verification.
16538 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16539 for (int i = 0; i < kElementCount; i++) {
16540 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16541 static_cast<int64_t>(fixed_array->get_scalar(i)));
16543 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16544 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16545 i::Handle<i::Map> fixed_array_map =
16546 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16547 jsobj->set_map(*fixed_array_map);
16548 jsobj->set_elements(*fixed_array);
16550 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16551 context.local(), obj, kElementCount, array_type,
16552 static_cast<int64_t>(low),
16553 static_cast<int64_t>(high));
16557 THREADED_TEST(FixedUint8Array) {
16558 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16559 v8::kExternalUint8Array,
16564 THREADED_TEST(FixedUint8ClampedArray) {
16565 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16566 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16567 v8::kExternalUint8ClampedArray,
16572 THREADED_TEST(FixedInt8Array) {
16573 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16574 v8::kExternalInt8Array,
16579 THREADED_TEST(FixedUint16Array) {
16580 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16581 v8::kExternalUint16Array,
16586 THREADED_TEST(FixedInt16Array) {
16587 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16588 v8::kExternalInt16Array,
16593 THREADED_TEST(FixedUint32Array) {
16594 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16595 v8::kExternalUint32Array,
16600 THREADED_TEST(FixedInt32Array) {
16601 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16602 v8::kExternalInt32Array,
16607 THREADED_TEST(FixedFloat32Array) {
16608 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16609 v8::kExternalFloat32Array,
16614 THREADED_TEST(FixedFloat64Array) {
16615 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16616 v8::kExternalFloat64Array,
16621 template <class ExternalArrayClass, class ElementType>
16622 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16625 LocalContext context;
16626 i::Isolate* isolate = CcTest::i_isolate();
16627 i::Factory* factory = isolate->factory();
16628 v8::HandleScope scope(context->GetIsolate());
16629 const int kElementCount = 40;
16630 int element_size = ExternalArrayElementSize(array_type);
16631 ElementType* array_data =
16632 static_cast<ElementType*>(malloc(kElementCount * element_size));
16633 i::Handle<ExternalArrayClass> array =
16634 i::Handle<ExternalArrayClass>::cast(
16635 factory->NewExternalArray(kElementCount, array_type, array_data));
16636 // Force GC to trigger verification.
16637 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16638 for (int i = 0; i < kElementCount; i++) {
16639 array->set(i, static_cast<ElementType>(i));
16641 // Force GC to trigger verification.
16642 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16643 for (int i = 0; i < kElementCount; i++) {
16644 CHECK_EQ(static_cast<int64_t>(i),
16645 static_cast<int64_t>(array->get_scalar(i)));
16646 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16649 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16650 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16651 // Set the elements to be the external array.
16652 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16657 i::Object::GetElement(
16658 isolate, jsobj, 1).ToHandleChecked()->Number()));
16660 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16661 context.local(), obj, kElementCount, array_type, low, high);
16663 v8::Handle<v8::Value> result;
16665 // Test more complex manipulations which cause eax to contain values
16666 // that won't be completely overwritten by loads from the arrays.
16667 // This catches bugs in the instructions used for the KeyedLoadIC
16668 // for byte and word types.
16670 const int kXSize = 300;
16671 const int kYSize = 300;
16672 const int kLargeElementCount = kXSize * kYSize * 4;
16673 ElementType* large_array_data =
16674 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16675 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16676 // Set the elements to be the external array.
16677 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16679 kLargeElementCount);
16680 context->Global()->Set(v8_str("large_array"), large_obj);
16681 // Initialize contents of a few rows.
16682 for (int x = 0; x < 300; x++) {
16684 int offset = row * 300 * 4;
16685 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16686 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16687 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16688 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16690 offset = row * 300 * 4;
16691 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16692 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16693 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16694 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16696 offset = row * 300 * 4;
16697 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16698 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16699 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16700 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16702 // The goal of the code below is to make "offset" large enough
16703 // that the computation of the index (which goes into eax) has
16704 // high bits set which will not be overwritten by a byte or short
16706 result = CompileRun("var failed = false;"
16708 "for (var i = 0; i < 300; i++) {"
16709 " if (large_array[4 * i] != 127 ||"
16710 " large_array[4 * i + 1] != 0 ||"
16711 " large_array[4 * i + 2] != 0 ||"
16712 " large_array[4 * i + 3] != 127) {"
16716 "offset = 150 * 300 * 4;"
16717 "for (var i = 0; i < 300; i++) {"
16718 " if (large_array[offset + 4 * i] != 127 ||"
16719 " large_array[offset + 4 * i + 1] != 0 ||"
16720 " large_array[offset + 4 * i + 2] != 0 ||"
16721 " large_array[offset + 4 * i + 3] != 127) {"
16725 "offset = 298 * 300 * 4;"
16726 "for (var i = 0; i < 300; i++) {"
16727 " if (large_array[offset + 4 * i] != 127 ||"
16728 " large_array[offset + 4 * i + 1] != 0 ||"
16729 " large_array[offset + 4 * i + 2] != 0 ||"
16730 " large_array[offset + 4 * i + 3] != 127) {"
16735 CHECK_EQ(true, result->BooleanValue());
16736 free(large_array_data);
16739 // The "" property descriptor is overloaded to store information about
16740 // the external array. Ensure that setting and accessing the "" property
16741 // works (it should overwrite the information cached about the external
16742 // array in the DescriptorArray) in various situations.
16743 result = CompileRun("ext_array[''] = 23; ext_array['']");
16744 CHECK_EQ(23, result->Int32Value());
16746 // Property "" set after the external array is associated with the object.
16748 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16749 obj2->Set(v8_str("ee_test_field"),
16750 v8::Int32::New(context->GetIsolate(), 256));
16751 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16752 // Set the elements to be the external array.
16753 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16756 context->Global()->Set(v8_str("ext_array"), obj2);
16757 result = CompileRun("ext_array['']");
16758 CHECK_EQ(1503, result->Int32Value());
16761 // Property "" set after the external array is associated with the object.
16763 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16764 obj2->Set(v8_str("ee_test_field_2"),
16765 v8::Int32::New(context->GetIsolate(), 256));
16766 // Set the elements to be the external array.
16767 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16770 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16771 context->Global()->Set(v8_str("ext_array"), obj2);
16772 result = CompileRun("ext_array['']");
16773 CHECK_EQ(1503, result->Int32Value());
16776 // Should reuse the map from previous test.
16778 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16779 obj2->Set(v8_str("ee_test_field_2"),
16780 v8::Int32::New(context->GetIsolate(), 256));
16781 // Set the elements to be the external array. Should re-use the map
16782 // from previous test.
16783 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16786 context->Global()->Set(v8_str("ext_array"), obj2);
16787 result = CompileRun("ext_array['']");
16790 // Property "" is a constant function that shouldn't not be interfered with
16791 // when an external array is set.
16793 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16795 obj2->Set(v8_str("ee_test_field3"),
16796 v8::Int32::New(context->GetIsolate(), 256));
16798 // Add a constant function to an object.
16799 context->Global()->Set(v8_str("ext_array"), obj2);
16800 result = CompileRun("ext_array[''] = function() {return 1503;};"
16801 "ext_array['']();");
16803 // Add an external array transition to the same map that
16804 // has the constant transition.
16805 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16806 obj3->Set(v8_str("ee_test_field3"),
16807 v8::Int32::New(context->GetIsolate(), 256));
16808 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16811 context->Global()->Set(v8_str("ext_array"), obj3);
16814 // If a external array transition is in the map, it should get clobbered
16815 // by a constant function.
16817 // Add an external array transition.
16818 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16819 obj3->Set(v8_str("ee_test_field4"),
16820 v8::Int32::New(context->GetIsolate(), 256));
16821 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16825 // Add a constant function to the same map that just got an external array
16827 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16828 obj2->Set(v8_str("ee_test_field4"),
16829 v8::Int32::New(context->GetIsolate(), 256));
16830 context->Global()->Set(v8_str("ext_array"), obj2);
16831 result = CompileRun("ext_array[''] = function() {return 1503;};"
16832 "ext_array['']();");
16839 THREADED_TEST(ExternalInt8Array) {
16840 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16841 v8::kExternalInt8Array,
16847 THREADED_TEST(ExternalUint8Array) {
16848 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16849 v8::kExternalUint8Array,
16855 THREADED_TEST(ExternalUint8ClampedArray) {
16856 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16857 v8::kExternalUint8ClampedArray,
16863 THREADED_TEST(ExternalInt16Array) {
16864 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16865 v8::kExternalInt16Array,
16871 THREADED_TEST(ExternalUint16Array) {
16872 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16873 v8::kExternalUint16Array,
16879 THREADED_TEST(ExternalInt32Array) {
16880 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16881 v8::kExternalInt32Array,
16882 INT_MIN, // -2147483648
16883 INT_MAX); // 2147483647
16887 THREADED_TEST(ExternalUint32Array) {
16888 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16889 v8::kExternalUint32Array,
16891 UINT_MAX); // 4294967295
16895 THREADED_TEST(ExternalFloat32Array) {
16896 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16897 v8::kExternalFloat32Array,
16903 THREADED_TEST(ExternalFloat64Array) {
16904 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16905 v8::kExternalFloat64Array,
16911 THREADED_TEST(ExternalArrays) {
16912 TestExternalInt8Array();
16913 TestExternalUint8Array();
16914 TestExternalInt16Array();
16915 TestExternalUint16Array();
16916 TestExternalInt32Array();
16917 TestExternalUint32Array();
16918 TestExternalFloat32Array();
16922 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16923 LocalContext context;
16924 v8::HandleScope scope(context->GetIsolate());
16925 for (int size = 0; size < 100; size += 10) {
16926 int element_size = ExternalArrayElementSize(array_type);
16927 void* external_data = malloc(size * element_size);
16928 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16929 obj->SetIndexedPropertiesToExternalArrayData(
16930 external_data, array_type, size);
16931 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16932 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16933 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16934 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16935 free(external_data);
16940 THREADED_TEST(ExternalArrayInfo) {
16941 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16942 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16943 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16944 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16945 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16946 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16947 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16948 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16949 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16953 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16954 v8::ExternalArrayType array_type,
16956 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16957 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16958 last_location = last_message = NULL;
16959 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16960 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16961 CHECK_NE(NULL, last_location);
16962 CHECK_NE(NULL, last_message);
16966 TEST(ExternalArrayLimits) {
16967 LocalContext context;
16968 v8::Isolate* isolate = context->GetIsolate();
16969 v8::HandleScope scope(isolate);
16970 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16971 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16972 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16973 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16974 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16975 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16976 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16977 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16978 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16979 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16980 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16981 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16982 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16983 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16984 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16985 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16986 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16987 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16991 template <typename ElementType, typename TypedArray,
16992 class ExternalArrayClass>
16993 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16994 int64_t low, int64_t high) {
16995 const int kElementCount = 50;
16997 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17000 v8::Isolate* isolate = env->GetIsolate();
17001 v8::HandleScope handle_scope(isolate);
17003 Local<v8::ArrayBuffer> ab =
17004 v8::ArrayBuffer::New(isolate, backing_store.start(),
17005 (kElementCount + 2) * sizeof(ElementType));
17006 Local<TypedArray> ta =
17007 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17008 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17009 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17010 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17011 CHECK_EQ(kElementCount*sizeof(ElementType),
17012 static_cast<int>(ta->ByteLength()));
17013 CHECK_EQ(ab, ta->Buffer());
17015 ElementType* data = backing_store.start() + 2;
17016 for (int i = 0; i < kElementCount; i++) {
17017 data[i] = static_cast<ElementType>(i);
17020 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17021 env.local(), ta, kElementCount, array_type, low, high);
17025 THREADED_TEST(Uint8Array) {
17026 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17027 v8::kExternalUint8Array, 0, 0xFF);
17031 THREADED_TEST(Int8Array) {
17032 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17033 v8::kExternalInt8Array, -0x80, 0x7F);
17037 THREADED_TEST(Uint16Array) {
17038 TypedArrayTestHelper<uint16_t,
17040 i::ExternalUint16Array>(
17041 v8::kExternalUint16Array, 0, 0xFFFF);
17045 THREADED_TEST(Int16Array) {
17046 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17047 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17051 THREADED_TEST(Uint32Array) {
17052 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17053 v8::kExternalUint32Array, 0, UINT_MAX);
17057 THREADED_TEST(Int32Array) {
17058 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17059 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17063 THREADED_TEST(Float32Array) {
17064 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17065 v8::kExternalFloat32Array, -500, 500);
17069 THREADED_TEST(Float64Array) {
17070 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17071 v8::kExternalFloat64Array, -500, 500);
17075 THREADED_TEST(Uint8ClampedArray) {
17076 TypedArrayTestHelper<uint8_t,
17077 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17078 v8::kExternalUint8ClampedArray, 0, 0xFF);
17082 THREADED_TEST(DataView) {
17083 const int kSize = 50;
17085 i::ScopedVector<uint8_t> backing_store(kSize+2);
17088 v8::Isolate* isolate = env->GetIsolate();
17089 v8::HandleScope handle_scope(isolate);
17091 Local<v8::ArrayBuffer> ab =
17092 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17093 Local<v8::DataView> dv =
17094 v8::DataView::New(ab, 2, kSize);
17095 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17096 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17097 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17098 CHECK_EQ(ab, dv->Buffer());
17102 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17103 THREADED_TEST(Is##View) { \
17104 LocalContext env; \
17105 v8::Isolate* isolate = env->GetIsolate(); \
17106 v8::HandleScope handle_scope(isolate); \
17108 Handle<Value> result = CompileRun( \
17109 "var ab = new ArrayBuffer(128);" \
17110 "new " #View "(ab)"); \
17111 CHECK(result->IsArrayBufferView()); \
17112 CHECK(result->Is##View()); \
17113 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17116 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17117 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17118 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17119 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17120 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17121 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17122 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17123 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17124 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17125 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17127 #undef IS_ARRAY_BUFFER_VIEW_TEST
17131 THREADED_TEST(ScriptContextDependence) {
17133 v8::HandleScope scope(c1->GetIsolate());
17134 const char *source = "foo";
17135 v8::Handle<v8::Script> dep = v8_compile(source);
17136 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17137 c1->GetIsolate(), source));
17138 v8::Handle<v8::UnboundScript> indep =
17139 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17140 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17141 v8::Integer::New(c1->GetIsolate(), 100));
17142 CHECK_EQ(dep->Run()->Int32Value(), 100);
17143 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17145 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17146 v8::Integer::New(c2->GetIsolate(), 101));
17147 CHECK_EQ(dep->Run()->Int32Value(), 100);
17148 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17152 THREADED_TEST(StackTrace) {
17153 LocalContext context;
17154 v8::HandleScope scope(context->GetIsolate());
17155 v8::TryCatch try_catch;
17156 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17157 v8::Handle<v8::String> src =
17158 v8::String::NewFromUtf8(context->GetIsolate(), source);
17159 v8::Handle<v8::String> origin =
17160 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17161 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17162 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17163 ->BindToCurrentContext()
17165 CHECK(try_catch.HasCaught());
17166 v8::String::Utf8Value stack(try_catch.StackTrace());
17167 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17171 // Checks that a StackFrame has certain expected values.
17172 void checkStackFrame(const char* expected_script_name,
17173 const char* expected_func_name, int expected_line_number,
17174 int expected_column, bool is_eval, bool is_constructor,
17175 v8::Handle<v8::StackFrame> frame) {
17176 v8::HandleScope scope(CcTest::isolate());
17177 v8::String::Utf8Value func_name(frame->GetFunctionName());
17178 v8::String::Utf8Value script_name(frame->GetScriptName());
17179 if (*script_name == NULL) {
17180 // The situation where there is no associated script, like for evals.
17181 CHECK(expected_script_name == NULL);
17183 CHECK(strstr(*script_name, expected_script_name) != NULL);
17185 CHECK(strstr(*func_name, expected_func_name) != NULL);
17186 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17187 CHECK_EQ(expected_column, frame->GetColumn());
17188 CHECK_EQ(is_eval, frame->IsEval());
17189 CHECK_EQ(is_constructor, frame->IsConstructor());
17193 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17194 v8::HandleScope scope(args.GetIsolate());
17195 const char* origin = "capture-stack-trace-test";
17196 const int kOverviewTest = 1;
17197 const int kDetailedTest = 2;
17199 ASSERT(args.Length() == 1);
17201 int testGroup = args[0]->Int32Value();
17202 if (testGroup == kOverviewTest) {
17203 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17204 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17205 CHECK_EQ(4, stackTrace->GetFrameCount());
17206 checkStackFrame(origin, "bar", 2, 10, false, false,
17207 stackTrace->GetFrame(0));
17208 checkStackFrame(origin, "foo", 6, 3, false, false,
17209 stackTrace->GetFrame(1));
17210 // This is the source string inside the eval which has the call to foo.
17211 checkStackFrame(NULL, "", 1, 5, false, false,
17212 stackTrace->GetFrame(2));
17213 // The last frame is an anonymous function which has the initial eval call.
17214 checkStackFrame(origin, "", 8, 7, false, false,
17215 stackTrace->GetFrame(3));
17217 CHECK(stackTrace->AsArray()->IsArray());
17218 } else if (testGroup == kDetailedTest) {
17219 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17220 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17221 CHECK_EQ(4, stackTrace->GetFrameCount());
17222 checkStackFrame(origin, "bat", 4, 22, false, false,
17223 stackTrace->GetFrame(0));
17224 checkStackFrame(origin, "baz", 8, 3, false, true,
17225 stackTrace->GetFrame(1));
17226 bool is_eval = true;
17227 // This is the source string inside the eval which has the call to baz.
17228 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17229 stackTrace->GetFrame(2));
17230 // The last frame is an anonymous function which has the initial eval call.
17231 checkStackFrame(origin, "", 10, 1, false, false,
17232 stackTrace->GetFrame(3));
17234 CHECK(stackTrace->AsArray()->IsArray());
17239 // Tests the C++ StackTrace API.
17240 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17241 // THREADED_TEST(CaptureStackTrace) {
17242 TEST(CaptureStackTrace) {
17243 v8::Isolate* isolate = CcTest::isolate();
17244 v8::HandleScope scope(isolate);
17245 v8::Handle<v8::String> origin =
17246 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17247 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17248 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17249 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17250 LocalContext context(0, templ);
17252 // Test getting OVERVIEW information. Should ignore information that is not
17253 // script name, function name, line number, and column offset.
17254 const char *overview_source =
17255 "function bar() {\n"
17256 " var y; AnalyzeStackInNativeCode(1);\n"
17258 "function foo() {\n"
17262 "var x;eval('new foo();');";
17263 v8::Handle<v8::String> overview_src =
17264 v8::String::NewFromUtf8(isolate, overview_source);
17265 v8::ScriptCompiler::Source script_source(overview_src,
17266 v8::ScriptOrigin(origin));
17267 v8::Handle<Value> overview_result(
17268 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17269 ->BindToCurrentContext()
17271 CHECK(!overview_result.IsEmpty());
17272 CHECK(overview_result->IsObject());
17274 // Test getting DETAILED information.
17275 const char *detailed_source =
17276 "function bat() {AnalyzeStackInNativeCode(2);\n"
17279 "function baz() {\n"
17282 "eval('new baz();');";
17283 v8::Handle<v8::String> detailed_src =
17284 v8::String::NewFromUtf8(isolate, detailed_source);
17285 // Make the script using a non-zero line and column offset.
17286 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17287 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17288 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17289 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17290 v8::Handle<v8::UnboundScript> detailed_script(
17291 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17292 v8::Handle<Value> detailed_result(
17293 detailed_script->BindToCurrentContext()->Run());
17294 CHECK(!detailed_result.IsEmpty());
17295 CHECK(detailed_result->IsObject());
17299 static void StackTraceForUncaughtExceptionListener(
17300 v8::Handle<v8::Message> message,
17301 v8::Handle<Value>) {
17302 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17303 CHECK_EQ(2, stack_trace->GetFrameCount());
17304 checkStackFrame("origin", "foo", 2, 3, false, false,
17305 stack_trace->GetFrame(0));
17306 checkStackFrame("origin", "bar", 5, 3, false, false,
17307 stack_trace->GetFrame(1));
17311 TEST(CaptureStackTraceForUncaughtException) {
17314 v8::HandleScope scope(env->GetIsolate());
17315 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17316 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17318 CompileRunWithOrigin(
17319 "function foo() {\n"
17322 "function bar() {\n"
17326 v8::Local<v8::Object> global = env->Global();
17327 Local<Value> trouble = global->Get(v8_str("bar"));
17328 CHECK(trouble->IsFunction());
17329 Function::Cast(*trouble)->Call(global, 0, NULL);
17330 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17331 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17335 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17337 v8::HandleScope scope(env->GetIsolate());
17338 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17340 v8::StackTrace::kDetailed);
17343 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17344 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17345 " 'isConstructor'];\n"
17346 "for (var i = 0; i < setters.length; i++) {\n"
17347 " var prop = setters[i];\n"
17348 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17350 CompileRun("throw 'exception';");
17351 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17355 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17356 v8::Handle<v8::Value> data) {
17357 // Use the frame where JavaScript is called from.
17358 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17359 CHECK(!stack_trace.IsEmpty());
17360 int frame_count = stack_trace->GetFrameCount();
17361 CHECK_EQ(3, frame_count);
17362 int line_number[] = {1, 2, 5};
17363 for (int i = 0; i < frame_count; i++) {
17364 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17369 // Test that we only return the stack trace at the site where the exception
17370 // is first thrown (not where it is rethrown).
17371 TEST(RethrowStackTrace) {
17373 v8::HandleScope scope(env->GetIsolate());
17374 // We make sure that
17375 // - the stack trace of the ReferenceError in g() is reported.
17376 // - the stack trace is not overwritten when e1 is rethrown by t().
17377 // - the stack trace of e2 does not overwrite that of e1.
17378 const char* source =
17379 "function g() { error; } \n"
17380 "function f() { g(); } \n"
17381 "function t(e) { throw e; } \n"
17384 "} catch (e1) { \n"
17387 " } catch (e2) { \n"
17391 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17392 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17393 CompileRun(source);
17394 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17395 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17399 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17400 v8::Handle<v8::Value> data) {
17401 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17402 CHECK(!stack_trace.IsEmpty());
17403 int frame_count = stack_trace->GetFrameCount();
17404 CHECK_EQ(2, frame_count);
17405 int line_number[] = {3, 7};
17406 for (int i = 0; i < frame_count; i++) {
17407 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17412 // Test that we do not recognize identity for primitive exceptions.
17413 TEST(RethrowPrimitiveStackTrace) {
17415 v8::HandleScope scope(env->GetIsolate());
17416 // We do not capture stack trace for non Error objects on creation time.
17417 // Instead, we capture the stack trace on last throw.
17418 const char* source =
17419 "function g() { throw 404; } \n"
17420 "function f() { g(); } \n"
17421 "function t(e) { throw e; } \n"
17424 "} catch (e1) { \n"
17427 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17428 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17429 CompileRun(source);
17430 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17431 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17435 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17436 v8::Handle<v8::Value> data) {
17437 // Use the frame where JavaScript is called from.
17438 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17439 CHECK(!stack_trace.IsEmpty());
17440 CHECK_EQ(1, stack_trace->GetFrameCount());
17441 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17445 // Test that the stack trace is captured when the error object is created and
17446 // not where it is thrown.
17447 TEST(RethrowExistingStackTrace) {
17449 v8::HandleScope scope(env->GetIsolate());
17450 const char* source =
17451 "var e = new Error(); \n"
17453 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17454 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17455 CompileRun(source);
17456 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17457 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17461 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17462 v8::Handle<v8::Value> data) {
17463 // Use the frame where JavaScript is called from.
17464 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17465 CHECK(!stack_trace.IsEmpty());
17466 CHECK_EQ(1, stack_trace->GetFrameCount());
17467 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17471 // Test that the stack trace is captured where the bogus Error object is thrown.
17472 TEST(RethrowBogusErrorStackTrace) {
17474 v8::HandleScope scope(env->GetIsolate());
17475 const char* source =
17476 "var e = {__proto__: new Error()} \n"
17478 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17479 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17480 CompileRun(source);
17481 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17482 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17486 void AnalyzeStackOfEvalWithSourceURL(
17487 const v8::FunctionCallbackInfo<v8::Value>& args) {
17488 v8::HandleScope scope(args.GetIsolate());
17489 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17490 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17491 CHECK_EQ(5, stackTrace->GetFrameCount());
17492 v8::Handle<v8::String> url = v8_str("eval_url");
17493 for (int i = 0; i < 3; i++) {
17494 v8::Handle<v8::String> name =
17495 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17496 CHECK(!name.IsEmpty());
17497 CHECK_EQ(url, name);
17502 TEST(SourceURLInStackTrace) {
17503 v8::Isolate* isolate = CcTest::isolate();
17504 v8::HandleScope scope(isolate);
17505 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17506 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17507 v8::FunctionTemplate::New(isolate,
17508 AnalyzeStackOfEvalWithSourceURL));
17509 LocalContext context(0, templ);
17511 const char *source =
17512 "function outer() {\n"
17513 "function bar() {\n"
17514 " AnalyzeStackOfEvalWithSourceURL();\n"
17516 "function foo() {\n"
17522 "eval('(' + outer +')()%s');";
17524 i::ScopedVector<char> code(1024);
17525 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17526 CHECK(CompileRun(code.start())->IsUndefined());
17527 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17528 CHECK(CompileRun(code.start())->IsUndefined());
17532 static int scriptIdInStack[2];
17534 void AnalyzeScriptIdInStack(
17535 const v8::FunctionCallbackInfo<v8::Value>& args) {
17536 v8::HandleScope scope(args.GetIsolate());
17537 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17538 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17539 CHECK_EQ(2, stackTrace->GetFrameCount());
17540 for (int i = 0; i < 2; i++) {
17541 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17546 TEST(ScriptIdInStackTrace) {
17547 v8::Isolate* isolate = CcTest::isolate();
17548 v8::HandleScope scope(isolate);
17549 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17550 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17551 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17552 LocalContext context(0, templ);
17554 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17556 "function foo() {\n"
17557 " AnalyzeScriptIdInStack();"
17560 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17562 for (int i = 0; i < 2; i++) {
17563 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17564 CHECK_EQ(scriptIdInStack[i], script->GetId());
17569 void AnalyzeStackOfInlineScriptWithSourceURL(
17570 const v8::FunctionCallbackInfo<v8::Value>& args) {
17571 v8::HandleScope scope(args.GetIsolate());
17572 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17573 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17574 CHECK_EQ(4, stackTrace->GetFrameCount());
17575 v8::Handle<v8::String> url = v8_str("url");
17576 for (int i = 0; i < 3; i++) {
17577 v8::Handle<v8::String> name =
17578 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17579 CHECK(!name.IsEmpty());
17580 CHECK_EQ(url, name);
17585 TEST(InlineScriptWithSourceURLInStackTrace) {
17586 v8::Isolate* isolate = CcTest::isolate();
17587 v8::HandleScope scope(isolate);
17588 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17589 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17590 v8::FunctionTemplate::New(
17591 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17592 LocalContext context(0, templ);
17594 const char *source =
17595 "function outer() {\n"
17596 "function bar() {\n"
17597 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17599 "function foo() {\n"
17607 i::ScopedVector<char> code(1024);
17608 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17609 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17610 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17611 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17615 void AnalyzeStackOfDynamicScriptWithSourceURL(
17616 const v8::FunctionCallbackInfo<v8::Value>& args) {
17617 v8::HandleScope scope(args.GetIsolate());
17618 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17619 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17620 CHECK_EQ(4, stackTrace->GetFrameCount());
17621 v8::Handle<v8::String> url = v8_str("source_url");
17622 for (int i = 0; i < 3; i++) {
17623 v8::Handle<v8::String> name =
17624 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17625 CHECK(!name.IsEmpty());
17626 CHECK_EQ(url, name);
17631 TEST(DynamicWithSourceURLInStackTrace) {
17632 v8::Isolate* isolate = CcTest::isolate();
17633 v8::HandleScope scope(isolate);
17634 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17635 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17636 v8::FunctionTemplate::New(
17637 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17638 LocalContext context(0, templ);
17640 const char *source =
17641 "function outer() {\n"
17642 "function bar() {\n"
17643 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17645 "function foo() {\n"
17653 i::ScopedVector<char> code(1024);
17654 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17655 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17656 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17657 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17661 TEST(DynamicWithSourceURLInStackTraceString) {
17662 LocalContext context;
17663 v8::HandleScope scope(context->GetIsolate());
17665 const char *source =
17666 "function outer() {\n"
17667 " function foo() {\n"
17674 i::ScopedVector<char> code(1024);
17675 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17676 v8::TryCatch try_catch;
17677 CompileRunWithOrigin(code.start(), "", 0, 0);
17678 CHECK(try_catch.HasCaught());
17679 v8::String::Utf8Value stack(try_catch.StackTrace());
17680 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17684 static void CreateGarbageInOldSpace() {
17685 i::Factory* factory = CcTest::i_isolate()->factory();
17686 v8::HandleScope scope(CcTest::isolate());
17687 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17688 for (int i = 0; i < 1000; i++) {
17689 factory->NewFixedArray(1000, i::TENURED);
17694 // Test that idle notification can be handled and eventually returns true.
17695 TEST(IdleNotification) {
17696 const intptr_t MB = 1024 * 1024;
17698 v8::HandleScope scope(env->GetIsolate());
17699 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17700 CreateGarbageInOldSpace();
17701 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17702 CHECK_GT(size_with_garbage, initial_size + MB);
17703 bool finished = false;
17704 for (int i = 0; i < 200 && !finished; i++) {
17705 finished = v8::V8::IdleNotification();
17707 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17709 CHECK_LT(final_size, initial_size + 1);
17713 // Test that idle notification can be handled and eventually collects garbage.
17714 TEST(IdleNotificationWithSmallHint) {
17715 const intptr_t MB = 1024 * 1024;
17716 const int IdlePauseInMs = 900;
17718 v8::HandleScope scope(env->GetIsolate());
17719 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17720 CreateGarbageInOldSpace();
17721 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17722 CHECK_GT(size_with_garbage, initial_size + MB);
17723 bool finished = false;
17724 for (int i = 0; i < 200 && !finished; i++) {
17725 finished = v8::V8::IdleNotification(IdlePauseInMs);
17727 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17729 CHECK_LT(final_size, initial_size + 1);
17733 // Test that idle notification can be handled and eventually collects garbage.
17734 TEST(IdleNotificationWithLargeHint) {
17735 const intptr_t MB = 1024 * 1024;
17736 const int IdlePauseInMs = 900;
17738 v8::HandleScope scope(env->GetIsolate());
17739 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17740 CreateGarbageInOldSpace();
17741 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17742 CHECK_GT(size_with_garbage, initial_size + MB);
17743 bool finished = false;
17744 for (int i = 0; i < 200 && !finished; i++) {
17745 finished = v8::V8::IdleNotification(IdlePauseInMs);
17747 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17749 CHECK_LT(final_size, initial_size + 1);
17753 TEST(Regress2107) {
17754 const intptr_t MB = 1024 * 1024;
17755 const int kShortIdlePauseInMs = 100;
17756 const int kLongIdlePauseInMs = 1000;
17758 v8::Isolate* isolate = env->GetIsolate();
17759 v8::HandleScope scope(env->GetIsolate());
17760 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17761 // Send idle notification to start a round of incremental GCs.
17762 v8::V8::IdleNotification(kShortIdlePauseInMs);
17763 // Emulate 7 page reloads.
17764 for (int i = 0; i < 7; i++) {
17766 v8::HandleScope inner_scope(env->GetIsolate());
17767 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17769 CreateGarbageInOldSpace();
17772 v8::V8::ContextDisposedNotification();
17773 v8::V8::IdleNotification(kLongIdlePauseInMs);
17775 // Create garbage and check that idle notification still collects it.
17776 CreateGarbageInOldSpace();
17777 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17778 CHECK_GT(size_with_garbage, initial_size + MB);
17779 bool finished = false;
17780 for (int i = 0; i < 200 && !finished; i++) {
17781 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17783 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17784 CHECK_LT(final_size, initial_size + 1);
17788 TEST(Regress2333) {
17790 for (int i = 0; i < 3; i++) {
17791 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17795 static uint32_t* stack_limit;
17797 static void GetStackLimitCallback(
17798 const v8::FunctionCallbackInfo<v8::Value>& args) {
17799 stack_limit = reinterpret_cast<uint32_t*>(
17800 CcTest::i_isolate()->stack_guard()->real_climit());
17804 // Uses the address of a local variable to determine the stack top now.
17805 // Given a size, returns an address that is that far from the current
17807 static uint32_t* ComputeStackLimit(uint32_t size) {
17808 uint32_t* answer = &size - (size / sizeof(size));
17809 // If the size is very large and the stack is very near the bottom of
17810 // memory then the calculation above may wrap around and give an address
17811 // that is above the (downwards-growing) stack. In that case we return
17812 // a very low address.
17813 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17818 // We need at least 165kB for an x64 debug build with clang and ASAN.
17819 static const int stack_breathing_room = 256 * i::KB;
17822 TEST(SetResourceConstraints) {
17823 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17825 // Set stack limit.
17826 v8::ResourceConstraints constraints;
17827 constraints.set_stack_limit(set_limit);
17828 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17830 // Execute a script.
17832 v8::HandleScope scope(env->GetIsolate());
17833 Local<v8::FunctionTemplate> fun_templ =
17834 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17835 Local<Function> fun = fun_templ->GetFunction();
17836 env->Global()->Set(v8_str("get_stack_limit"), fun);
17837 CompileRun("get_stack_limit();");
17839 CHECK(stack_limit == set_limit);
17843 TEST(SetResourceConstraintsInThread) {
17844 uint32_t* set_limit;
17846 v8::Locker locker(CcTest::isolate());
17847 set_limit = ComputeStackLimit(stack_breathing_room);
17849 // Set stack limit.
17850 v8::ResourceConstraints constraints;
17851 constraints.set_stack_limit(set_limit);
17852 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17854 // Execute a script.
17855 v8::HandleScope scope(CcTest::isolate());
17857 Local<v8::FunctionTemplate> fun_templ =
17858 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17859 Local<Function> fun = fun_templ->GetFunction();
17860 env->Global()->Set(v8_str("get_stack_limit"), fun);
17861 CompileRun("get_stack_limit();");
17863 CHECK(stack_limit == set_limit);
17866 v8::Locker locker(CcTest::isolate());
17867 CHECK(stack_limit == set_limit);
17872 THREADED_TEST(GetHeapStatistics) {
17874 v8::HandleScope scope(c1->GetIsolate());
17875 v8::HeapStatistics heap_statistics;
17876 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17877 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17878 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17879 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17880 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17884 class VisitorImpl : public v8::ExternalResourceVisitor {
17886 explicit VisitorImpl(TestResource** resource) {
17887 for (int i = 0; i < 4; i++) {
17888 resource_[i] = resource[i];
17889 found_resource_[i] = false;
17892 virtual ~VisitorImpl() {}
17893 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17894 if (!string->IsExternal()) {
17895 CHECK(string->IsExternalAscii());
17898 v8::String::ExternalStringResource* resource =
17899 string->GetExternalStringResource();
17901 for (int i = 0; i < 4; i++) {
17902 if (resource_[i] == resource) {
17903 CHECK(!found_resource_[i]);
17904 found_resource_[i] = true;
17908 void CheckVisitedResources() {
17909 for (int i = 0; i < 4; i++) {
17910 CHECK(found_resource_[i]);
17915 v8::String::ExternalStringResource* resource_[4];
17916 bool found_resource_[4];
17920 TEST(ExternalizeOldSpaceTwoByteCons) {
17922 v8::HandleScope scope(env->GetIsolate());
17923 v8::Local<v8::String> cons =
17924 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17925 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17926 CcTest::heap()->CollectAllAvailableGarbage();
17927 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17928 *v8::Utils::OpenHandle(*cons)));
17930 TestResource* resource = new TestResource(
17931 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17932 cons->MakeExternal(resource);
17934 CHECK(cons->IsExternal());
17935 CHECK_EQ(resource, cons->GetExternalStringResource());
17936 String::Encoding encoding;
17937 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17938 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17942 TEST(ExternalizeOldSpaceOneByteCons) {
17944 v8::HandleScope scope(env->GetIsolate());
17945 v8::Local<v8::String> cons =
17946 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17947 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17948 CcTest::heap()->CollectAllAvailableGarbage();
17949 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17950 *v8::Utils::OpenHandle(*cons)));
17952 TestAsciiResource* resource =
17953 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17954 cons->MakeExternal(resource);
17956 CHECK(cons->IsExternalAscii());
17957 CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17958 String::Encoding encoding;
17959 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17960 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17964 TEST(VisitExternalStrings) {
17966 v8::HandleScope scope(env->GetIsolate());
17967 const char* string = "Some string";
17968 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17969 TestResource* resource[4];
17970 resource[0] = new TestResource(two_byte_string);
17971 v8::Local<v8::String> string0 =
17972 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17973 resource[1] = new TestResource(two_byte_string, NULL, false);
17974 v8::Local<v8::String> string1 =
17975 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17977 // Externalized symbol.
17978 resource[2] = new TestResource(two_byte_string, NULL, false);
17979 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17980 env->GetIsolate(), string, v8::String::kInternalizedString);
17981 CHECK(string2->MakeExternal(resource[2]));
17983 // Symbolized External.
17984 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17985 v8::Local<v8::String> string3 =
17986 v8::String::NewExternal(env->GetIsolate(), resource[3]);
17987 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17988 // Turn into a symbol.
17989 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17990 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
17991 string3_i).is_null());
17992 CHECK(string3_i->IsInternalizedString());
17994 // We need to add usages for string* to avoid warnings in GCC 4.7
17995 CHECK(string0->IsExternal());
17996 CHECK(string1->IsExternal());
17997 CHECK(string2->IsExternal());
17998 CHECK(string3->IsExternal());
18000 VisitorImpl visitor(resource);
18001 v8::V8::VisitExternalResources(&visitor);
18002 visitor.CheckVisitedResources();
18006 TEST(ExternalStringCollectedAtTearDown) {
18008 v8::Isolate* isolate = v8::Isolate::New();
18009 { v8::Isolate::Scope isolate_scope(isolate);
18010 v8::HandleScope handle_scope(isolate);
18011 const char* s = "One string to test them all, one string to find them.";
18012 TestAsciiResource* inscription =
18013 new TestAsciiResource(i::StrDup(s), &destroyed);
18014 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18015 // Ring is still alive. Orcs are roaming freely across our lands.
18016 CHECK_EQ(0, destroyed);
18020 isolate->Dispose();
18021 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18022 CHECK_EQ(1, destroyed);
18026 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18028 v8::Isolate* isolate = v8::Isolate::New();
18029 { v8::Isolate::Scope isolate_scope(isolate);
18030 LocalContext env(isolate);
18031 v8::HandleScope handle_scope(isolate);
18032 CompileRun("var ring = 'One string to test them all';");
18033 const char* s = "One string to test them all";
18034 TestAsciiResource* inscription =
18035 new TestAsciiResource(i::StrDup(s), &destroyed);
18036 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18037 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18038 ring->MakeExternal(inscription);
18039 // Ring is still alive. Orcs are roaming freely across our lands.
18040 CHECK_EQ(0, destroyed);
18044 isolate->Dispose();
18045 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18046 CHECK_EQ(1, destroyed);
18050 TEST(ExternalInternalizedStringCollectedAtGC) {
18052 { LocalContext env;
18053 v8::HandleScope handle_scope(env->GetIsolate());
18054 CompileRun("var ring = 'One string to test them all';");
18055 const char* s = "One string to test them all";
18056 TestAsciiResource* inscription =
18057 new TestAsciiResource(i::StrDup(s), &destroyed);
18058 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18059 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18060 ring->MakeExternal(inscription);
18061 // Ring is still alive. Orcs are roaming freely across our lands.
18062 CHECK_EQ(0, destroyed);
18066 // Garbage collector deals swift blows to evil.
18067 CcTest::i_isolate()->compilation_cache()->Clear();
18068 CcTest::heap()->CollectAllAvailableGarbage();
18070 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18071 CHECK_EQ(1, destroyed);
18075 static double DoubleFromBits(uint64_t value) {
18077 i::OS::MemCopy(&target, &value, sizeof(target));
18082 static uint64_t DoubleToBits(double value) {
18084 i::OS::MemCopy(&target, &value, sizeof(target));
18089 static double DoubleToDateTime(double input) {
18090 double date_limit = 864e13;
18091 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18092 return i::OS::nan_value();
18094 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18098 // We don't have a consistent way to write 64-bit constants syntactically, so we
18099 // split them into two 32-bit constants and combine them programmatically.
18100 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18101 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18105 THREADED_TEST(QuietSignalingNaNs) {
18106 LocalContext context;
18107 v8::Isolate* isolate = context->GetIsolate();
18108 v8::HandleScope scope(isolate);
18109 v8::TryCatch try_catch;
18111 // Special double values.
18112 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18113 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18114 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18115 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18116 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18117 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18118 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18120 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18121 // on either side of the epoch.
18122 double date_limit = 864e13;
18124 double test_values[] = {
18146 int num_test_values = 20;
18148 for (int i = 0; i < num_test_values; i++) {
18149 double test_value = test_values[i];
18151 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18152 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18153 double stored_number = number->NumberValue();
18154 if (!std::isnan(test_value)) {
18155 CHECK_EQ(test_value, stored_number);
18157 uint64_t stored_bits = DoubleToBits(stored_number);
18158 // Check if quiet nan (bits 51..62 all set).
18159 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18160 // Most significant fraction bit for quiet nan is set to 0
18161 // on MIPS architecture. Allowed by IEEE-754.
18162 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18164 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18168 // Check that Date::New preserves non-NaNs in the date range and
18170 v8::Handle<v8::Value> date =
18171 v8::Date::New(isolate, test_value);
18172 double expected_stored_date = DoubleToDateTime(test_value);
18173 double stored_date = date->NumberValue();
18174 if (!std::isnan(expected_stored_date)) {
18175 CHECK_EQ(expected_stored_date, stored_date);
18177 uint64_t stored_bits = DoubleToBits(stored_date);
18178 // Check if quiet nan (bits 51..62 all set).
18179 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18180 // Most significant fraction bit for quiet nan is set to 0
18181 // on MIPS architecture. Allowed by IEEE-754.
18182 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18184 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18191 static void SpaghettiIncident(
18192 const v8::FunctionCallbackInfo<v8::Value>& args) {
18193 v8::HandleScope scope(args.GetIsolate());
18195 v8::Handle<v8::String> str(args[0]->ToString());
18197 if (tc.HasCaught())
18202 // Test that an exception can be propagated down through a spaghetti
18203 // stack using ReThrow.
18204 THREADED_TEST(SpaghettiStackReThrow) {
18205 v8::Isolate* isolate = CcTest::isolate();
18206 v8::HandleScope scope(isolate);
18207 LocalContext context;
18208 context->Global()->Set(
18209 v8::String::NewFromUtf8(isolate, "s"),
18210 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18211 v8::TryCatch try_catch;
18215 " toString: function () {"
18225 CHECK(try_catch.HasCaught());
18226 v8::String::Utf8Value value(try_catch.Exception());
18227 CHECK_EQ(0, strcmp(*value, "Hey!"));
18232 v8::V8::Initialize();
18233 v8::Isolate* isolate = CcTest::isolate();
18234 v8::HandleScope scope(isolate);
18235 v8::Local<Context> other_context;
18238 // Create a context used to keep the code from aging in the compilation
18240 other_context = Context::New(isolate);
18242 // Context-dependent context data creates reference from the compilation
18243 // cache to the global object.
18244 const char* source_simple = "1";
18246 v8::HandleScope scope(isolate);
18247 v8::Local<Context> context = Context::New(isolate);
18250 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18251 context->SetEmbedderData(0, obj);
18252 CompileRun(source_simple);
18255 v8::V8::ContextDisposedNotification();
18256 for (gc_count = 1; gc_count < 10; gc_count++) {
18257 other_context->Enter();
18258 CompileRun(source_simple);
18259 other_context->Exit();
18260 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18261 if (GetGlobalObjectsCount() == 1) break;
18263 CHECK_GE(2, gc_count);
18264 CHECK_EQ(1, GetGlobalObjectsCount());
18266 // Eval in a function creates reference from the compilation cache to the
18268 const char* source_eval = "function f(){eval('1')}; f()";
18270 v8::HandleScope scope(isolate);
18271 v8::Local<Context> context = Context::New(isolate);
18274 CompileRun(source_eval);
18277 v8::V8::ContextDisposedNotification();
18278 for (gc_count = 1; gc_count < 10; gc_count++) {
18279 other_context->Enter();
18280 CompileRun(source_eval);
18281 other_context->Exit();
18282 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18283 if (GetGlobalObjectsCount() == 1) break;
18285 CHECK_GE(2, gc_count);
18286 CHECK_EQ(1, GetGlobalObjectsCount());
18288 // Looking up the line number for an exception creates reference from the
18289 // compilation cache to the global object.
18290 const char* source_exception = "function f(){throw 1;} f()";
18292 v8::HandleScope scope(isolate);
18293 v8::Local<Context> context = Context::New(isolate);
18296 v8::TryCatch try_catch;
18297 CompileRun(source_exception);
18298 CHECK(try_catch.HasCaught());
18299 v8::Handle<v8::Message> message = try_catch.Message();
18300 CHECK(!message.IsEmpty());
18301 CHECK_EQ(1, message->GetLineNumber());
18304 v8::V8::ContextDisposedNotification();
18305 for (gc_count = 1; gc_count < 10; gc_count++) {
18306 other_context->Enter();
18307 CompileRun(source_exception);
18308 other_context->Exit();
18309 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18310 if (GetGlobalObjectsCount() == 1) break;
18312 CHECK_GE(2, gc_count);
18313 CHECK_EQ(1, GetGlobalObjectsCount());
18315 v8::V8::ContextDisposedNotification();
18319 THREADED_TEST(ScriptOrigin) {
18321 v8::HandleScope scope(env->GetIsolate());
18322 v8::ScriptOrigin origin =
18323 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18324 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18325 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18326 v8::Script::Compile(script, &origin)->Run();
18327 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18328 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18329 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18330 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18332 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18333 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18334 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18336 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18337 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18338 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18342 THREADED_TEST(FunctionGetInferredName) {
18344 v8::HandleScope scope(env->GetIsolate());
18345 v8::ScriptOrigin origin =
18346 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18347 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18349 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18350 v8::Script::Compile(script, &origin)->Run();
18351 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18352 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18353 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18357 THREADED_TEST(FunctionGetDisplayName) {
18359 v8::HandleScope scope(env->GetIsolate());
18360 const char* code = "var error = false;"
18361 "function a() { this.x = 1; };"
18362 "a.displayName = 'display_a';"
18363 "var b = (function() {"
18364 " var f = function() { this.x = 2; };"
18365 " f.displayName = 'display_b';"
18368 "var c = function() {};"
18369 "c.__defineGetter__('displayName', function() {"
18371 " throw new Error();"
18374 "d.__defineGetter__('displayName', function() {"
18376 " return 'wrong_display_name';"
18379 "e.displayName = 'wrong_display_name';"
18380 "e.__defineSetter__('displayName', function() {"
18382 " throw new Error();"
18385 "f.displayName = { 'foo': 6, toString: function() {"
18387 " return 'wrong_display_name';"
18389 "var g = function() {"
18390 " arguments.callee.displayName = 'set_in_runtime';"
18393 v8::ScriptOrigin origin =
18394 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18395 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18397 v8::Local<v8::Value> error =
18398 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18399 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18400 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18401 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18402 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18403 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18404 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18405 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18406 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18407 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18408 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18409 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18410 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18411 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18412 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18413 CHECK_EQ(false, error->BooleanValue());
18414 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18415 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18416 CHECK(c->GetDisplayName()->IsUndefined());
18417 CHECK(d->GetDisplayName()->IsUndefined());
18418 CHECK(e->GetDisplayName()->IsUndefined());
18419 CHECK(f->GetDisplayName()->IsUndefined());
18420 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18424 THREADED_TEST(ScriptLineNumber) {
18426 v8::HandleScope scope(env->GetIsolate());
18427 v8::ScriptOrigin origin =
18428 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18429 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18430 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18431 v8::Script::Compile(script, &origin)->Run();
18432 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18433 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18434 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18435 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18436 CHECK_EQ(0, f->GetScriptLineNumber());
18437 CHECK_EQ(2, g->GetScriptLineNumber());
18441 THREADED_TEST(ScriptColumnNumber) {
18443 v8::Isolate* isolate = env->GetIsolate();
18444 v8::HandleScope scope(isolate);
18445 v8::ScriptOrigin origin =
18446 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18447 v8::Integer::New(isolate, 3),
18448 v8::Integer::New(isolate, 2));
18449 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18450 isolate, "function foo() {}\n\n function bar() {}");
18451 v8::Script::Compile(script, &origin)->Run();
18452 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18453 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18454 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18455 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18456 CHECK_EQ(14, foo->GetScriptColumnNumber());
18457 CHECK_EQ(17, bar->GetScriptColumnNumber());
18461 THREADED_TEST(FunctionIsBuiltin) {
18463 v8::Isolate* isolate = env->GetIsolate();
18464 v8::HandleScope scope(isolate);
18465 v8::Local<v8::Function> f;
18466 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18467 CHECK(f->IsBuiltin());
18468 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18469 CHECK(f->IsBuiltin());
18470 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18471 CHECK(f->IsBuiltin());
18472 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18473 CHECK(f->IsBuiltin());
18474 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18475 CHECK(!f->IsBuiltin());
18479 THREADED_TEST(FunctionGetScriptId) {
18481 v8::Isolate* isolate = env->GetIsolate();
18482 v8::HandleScope scope(isolate);
18483 v8::ScriptOrigin origin =
18484 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18485 v8::Integer::New(isolate, 3),
18486 v8::Integer::New(isolate, 2));
18487 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18488 isolate, "function foo() {}\n\n function bar() {}");
18489 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18491 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18492 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18493 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18494 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18495 CHECK_EQ(script->GetId(), foo->ScriptId());
18496 CHECK_EQ(script->GetId(), bar->ScriptId());
18500 THREADED_TEST(FunctionGetBoundFunction) {
18502 v8::HandleScope scope(env->GetIsolate());
18503 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18504 env->GetIsolate(), "test"));
18505 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18507 "var a = new Object();\n"
18509 "function f () { return this.x };\n"
18510 "var g = f.bind(a);\n"
18512 v8::Script::Compile(script, &origin)->Run();
18513 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18514 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18515 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18516 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18517 CHECK(g->GetBoundFunction()->IsFunction());
18518 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18519 g->GetBoundFunction());
18520 CHECK_EQ(f->GetName(), original_function->GetName());
18521 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18522 CHECK_EQ(f->GetScriptColumnNumber(),
18523 original_function->GetScriptColumnNumber());
18527 static void GetterWhichReturns42(
18528 Local<String> name,
18529 const v8::PropertyCallbackInfo<v8::Value>& info) {
18530 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18531 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18532 info.GetReturnValue().Set(v8_num(42));
18536 static void SetterWhichSetsYOnThisTo23(
18537 Local<String> name,
18538 Local<Value> value,
18539 const v8::PropertyCallbackInfo<void>& info) {
18540 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18541 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18542 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18546 void FooGetInterceptor(Local<String> name,
18547 const v8::PropertyCallbackInfo<v8::Value>& info) {
18548 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18549 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18550 if (!name->Equals(v8_str("foo"))) return;
18551 info.GetReturnValue().Set(v8_num(42));
18555 void FooSetInterceptor(Local<String> name,
18556 Local<Value> value,
18557 const v8::PropertyCallbackInfo<v8::Value>& info) {
18558 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18559 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18560 if (!name->Equals(v8_str("foo"))) return;
18561 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18562 info.GetReturnValue().Set(v8_num(23));
18566 TEST(SetterOnConstructorPrototype) {
18567 v8::Isolate* isolate = CcTest::isolate();
18568 v8::HandleScope scope(isolate);
18569 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18570 templ->SetAccessor(v8_str("x"),
18571 GetterWhichReturns42,
18572 SetterWhichSetsYOnThisTo23);
18573 LocalContext context;
18574 context->Global()->Set(v8_str("P"), templ->NewInstance());
18575 CompileRun("function C1() {"
18578 "C1.prototype = P;"
18582 "C2.prototype = { };"
18583 "C2.prototype.__proto__ = P;");
18585 v8::Local<v8::Script> script;
18586 script = v8_compile("new C1();");
18587 for (int i = 0; i < 10; i++) {
18588 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18589 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18590 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18593 script = v8_compile("new C2();");
18594 for (int i = 0; i < 10; i++) {
18595 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18596 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18597 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18602 static void NamedPropertyGetterWhichReturns42(
18603 Local<String> name,
18604 const v8::PropertyCallbackInfo<v8::Value>& info) {
18605 info.GetReturnValue().Set(v8_num(42));
18609 static void NamedPropertySetterWhichSetsYOnThisTo23(
18610 Local<String> name,
18611 Local<Value> value,
18612 const v8::PropertyCallbackInfo<v8::Value>& info) {
18613 if (name->Equals(v8_str("x"))) {
18614 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18619 THREADED_TEST(InterceptorOnConstructorPrototype) {
18620 v8::Isolate* isolate = CcTest::isolate();
18621 v8::HandleScope scope(isolate);
18622 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18623 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18624 NamedPropertySetterWhichSetsYOnThisTo23);
18625 LocalContext context;
18626 context->Global()->Set(v8_str("P"), templ->NewInstance());
18627 CompileRun("function C1() {"
18630 "C1.prototype = P;"
18634 "C2.prototype = { };"
18635 "C2.prototype.__proto__ = P;");
18637 v8::Local<v8::Script> script;
18638 script = v8_compile("new C1();");
18639 for (int i = 0; i < 10; i++) {
18640 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18641 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18642 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18645 script = v8_compile("new C2();");
18646 for (int i = 0; i < 10; i++) {
18647 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18648 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18649 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18655 const char* source = "function C1() {"
18658 "C1.prototype = P;";
18660 LocalContext context;
18661 v8::Isolate* isolate = context->GetIsolate();
18662 v8::HandleScope scope(isolate);
18663 v8::Local<v8::Script> script;
18665 // Use a simple object as prototype.
18666 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18667 prototype->Set(v8_str("y"), v8_num(42));
18668 context->Global()->Set(v8_str("P"), prototype);
18670 // This compile will add the code to the compilation cache.
18671 CompileRun(source);
18673 script = v8_compile("new C1();");
18674 // Allow enough iterations for the inobject slack tracking logic
18675 // to finalize instance size and install the fast construct stub.
18676 for (int i = 0; i < 256; i++) {
18677 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18678 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18679 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18682 // Use an API object with accessors as prototype.
18683 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18684 templ->SetAccessor(v8_str("x"),
18685 GetterWhichReturns42,
18686 SetterWhichSetsYOnThisTo23);
18687 context->Global()->Set(v8_str("P"), templ->NewInstance());
18689 // This compile will get the code from the compilation cache.
18690 CompileRun(source);
18692 script = v8_compile("new C1();");
18693 for (int i = 0; i < 10; i++) {
18694 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18695 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18696 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18700 v8::Isolate* gc_callbacks_isolate = NULL;
18701 int prologue_call_count = 0;
18702 int epilogue_call_count = 0;
18703 int prologue_call_count_second = 0;
18704 int epilogue_call_count_second = 0;
18705 int prologue_call_count_alloc = 0;
18706 int epilogue_call_count_alloc = 0;
18708 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18709 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18710 ++prologue_call_count;
18714 void PrologueCallback(v8::Isolate* isolate,
18716 v8::GCCallbackFlags flags) {
18717 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18718 CHECK_EQ(gc_callbacks_isolate, isolate);
18719 ++prologue_call_count;
18723 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18724 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18725 ++epilogue_call_count;
18729 void EpilogueCallback(v8::Isolate* isolate,
18731 v8::GCCallbackFlags flags) {
18732 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18733 CHECK_EQ(gc_callbacks_isolate, isolate);
18734 ++epilogue_call_count;
18738 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18739 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18740 ++prologue_call_count_second;
18744 void PrologueCallbackSecond(v8::Isolate* isolate,
18746 v8::GCCallbackFlags flags) {
18747 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18748 CHECK_EQ(gc_callbacks_isolate, isolate);
18749 ++prologue_call_count_second;
18753 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18754 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18755 ++epilogue_call_count_second;
18759 void EpilogueCallbackSecond(v8::Isolate* isolate,
18761 v8::GCCallbackFlags flags) {
18762 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18763 CHECK_EQ(gc_callbacks_isolate, isolate);
18764 ++epilogue_call_count_second;
18768 void PrologueCallbackAlloc(v8::Isolate* isolate,
18770 v8::GCCallbackFlags flags) {
18771 v8::HandleScope scope(isolate);
18773 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18774 CHECK_EQ(gc_callbacks_isolate, isolate);
18775 ++prologue_call_count_alloc;
18777 // Simulate full heap to see if we will reenter this callback
18778 SimulateFullSpace(CcTest::heap()->new_space());
18780 Local<Object> obj = Object::New(isolate);
18781 CHECK(!obj.IsEmpty());
18783 CcTest::heap()->CollectAllGarbage(
18784 i::Heap::kAbortIncrementalMarkingMask);
18788 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18790 v8::GCCallbackFlags flags) {
18791 v8::HandleScope scope(isolate);
18793 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18794 CHECK_EQ(gc_callbacks_isolate, isolate);
18795 ++epilogue_call_count_alloc;
18797 // Simulate full heap to see if we will reenter this callback
18798 SimulateFullSpace(CcTest::heap()->new_space());
18800 Local<Object> obj = Object::New(isolate);
18801 CHECK(!obj.IsEmpty());
18803 CcTest::heap()->CollectAllGarbage(
18804 i::Heap::kAbortIncrementalMarkingMask);
18808 TEST(GCCallbacksOld) {
18809 LocalContext context;
18811 v8::V8::AddGCPrologueCallback(PrologueCallback);
18812 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18813 CHECK_EQ(0, prologue_call_count);
18814 CHECK_EQ(0, epilogue_call_count);
18815 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18816 CHECK_EQ(1, prologue_call_count);
18817 CHECK_EQ(1, epilogue_call_count);
18818 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18819 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18820 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18821 CHECK_EQ(2, prologue_call_count);
18822 CHECK_EQ(2, epilogue_call_count);
18823 CHECK_EQ(1, prologue_call_count_second);
18824 CHECK_EQ(1, epilogue_call_count_second);
18825 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18826 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18827 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18828 CHECK_EQ(2, prologue_call_count);
18829 CHECK_EQ(2, epilogue_call_count);
18830 CHECK_EQ(2, prologue_call_count_second);
18831 CHECK_EQ(2, epilogue_call_count_second);
18832 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18833 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18834 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18835 CHECK_EQ(2, prologue_call_count);
18836 CHECK_EQ(2, epilogue_call_count);
18837 CHECK_EQ(2, prologue_call_count_second);
18838 CHECK_EQ(2, epilogue_call_count_second);
18842 TEST(GCCallbacks) {
18843 LocalContext context;
18844 v8::Isolate* isolate = context->GetIsolate();
18845 gc_callbacks_isolate = isolate;
18846 isolate->AddGCPrologueCallback(PrologueCallback);
18847 isolate->AddGCEpilogueCallback(EpilogueCallback);
18848 CHECK_EQ(0, prologue_call_count);
18849 CHECK_EQ(0, epilogue_call_count);
18850 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18851 CHECK_EQ(1, prologue_call_count);
18852 CHECK_EQ(1, epilogue_call_count);
18853 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18854 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18855 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18856 CHECK_EQ(2, prologue_call_count);
18857 CHECK_EQ(2, epilogue_call_count);
18858 CHECK_EQ(1, prologue_call_count_second);
18859 CHECK_EQ(1, epilogue_call_count_second);
18860 isolate->RemoveGCPrologueCallback(PrologueCallback);
18861 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18862 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18863 CHECK_EQ(2, prologue_call_count);
18864 CHECK_EQ(2, epilogue_call_count);
18865 CHECK_EQ(2, prologue_call_count_second);
18866 CHECK_EQ(2, epilogue_call_count_second);
18867 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18868 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18869 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18870 CHECK_EQ(2, prologue_call_count);
18871 CHECK_EQ(2, epilogue_call_count);
18872 CHECK_EQ(2, prologue_call_count_second);
18873 CHECK_EQ(2, epilogue_call_count_second);
18875 CHECK_EQ(0, prologue_call_count_alloc);
18876 CHECK_EQ(0, epilogue_call_count_alloc);
18877 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18878 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18879 CcTest::heap()->CollectAllGarbage(
18880 i::Heap::kAbortIncrementalMarkingMask);
18881 CHECK_EQ(1, prologue_call_count_alloc);
18882 CHECK_EQ(1, epilogue_call_count_alloc);
18883 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18884 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18888 THREADED_TEST(AddToJSFunctionResultCache) {
18889 i::FLAG_stress_compaction = false;
18890 i::FLAG_allow_natives_syntax = true;
18891 v8::HandleScope scope(CcTest::isolate());
18893 LocalContext context;
18899 " var r0 = %_GetFromCache(0, key0);"
18900 " var r1 = %_GetFromCache(0, key1);"
18901 " var r0_ = %_GetFromCache(0, key0);"
18903 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18904 " var r1_ = %_GetFromCache(0, key1);"
18906 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18907 " return 'PASSED';"
18909 CcTest::heap()->ClearJSFunctionResultCaches();
18910 ExpectString(code, "PASSED");
18914 THREADED_TEST(FillJSFunctionResultCache) {
18915 i::FLAG_allow_natives_syntax = true;
18916 LocalContext context;
18917 v8::HandleScope scope(context->GetIsolate());
18922 " var r = %_GetFromCache(0, k);"
18923 " for (var i = 0; i < 16; i++) {"
18924 " %_GetFromCache(0, 'a' + i);"
18926 " if (r === %_GetFromCache(0, k))"
18927 " return 'FAILED: k0CacheSize is too small';"
18928 " return 'PASSED';"
18930 CcTest::heap()->ClearJSFunctionResultCaches();
18931 ExpectString(code, "PASSED");
18935 THREADED_TEST(RoundRobinGetFromCache) {
18936 i::FLAG_allow_natives_syntax = true;
18937 LocalContext context;
18938 v8::HandleScope scope(context->GetIsolate());
18943 " for (var i = 0; i < 16; i++) keys.push(i);"
18944 " var values = [];"
18945 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18946 " for (var i = 0; i < 16; i++) {"
18947 " var v = %_GetFromCache(0, keys[i]);"
18948 " if (v.toString() !== values[i].toString())"
18949 " return 'Wrong value for ' + "
18950 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18952 " return 'PASSED';"
18954 CcTest::heap()->ClearJSFunctionResultCaches();
18955 ExpectString(code, "PASSED");
18959 THREADED_TEST(ReverseGetFromCache) {
18960 i::FLAG_allow_natives_syntax = true;
18961 LocalContext context;
18962 v8::HandleScope scope(context->GetIsolate());
18967 " for (var i = 0; i < 16; i++) keys.push(i);"
18968 " var values = [];"
18969 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18970 " for (var i = 15; i >= 16; i--) {"
18971 " var v = %_GetFromCache(0, keys[i]);"
18972 " if (v !== values[i])"
18973 " return 'Wrong value for ' + "
18974 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18976 " return 'PASSED';"
18978 CcTest::heap()->ClearJSFunctionResultCaches();
18979 ExpectString(code, "PASSED");
18983 THREADED_TEST(TestEviction) {
18984 i::FLAG_allow_natives_syntax = true;
18985 LocalContext context;
18986 v8::HandleScope scope(context->GetIsolate());
18990 " for (var i = 0; i < 2*16; i++) {"
18991 " %_GetFromCache(0, 'a' + i);"
18993 " return 'PASSED';"
18995 CcTest::heap()->ClearJSFunctionResultCaches();
18996 ExpectString(code, "PASSED");
19000 THREADED_TEST(TwoByteStringInAsciiCons) {
19001 // See Chromium issue 47824.
19002 LocalContext context;
19003 v8::HandleScope scope(context->GetIsolate());
19005 const char* init_code =
19006 "var str1 = 'abelspendabel';"
19007 "var str2 = str1 + str1 + str1;"
19009 Local<Value> result = CompileRun(init_code);
19011 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19012 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19014 CHECK(result->IsString());
19015 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19016 int length = string->length();
19017 CHECK(string->IsOneByteRepresentation());
19019 i::Handle<i::String> flat_string = i::String::Flatten(string);
19021 CHECK(string->IsOneByteRepresentation());
19022 CHECK(flat_string->IsOneByteRepresentation());
19024 // Create external resource.
19025 uint16_t* uc16_buffer = new uint16_t[length + 1];
19027 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19028 uc16_buffer[length] = 0;
19030 TestResource resource(uc16_buffer);
19032 flat_string->MakeExternal(&resource);
19034 CHECK(flat_string->IsTwoByteRepresentation());
19036 // If the cons string has been short-circuited, skip the following checks.
19037 if (!string.is_identical_to(flat_string)) {
19038 // At this point, we should have a Cons string which is flat and ASCII,
19039 // with a first half that is a two-byte string (although it only contains
19040 // ASCII characters). This is a valid sequence of steps, and it can happen
19042 CHECK(string->IsOneByteRepresentation());
19043 i::ConsString* cons = i::ConsString::cast(*string);
19044 CHECK_EQ(0, cons->second()->length());
19045 CHECK(cons->first()->IsTwoByteRepresentation());
19048 // Check that some string operations work.
19051 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19052 CHECK_EQ(6, reresult->Int32Value());
19055 reresult = CompileRun("str2.match(/abe./g).length;");
19056 CHECK_EQ(6, reresult->Int32Value());
19058 reresult = CompileRun("str2.search(/bel/g);");
19059 CHECK_EQ(1, reresult->Int32Value());
19061 reresult = CompileRun("str2.search(/be./g);");
19062 CHECK_EQ(1, reresult->Int32Value());
19064 ExpectTrue("/bel/g.test(str2);");
19066 ExpectTrue("/be./g.test(str2);");
19068 reresult = CompileRun("/bel/g.exec(str2);");
19069 CHECK(!reresult->IsNull());
19071 reresult = CompileRun("/be./g.exec(str2);");
19072 CHECK(!reresult->IsNull());
19074 ExpectString("str2.substring(2, 10);", "elspenda");
19076 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19078 ExpectString("str2.charAt(2);", "e");
19080 ExpectObject("str2.indexOf('els');", indexof);
19082 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19084 reresult = CompileRun("str2.charCodeAt(2);");
19085 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19089 TEST(ContainsOnlyOneByte) {
19090 v8::V8::Initialize();
19091 v8::Isolate* isolate = CcTest::isolate();
19092 v8::HandleScope scope(isolate);
19093 // Make a buffer long enough that it won't automatically be converted.
19094 const int length = 512;
19095 // Ensure word aligned assignment.
19096 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19097 i::SmartArrayPointer<uintptr_t>
19098 aligned_contents(new uintptr_t[aligned_length]);
19099 uint16_t* string_contents =
19100 reinterpret_cast<uint16_t*>(aligned_contents.get());
19101 // Set to contain only one byte.
19102 for (int i = 0; i < length-1; i++) {
19103 string_contents[i] = 0x41;
19105 string_contents[length-1] = 0;
19107 Handle<String> string =
19108 String::NewExternal(isolate,
19109 new TestResource(string_contents, NULL, false));
19110 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19111 // Counter example.
19112 string = String::NewFromTwoByte(isolate, string_contents);
19113 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19114 // Test left right and balanced cons strings.
19115 Handle<String> base = String::NewFromUtf8(isolate, "a");
19116 Handle<String> left = base;
19117 Handle<String> right = base;
19118 for (int i = 0; i < 1000; i++) {
19119 left = String::Concat(base, left);
19120 right = String::Concat(right, base);
19122 Handle<String> balanced = String::Concat(left, base);
19123 balanced = String::Concat(balanced, right);
19124 Handle<String> cons_strings[] = {left, balanced, right};
19125 Handle<String> two_byte =
19126 String::NewExternal(isolate,
19127 new TestResource(string_contents, NULL, false));
19128 USE(two_byte); USE(cons_strings);
19129 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19130 // Base assumptions.
19131 string = cons_strings[i];
19132 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19133 // Test left and right concatentation.
19134 string = String::Concat(two_byte, cons_strings[i]);
19135 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19136 string = String::Concat(cons_strings[i], two_byte);
19137 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19139 // Set bits in different positions
19140 // for strings of different lengths and alignments.
19141 for (int alignment = 0; alignment < 7; alignment++) {
19142 for (int size = 2; alignment + size < length; size *= 2) {
19143 int zero_offset = size + alignment;
19144 string_contents[zero_offset] = 0;
19145 for (int i = 0; i < size; i++) {
19146 int shift = 8 + (i % 7);
19147 string_contents[alignment + i] = 1 << shift;
19148 string = String::NewExternal(
19150 new TestResource(string_contents + alignment, NULL, false));
19151 CHECK_EQ(size, string->Length());
19152 CHECK(!string->ContainsOnlyOneByte());
19153 string_contents[alignment + i] = 0x41;
19155 string_contents[zero_offset] = 0x41;
19161 // Failed access check callback that performs a GC on each invocation.
19162 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19163 v8::AccessType type,
19164 Local<v8::Value> data) {
19165 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19169 TEST(GCInFailedAccessCheckCallback) {
19170 // Install a failed access check callback that performs a GC on each
19171 // invocation. Then force the callback to be called from va
19173 v8::V8::Initialize();
19174 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19176 v8::Isolate* isolate = CcTest::isolate();
19177 v8::HandleScope scope(isolate);
19179 // Create an ObjectTemplate for global objects and install access
19180 // check callbacks that will block access.
19181 v8::Handle<v8::ObjectTemplate> global_template =
19182 v8::ObjectTemplate::New(isolate);
19183 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19184 IndexedGetAccessBlocker,
19185 v8::Handle<v8::Value>(),
19188 // Create a context and set an x property on it's global object.
19189 LocalContext context0(NULL, global_template);
19190 context0->Global()->Set(v8_str("x"), v8_num(42));
19191 v8::Handle<v8::Object> global0 = context0->Global();
19193 // Create a context with a different security token so that the
19194 // failed access check callback will be called on each access.
19195 LocalContext context1(NULL, global_template);
19196 context1->Global()->Set(v8_str("other"), global0);
19198 // Get property with failed access check.
19199 ExpectUndefined("other.x");
19201 // Get element with failed access check.
19202 ExpectUndefined("other[0]");
19204 // Set property with failed access check.
19205 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19206 CHECK(result->IsObject());
19208 // Set element with failed access check.
19209 result = CompileRun("other[0] = new Object()");
19210 CHECK(result->IsObject());
19212 // Get property attribute with failed access check.
19213 ExpectFalse("\'x\' in other");
19215 // Get property attribute for element with failed access check.
19216 ExpectFalse("0 in other");
19218 // Delete property.
19219 ExpectFalse("delete other.x");
19222 CHECK_EQ(false, global0->Delete(0));
19226 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19228 // Define JavaScript accessor.
19229 ExpectUndefined("Object.prototype.__defineGetter__.call("
19230 " other, \'x\', function() { return 42; })");
19233 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19236 // HasLocalElement.
19237 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19239 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19240 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19241 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19243 // Reset the failed access check callback so it does not influence
19244 // the other tests.
19245 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19249 TEST(IsolateNewDispose) {
19250 v8::Isolate* current_isolate = CcTest::isolate();
19251 v8::Isolate* isolate = v8::Isolate::New();
19252 CHECK(isolate != NULL);
19253 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19254 CHECK(current_isolate != isolate);
19255 CHECK(current_isolate == CcTest::isolate());
19257 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19258 last_location = last_message = NULL;
19259 isolate->Dispose();
19260 CHECK_EQ(last_location, NULL);
19261 CHECK_EQ(last_message, NULL);
19265 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19266 v8::Isolate* isolate = v8::Isolate::New();
19268 v8::Isolate::Scope i_scope(isolate);
19269 v8::HandleScope scope(isolate);
19270 LocalContext context(isolate);
19271 // Run something in this isolate.
19272 ExpectTrue("true");
19273 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19274 last_location = last_message = NULL;
19275 // Still entered, should fail.
19276 isolate->Dispose();
19277 CHECK_NE(last_location, NULL);
19278 CHECK_NE(last_message, NULL);
19280 isolate->Dispose();
19284 TEST(RunTwoIsolatesOnSingleThread) {
19286 v8::Isolate* isolate1 = v8::Isolate::New();
19288 v8::Persistent<v8::Context> context1;
19290 v8::HandleScope scope(isolate1);
19291 context1.Reset(isolate1, Context::New(isolate1));
19295 v8::HandleScope scope(isolate1);
19296 v8::Local<v8::Context> context =
19297 v8::Local<v8::Context>::New(isolate1, context1);
19298 v8::Context::Scope context_scope(context);
19299 // Run something in new isolate.
19300 CompileRun("var foo = 'isolate 1';");
19301 ExpectString("function f() { return foo; }; f()", "isolate 1");
19305 v8::Isolate* isolate2 = v8::Isolate::New();
19306 v8::Persistent<v8::Context> context2;
19309 v8::Isolate::Scope iscope(isolate2);
19310 v8::HandleScope scope(isolate2);
19311 context2.Reset(isolate2, Context::New(isolate2));
19312 v8::Local<v8::Context> context =
19313 v8::Local<v8::Context>::New(isolate2, context2);
19314 v8::Context::Scope context_scope(context);
19316 // Run something in new isolate.
19317 CompileRun("var foo = 'isolate 2';");
19318 ExpectString("function f() { return foo; }; f()", "isolate 2");
19322 v8::HandleScope scope(isolate1);
19323 v8::Local<v8::Context> context =
19324 v8::Local<v8::Context>::New(isolate1, context1);
19325 v8::Context::Scope context_scope(context);
19326 // Now again in isolate 1
19327 ExpectString("function f() { return foo; }; f()", "isolate 1");
19332 // Run some stuff in default isolate.
19333 v8::Persistent<v8::Context> context_default;
19335 v8::Isolate* isolate = CcTest::isolate();
19336 v8::Isolate::Scope iscope(isolate);
19337 v8::HandleScope scope(isolate);
19338 context_default.Reset(isolate, Context::New(isolate));
19342 v8::HandleScope scope(CcTest::isolate());
19343 v8::Local<v8::Context> context =
19344 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19345 v8::Context::Scope context_scope(context);
19346 // Variables in other isolates should be not available, verify there
19347 // is an exception.
19348 ExpectTrue("function f() {"
19356 "var isDefaultIsolate = true;"
19363 v8::Isolate::Scope iscope(isolate2);
19364 v8::HandleScope scope(isolate2);
19365 v8::Local<v8::Context> context =
19366 v8::Local<v8::Context>::New(isolate2, context2);
19367 v8::Context::Scope context_scope(context);
19368 ExpectString("function f() { return foo; }; f()", "isolate 2");
19372 v8::HandleScope scope(v8::Isolate::GetCurrent());
19373 v8::Local<v8::Context> context =
19374 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19375 v8::Context::Scope context_scope(context);
19376 ExpectString("function f() { return foo; }; f()", "isolate 1");
19380 v8::Isolate::Scope iscope(isolate2);
19387 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19388 last_location = last_message = NULL;
19390 isolate1->Dispose();
19391 CHECK_EQ(last_location, NULL);
19392 CHECK_EQ(last_message, NULL);
19394 isolate2->Dispose();
19395 CHECK_EQ(last_location, NULL);
19396 CHECK_EQ(last_message, NULL);
19398 // Check that default isolate still runs.
19400 v8::HandleScope scope(CcTest::isolate());
19401 v8::Local<v8::Context> context =
19402 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19403 v8::Context::Scope context_scope(context);
19404 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19409 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19410 v8::Isolate::Scope isolate_scope(isolate);
19411 v8::HandleScope scope(isolate);
19412 LocalContext context(isolate);
19413 i::ScopedVector<char> code(1024);
19414 i::OS::SNPrintF(code, "function fib(n) {"
19415 " if (n <= 2) return 1;"
19416 " return fib(n-1) + fib(n-2);"
19419 Local<Value> value = CompileRun(code.start());
19420 CHECK(value->IsNumber());
19421 return static_cast<int>(value->NumberValue());
19424 class IsolateThread : public v8::internal::Thread {
19426 IsolateThread(v8::Isolate* isolate, int fib_limit)
19427 : Thread("IsolateThread"),
19429 fib_limit_(fib_limit),
19433 result_ = CalcFibonacci(isolate_, fib_limit_);
19436 int result() { return result_; }
19439 v8::Isolate* isolate_;
19445 TEST(MultipleIsolatesOnIndividualThreads) {
19446 v8::Isolate* isolate1 = v8::Isolate::New();
19447 v8::Isolate* isolate2 = v8::Isolate::New();
19449 IsolateThread thread1(isolate1, 21);
19450 IsolateThread thread2(isolate2, 12);
19452 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19456 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19457 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19462 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19463 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19464 CHECK_EQ(result1, 10946);
19465 CHECK_EQ(result2, 144);
19466 CHECK_EQ(result1, thread1.result());
19467 CHECK_EQ(result2, thread2.result());
19469 isolate1->Dispose();
19470 isolate2->Dispose();
19474 TEST(IsolateDifferentContexts) {
19475 v8::Isolate* isolate = v8::Isolate::New();
19476 Local<v8::Context> context;
19478 v8::Isolate::Scope isolate_scope(isolate);
19479 v8::HandleScope handle_scope(isolate);
19480 context = v8::Context::New(isolate);
19481 v8::Context::Scope context_scope(context);
19482 Local<Value> v = CompileRun("2");
19483 CHECK(v->IsNumber());
19484 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19487 v8::Isolate::Scope isolate_scope(isolate);
19488 v8::HandleScope handle_scope(isolate);
19489 context = v8::Context::New(isolate);
19490 v8::Context::Scope context_scope(context);
19491 Local<Value> v = CompileRun("22");
19492 CHECK(v->IsNumber());
19493 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19495 isolate->Dispose();
19498 class InitDefaultIsolateThread : public v8::internal::Thread {
19501 SetResourceConstraints,
19503 SetCounterFunction,
19504 SetCreateHistogramFunction,
19505 SetAddHistogramSampleFunction
19508 explicit InitDefaultIsolateThread(TestCase testCase)
19509 : Thread("InitDefaultIsolateThread"),
19510 testCase_(testCase),
19514 v8::Isolate* isolate = v8::Isolate::New();
19516 switch (testCase_) {
19517 case SetResourceConstraints: {
19518 static const int K = 1024;
19519 v8::ResourceConstraints constraints;
19520 constraints.set_max_new_space_size(256 * K);
19521 constraints.set_max_old_space_size(4 * K * K);
19522 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19526 case SetFatalHandler:
19527 v8::V8::SetFatalErrorHandler(NULL);
19530 case SetCounterFunction:
19531 v8::V8::SetCounterFunction(NULL);
19534 case SetCreateHistogramFunction:
19535 v8::V8::SetCreateHistogramFunction(NULL);
19538 case SetAddHistogramSampleFunction:
19539 v8::V8::SetAddHistogramSampleFunction(NULL);
19543 isolate->Dispose();
19547 bool result() { return result_; }
19550 TestCase testCase_;
19555 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19556 InitDefaultIsolateThread thread(testCase);
19559 CHECK_EQ(thread.result(), true);
19563 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19564 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19568 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19569 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19573 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19574 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19578 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19579 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19583 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19584 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19588 TEST(StringCheckMultipleContexts) {
19590 "(function() { return \"a\".charAt(0); })()";
19593 // Run the code twice in the first context to initialize the call IC.
19594 LocalContext context1;
19595 v8::HandleScope scope(context1->GetIsolate());
19596 ExpectString(code, "a");
19597 ExpectString(code, "a");
19601 // Change the String.prototype in the second context and check
19602 // that the right function gets called.
19603 LocalContext context2;
19604 v8::HandleScope scope(context2->GetIsolate());
19605 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19606 ExpectString(code, "not a");
19611 TEST(NumberCheckMultipleContexts) {
19613 "(function() { return (42).toString(); })()";
19616 // Run the code twice in the first context to initialize the call IC.
19617 LocalContext context1;
19618 v8::HandleScope scope(context1->GetIsolate());
19619 ExpectString(code, "42");
19620 ExpectString(code, "42");
19624 // Change the Number.prototype in the second context and check
19625 // that the right function gets called.
19626 LocalContext context2;
19627 v8::HandleScope scope(context2->GetIsolate());
19628 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19629 ExpectString(code, "not 42");
19634 TEST(BooleanCheckMultipleContexts) {
19636 "(function() { return true.toString(); })()";
19639 // Run the code twice in the first context to initialize the call IC.
19640 LocalContext context1;
19641 v8::HandleScope scope(context1->GetIsolate());
19642 ExpectString(code, "true");
19643 ExpectString(code, "true");
19647 // Change the Boolean.prototype in the second context and check
19648 // that the right function gets called.
19649 LocalContext context2;
19650 v8::HandleScope scope(context2->GetIsolate());
19651 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19652 ExpectString(code, "");
19657 TEST(DontDeleteCellLoadIC) {
19658 const char* function_code =
19659 "function readCell() { while (true) { return cell; } }";
19662 // Run the code twice in the first context to initialize the load
19663 // IC for a don't delete cell.
19664 LocalContext context1;
19665 v8::HandleScope scope(context1->GetIsolate());
19666 CompileRun("var cell = \"first\";");
19667 ExpectBoolean("delete cell", false);
19668 CompileRun(function_code);
19669 ExpectString("readCell()", "first");
19670 ExpectString("readCell()", "first");
19674 // Use a deletable cell in the second context.
19675 LocalContext context2;
19676 v8::HandleScope scope(context2->GetIsolate());
19677 CompileRun("cell = \"second\";");
19678 CompileRun(function_code);
19679 ExpectString("readCell()", "second");
19680 ExpectBoolean("delete cell", true);
19681 ExpectString("(function() {"
19683 " return readCell();"
19685 " return e.toString();"
19688 "ReferenceError: cell is not defined");
19689 CompileRun("cell = \"new_second\";");
19690 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19691 ExpectString("readCell()", "new_second");
19692 ExpectString("readCell()", "new_second");
19697 TEST(DontDeleteCellLoadICForceDelete) {
19698 const char* function_code =
19699 "function readCell() { while (true) { return cell; } }";
19701 // Run the code twice to initialize the load IC for a don't delete
19703 LocalContext context;
19704 v8::HandleScope scope(context->GetIsolate());
19705 CompileRun("var cell = \"value\";");
19706 ExpectBoolean("delete cell", false);
19707 CompileRun(function_code);
19708 ExpectString("readCell()", "value");
19709 ExpectString("readCell()", "value");
19711 // Delete the cell using the API and check the inlined code works
19713 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19714 ExpectString("(function() {"
19716 " return readCell();"
19718 " return e.toString();"
19721 "ReferenceError: cell is not defined");
19725 TEST(DontDeleteCellLoadICAPI) {
19726 const char* function_code =
19727 "function readCell() { while (true) { return cell; } }";
19729 // Run the code twice to initialize the load IC for a don't delete
19730 // cell created using the API.
19731 LocalContext context;
19732 v8::HandleScope scope(context->GetIsolate());
19733 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19734 ExpectBoolean("delete cell", false);
19735 CompileRun(function_code);
19736 ExpectString("readCell()", "value");
19737 ExpectString("readCell()", "value");
19739 // Delete the cell using the API and check the inlined code works
19741 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19742 ExpectString("(function() {"
19744 " return readCell();"
19746 " return e.toString();"
19749 "ReferenceError: cell is not defined");
19753 class Visitor42 : public v8::PersistentHandleVisitor {
19755 explicit Visitor42(v8::Persistent<v8::Object>* object)
19756 : counter_(0), object_(object) { }
19758 virtual void VisitPersistentHandle(Persistent<Value>* value,
19759 uint16_t class_id) {
19760 if (class_id != 42) return;
19761 CHECK_EQ(42, value->WrapperClassId());
19762 v8::Isolate* isolate = CcTest::isolate();
19763 v8::HandleScope handle_scope(isolate);
19764 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19765 v8::Handle<v8::Value> object =
19766 v8::Local<v8::Object>::New(isolate, *object_);
19767 CHECK(handle->IsObject());
19768 CHECK_EQ(Handle<Object>::Cast(handle), object);
19773 v8::Persistent<v8::Object>* object_;
19777 TEST(PersistentHandleVisitor) {
19778 LocalContext context;
19779 v8::Isolate* isolate = context->GetIsolate();
19780 v8::HandleScope scope(isolate);
19781 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19782 CHECK_EQ(0, object.WrapperClassId());
19783 object.SetWrapperClassId(42);
19784 CHECK_EQ(42, object.WrapperClassId());
19786 Visitor42 visitor(&object);
19787 v8::V8::VisitHandlesWithClassIds(&visitor);
19788 CHECK_EQ(1, visitor.counter_);
19794 TEST(WrapperClassId) {
19795 LocalContext context;
19796 v8::Isolate* isolate = context->GetIsolate();
19797 v8::HandleScope scope(isolate);
19798 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19799 CHECK_EQ(0, object.WrapperClassId());
19800 object.SetWrapperClassId(65535);
19801 CHECK_EQ(65535, object.WrapperClassId());
19806 TEST(PersistentHandleInNewSpaceVisitor) {
19807 LocalContext context;
19808 v8::Isolate* isolate = context->GetIsolate();
19809 v8::HandleScope scope(isolate);
19810 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19811 CHECK_EQ(0, object1.WrapperClassId());
19812 object1.SetWrapperClassId(42);
19813 CHECK_EQ(42, object1.WrapperClassId());
19815 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19817 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19818 CHECK_EQ(0, object2.WrapperClassId());
19819 object2.SetWrapperClassId(42);
19820 CHECK_EQ(42, object2.WrapperClassId());
19822 Visitor42 visitor(&object2);
19823 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19824 CHECK_EQ(1, visitor.counter_);
19832 LocalContext context;
19833 v8::HandleScope scope(context->GetIsolate());
19835 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19836 CHECK(re->IsRegExp());
19837 CHECK(re->GetSource()->Equals(v8_str("foo")));
19838 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19840 re = v8::RegExp::New(v8_str("bar"),
19841 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19842 v8::RegExp::kGlobal));
19843 CHECK(re->IsRegExp());
19844 CHECK(re->GetSource()->Equals(v8_str("bar")));
19845 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19846 static_cast<int>(re->GetFlags()));
19848 re = v8::RegExp::New(v8_str("baz"),
19849 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19850 v8::RegExp::kMultiline));
19851 CHECK(re->IsRegExp());
19852 CHECK(re->GetSource()->Equals(v8_str("baz")));
19853 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19854 static_cast<int>(re->GetFlags()));
19856 re = CompileRun("/quux/").As<v8::RegExp>();
19857 CHECK(re->IsRegExp());
19858 CHECK(re->GetSource()->Equals(v8_str("quux")));
19859 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19861 re = CompileRun("/quux/gm").As<v8::RegExp>();
19862 CHECK(re->IsRegExp());
19863 CHECK(re->GetSource()->Equals(v8_str("quux")));
19864 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19865 static_cast<int>(re->GetFlags()));
19867 // Override the RegExp constructor and check the API constructor
19869 CompileRun("RegExp = function() {}");
19871 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19872 CHECK(re->IsRegExp());
19873 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19874 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19876 re = v8::RegExp::New(v8_str("foobarbaz"),
19877 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19878 v8::RegExp::kMultiline));
19879 CHECK(re->IsRegExp());
19880 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19881 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19882 static_cast<int>(re->GetFlags()));
19884 context->Global()->Set(v8_str("re"), re);
19885 ExpectTrue("re.test('FoobarbaZ')");
19887 // RegExps are objects on which you can set properties.
19888 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19889 v8::Handle<v8::Value> value(CompileRun("re.property"));
19890 CHECK_EQ(32, value->Int32Value());
19892 v8::TryCatch try_catch;
19893 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19894 CHECK(re.IsEmpty());
19895 CHECK(try_catch.HasCaught());
19896 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19897 ExpectTrue("ex instanceof SyntaxError");
19901 THREADED_TEST(Equals) {
19902 LocalContext localContext;
19903 v8::HandleScope handleScope(localContext->GetIsolate());
19905 v8::Handle<v8::Object> globalProxy = localContext->Global();
19906 v8::Handle<Value> global = globalProxy->GetPrototype();
19908 CHECK(global->StrictEquals(global));
19909 CHECK(!global->StrictEquals(globalProxy));
19910 CHECK(!globalProxy->StrictEquals(global));
19911 CHECK(globalProxy->StrictEquals(globalProxy));
19913 CHECK(global->Equals(global));
19914 CHECK(!global->Equals(globalProxy));
19915 CHECK(!globalProxy->Equals(global));
19916 CHECK(globalProxy->Equals(globalProxy));
19920 static void Getter(v8::Local<v8::String> property,
19921 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19922 info.GetReturnValue().Set(v8_str("42!"));
19926 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19927 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19928 result->Set(0, v8_str("universalAnswer"));
19929 info.GetReturnValue().Set(result);
19933 TEST(NamedEnumeratorAndForIn) {
19934 LocalContext context;
19935 v8::Isolate* isolate = context->GetIsolate();
19936 v8::HandleScope handle_scope(isolate);
19937 v8::Context::Scope context_scope(context.local());
19939 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19940 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19941 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19942 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19943 "var result = []; for (var k in o) result.push(k); result"));
19944 CHECK_EQ(1, result->Length());
19945 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19949 TEST(DefinePropertyPostDetach) {
19950 LocalContext context;
19951 v8::HandleScope scope(context->GetIsolate());
19952 v8::Handle<v8::Object> proxy = context->Global();
19953 v8::Handle<v8::Function> define_property =
19954 CompileRun("(function() {"
19955 " Object.defineProperty("
19958 " { configurable: true, enumerable: true, value: 3 });"
19959 "})").As<Function>();
19960 context->DetachGlobal();
19961 define_property->Call(proxy, 0, NULL);
19965 static void InstallContextId(v8::Handle<Context> context, int id) {
19966 Context::Scope scope(context);
19967 CompileRun("Object.prototype").As<Object>()->
19968 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19972 static void CheckContextId(v8::Handle<Object> object, int expected) {
19973 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19977 THREADED_TEST(CreationContext) {
19978 v8::Isolate* isolate = CcTest::isolate();
19979 HandleScope handle_scope(isolate);
19980 Handle<Context> context1 = Context::New(isolate);
19981 InstallContextId(context1, 1);
19982 Handle<Context> context2 = Context::New(isolate);
19983 InstallContextId(context2, 2);
19984 Handle<Context> context3 = Context::New(isolate);
19985 InstallContextId(context3, 3);
19987 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19989 Local<Object> object1;
19990 Local<Function> func1;
19992 Context::Scope scope(context1);
19993 object1 = Object::New(isolate);
19994 func1 = tmpl->GetFunction();
19997 Local<Object> object2;
19998 Local<Function> func2;
20000 Context::Scope scope(context2);
20001 object2 = Object::New(isolate);
20002 func2 = tmpl->GetFunction();
20005 Local<Object> instance1;
20006 Local<Object> instance2;
20009 Context::Scope scope(context3);
20010 instance1 = func1->NewInstance();
20011 instance2 = func2->NewInstance();
20014 CHECK(object1->CreationContext() == context1);
20015 CheckContextId(object1, 1);
20016 CHECK(func1->CreationContext() == context1);
20017 CheckContextId(func1, 1);
20018 CHECK(instance1->CreationContext() == context1);
20019 CheckContextId(instance1, 1);
20020 CHECK(object2->CreationContext() == context2);
20021 CheckContextId(object2, 2);
20022 CHECK(func2->CreationContext() == context2);
20023 CheckContextId(func2, 2);
20024 CHECK(instance2->CreationContext() == context2);
20025 CheckContextId(instance2, 2);
20028 Context::Scope scope(context1);
20029 CHECK(object1->CreationContext() == context1);
20030 CheckContextId(object1, 1);
20031 CHECK(func1->CreationContext() == context1);
20032 CheckContextId(func1, 1);
20033 CHECK(instance1->CreationContext() == context1);
20034 CheckContextId(instance1, 1);
20035 CHECK(object2->CreationContext() == context2);
20036 CheckContextId(object2, 2);
20037 CHECK(func2->CreationContext() == context2);
20038 CheckContextId(func2, 2);
20039 CHECK(instance2->CreationContext() == context2);
20040 CheckContextId(instance2, 2);
20044 Context::Scope scope(context2);
20045 CHECK(object1->CreationContext() == context1);
20046 CheckContextId(object1, 1);
20047 CHECK(func1->CreationContext() == context1);
20048 CheckContextId(func1, 1);
20049 CHECK(instance1->CreationContext() == context1);
20050 CheckContextId(instance1, 1);
20051 CHECK(object2->CreationContext() == context2);
20052 CheckContextId(object2, 2);
20053 CHECK(func2->CreationContext() == context2);
20054 CheckContextId(func2, 2);
20055 CHECK(instance2->CreationContext() == context2);
20056 CheckContextId(instance2, 2);
20061 THREADED_TEST(CreationContextOfJsFunction) {
20062 HandleScope handle_scope(CcTest::isolate());
20063 Handle<Context> context = Context::New(CcTest::isolate());
20064 InstallContextId(context, 1);
20066 Local<Object> function;
20068 Context::Scope scope(context);
20069 function = CompileRun("function foo() {}; foo").As<Object>();
20072 CHECK(function->CreationContext() == context);
20073 CheckContextId(function, 1);
20077 void HasOwnPropertyIndexedPropertyGetter(
20079 const v8::PropertyCallbackInfo<v8::Value>& info) {
20080 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20084 void HasOwnPropertyNamedPropertyGetter(
20085 Local<String> property,
20086 const v8::PropertyCallbackInfo<v8::Value>& info) {
20087 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20091 void HasOwnPropertyIndexedPropertyQuery(
20092 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20093 if (index == 42) info.GetReturnValue().Set(1);
20097 void HasOwnPropertyNamedPropertyQuery(
20098 Local<String> property,
20099 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20100 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20104 void HasOwnPropertyNamedPropertyQuery2(
20105 Local<String> property,
20106 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20107 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20111 void HasOwnPropertyAccessorGetter(
20112 Local<String> property,
20113 const v8::PropertyCallbackInfo<v8::Value>& info) {
20114 info.GetReturnValue().Set(v8_str("yes"));
20118 TEST(HasOwnProperty) {
20120 v8::Isolate* isolate = env->GetIsolate();
20121 v8::HandleScope scope(isolate);
20122 { // Check normal properties and defined getters.
20123 Handle<Value> value = CompileRun(
20126 " this.__defineGetter__('baz', function() { return 1; });"
20128 "function Bar() { "
20130 " this.__defineGetter__('bla', function() { return 2; });"
20132 "Bar.prototype = new Foo();"
20134 CHECK(value->IsObject());
20135 Handle<Object> object = value->ToObject();
20136 CHECK(object->Has(v8_str("foo")));
20137 CHECK(!object->HasOwnProperty(v8_str("foo")));
20138 CHECK(object->HasOwnProperty(v8_str("bar")));
20139 CHECK(object->Has(v8_str("baz")));
20140 CHECK(!object->HasOwnProperty(v8_str("baz")));
20141 CHECK(object->HasOwnProperty(v8_str("bla")));
20143 { // Check named getter interceptors.
20144 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20145 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20146 Handle<Object> instance = templ->NewInstance();
20147 CHECK(!instance->HasOwnProperty(v8_str("42")));
20148 CHECK(instance->HasOwnProperty(v8_str("foo")));
20149 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20151 { // Check indexed getter interceptors.
20152 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20153 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20154 Handle<Object> instance = templ->NewInstance();
20155 CHECK(instance->HasOwnProperty(v8_str("42")));
20156 CHECK(!instance->HasOwnProperty(v8_str("43")));
20157 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20159 { // Check named query interceptors.
20160 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20161 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20162 Handle<Object> instance = templ->NewInstance();
20163 CHECK(instance->HasOwnProperty(v8_str("foo")));
20164 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20166 { // Check indexed query interceptors.
20167 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20168 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20169 Handle<Object> instance = templ->NewInstance();
20170 CHECK(instance->HasOwnProperty(v8_str("42")));
20171 CHECK(!instance->HasOwnProperty(v8_str("41")));
20173 { // Check callbacks.
20174 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20175 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20176 Handle<Object> instance = templ->NewInstance();
20177 CHECK(instance->HasOwnProperty(v8_str("foo")));
20178 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20180 { // Check that query wins on disagreement.
20181 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20182 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20184 HasOwnPropertyNamedPropertyQuery2);
20185 Handle<Object> instance = templ->NewInstance();
20186 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20187 CHECK(instance->HasOwnProperty(v8_str("bar")));
20192 TEST(IndexedInterceptorWithStringProto) {
20193 v8::Isolate* isolate = CcTest::isolate();
20194 v8::HandleScope scope(isolate);
20195 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20196 templ->SetIndexedPropertyHandler(NULL,
20198 HasOwnPropertyIndexedPropertyQuery);
20199 LocalContext context;
20200 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20201 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20202 // These should be intercepted.
20203 CHECK(CompileRun("42 in obj")->BooleanValue());
20204 CHECK(CompileRun("'42' in obj")->BooleanValue());
20205 // These should fall through to the String prototype.
20206 CHECK(CompileRun("0 in obj")->BooleanValue());
20207 CHECK(CompileRun("'0' in obj")->BooleanValue());
20208 // And these should both fail.
20209 CHECK(!CompileRun("32 in obj")->BooleanValue());
20210 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20214 void CheckCodeGenerationAllowed() {
20215 Handle<Value> result = CompileRun("eval('42')");
20216 CHECK_EQ(42, result->Int32Value());
20217 result = CompileRun("(function(e) { return e('42'); })(eval)");
20218 CHECK_EQ(42, result->Int32Value());
20219 result = CompileRun("var f = new Function('return 42'); f()");
20220 CHECK_EQ(42, result->Int32Value());
20224 void CheckCodeGenerationDisallowed() {
20225 TryCatch try_catch;
20227 Handle<Value> result = CompileRun("eval('42')");
20228 CHECK(result.IsEmpty());
20229 CHECK(try_catch.HasCaught());
20232 result = CompileRun("(function(e) { return e('42'); })(eval)");
20233 CHECK(result.IsEmpty());
20234 CHECK(try_catch.HasCaught());
20237 result = CompileRun("var f = new Function('return 42'); f()");
20238 CHECK(result.IsEmpty());
20239 CHECK(try_catch.HasCaught());
20243 bool CodeGenerationAllowed(Local<Context> context) {
20244 ApiTestFuzzer::Fuzz();
20249 bool CodeGenerationDisallowed(Local<Context> context) {
20250 ApiTestFuzzer::Fuzz();
20255 THREADED_TEST(AllowCodeGenFromStrings) {
20256 LocalContext context;
20257 v8::HandleScope scope(context->GetIsolate());
20259 // eval and the Function constructor allowed by default.
20260 CHECK(context->IsCodeGenerationFromStringsAllowed());
20261 CheckCodeGenerationAllowed();
20263 // Disallow eval and the Function constructor.
20264 context->AllowCodeGenerationFromStrings(false);
20265 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20266 CheckCodeGenerationDisallowed();
20269 context->AllowCodeGenerationFromStrings(true);
20270 CheckCodeGenerationAllowed();
20272 // Disallow but setting a global callback that will allow the calls.
20273 context->AllowCodeGenerationFromStrings(false);
20274 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20275 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20276 CheckCodeGenerationAllowed();
20278 // Set a callback that disallows the code generation.
20279 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20280 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20281 CheckCodeGenerationDisallowed();
20285 TEST(SetErrorMessageForCodeGenFromStrings) {
20286 LocalContext context;
20287 v8::HandleScope scope(context->GetIsolate());
20288 TryCatch try_catch;
20290 Handle<String> message = v8_str("Message") ;
20291 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20292 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20293 context->AllowCodeGenerationFromStrings(false);
20294 context->SetErrorMessageForCodeGenerationFromStrings(message);
20295 Handle<Value> result = CompileRun("eval('42')");
20296 CHECK(result.IsEmpty());
20297 CHECK(try_catch.HasCaught());
20298 Handle<String> actual_message = try_catch.Message()->Get();
20299 CHECK(expected_message->Equals(actual_message));
20303 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20307 THREADED_TEST(CallAPIFunctionOnNonObject) {
20308 LocalContext context;
20309 v8::Isolate* isolate = context->GetIsolate();
20310 v8::HandleScope scope(isolate);
20311 Handle<FunctionTemplate> templ =
20312 v8::FunctionTemplate::New(isolate, NonObjectThis);
20313 Handle<Function> function = templ->GetFunction();
20314 context->Global()->Set(v8_str("f"), function);
20315 TryCatch try_catch;
20316 CompileRun("f.call(2)");
20320 // Regression test for issue 1470.
20321 THREADED_TEST(ReadOnlyIndexedProperties) {
20322 v8::Isolate* isolate = CcTest::isolate();
20323 v8::HandleScope scope(isolate);
20324 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20326 LocalContext context;
20327 Local<v8::Object> obj = templ->NewInstance();
20328 context->Global()->Set(v8_str("obj"), obj);
20329 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20330 obj->Set(v8_str("1"), v8_str("foobar"));
20331 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20332 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20333 obj->Set(v8_num(2), v8_str("foobar"));
20334 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20336 // Test non-smi case.
20337 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20338 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20339 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20343 THREADED_TEST(Regress1516) {
20344 LocalContext context;
20345 v8::HandleScope scope(context->GetIsolate());
20347 { v8::HandleScope temp_scope(context->GetIsolate());
20348 CompileRun("({'a': 0})");
20352 { i::MapCache* map_cache =
20353 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20354 elements = map_cache->NumberOfElements();
20355 CHECK_LE(1, elements);
20358 CcTest::heap()->CollectAllGarbage(
20359 i::Heap::kAbortIncrementalMarkingMask);
20360 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20361 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20362 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20363 CHECK_GT(elements, map_cache->NumberOfElements());
20369 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20371 v8::AccessType type,
20372 Local<Value> data) {
20373 // Only block read access to __proto__.
20374 if (type == v8::ACCESS_GET &&
20375 name->IsString() &&
20376 name->ToString()->Length() == 9 &&
20377 name->ToString()->Utf8Length() == 9) {
20379 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20380 return strncmp(buffer, "__proto__", 9) != 0;
20387 THREADED_TEST(Regress93759) {
20388 v8::Isolate* isolate = CcTest::isolate();
20389 HandleScope scope(isolate);
20391 // Template for object with security check.
20392 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20393 // We don't do indexing, so any callback can be used for that.
20394 no_proto_template->SetAccessCheckCallbacks(
20395 BlockProtoNamedSecurityTestCallback,
20396 IndexedSecurityTestCallback);
20398 // Templates for objects with hidden prototypes and possibly security check.
20399 Local<FunctionTemplate> hidden_proto_template =
20400 v8::FunctionTemplate::New(isolate);
20401 hidden_proto_template->SetHiddenPrototype(true);
20403 Local<FunctionTemplate> protected_hidden_proto_template =
20404 v8::FunctionTemplate::New(isolate);
20405 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20406 BlockProtoNamedSecurityTestCallback,
20407 IndexedSecurityTestCallback);
20408 protected_hidden_proto_template->SetHiddenPrototype(true);
20410 // Context for "foreign" objects used in test.
20411 Local<Context> context = v8::Context::New(isolate);
20414 // Plain object, no security check.
20415 Local<Object> simple_object = Object::New(isolate);
20417 // Object with explicit security check.
20418 Local<Object> protected_object =
20419 no_proto_template->NewInstance();
20421 // JSGlobalProxy object, always have security check.
20422 Local<Object> proxy_object =
20425 // Global object, the prototype of proxy_object. No security checks.
20426 Local<Object> global_object =
20427 proxy_object->GetPrototype()->ToObject();
20429 // Hidden prototype without security check.
20430 Local<Object> hidden_prototype =
20431 hidden_proto_template->GetFunction()->NewInstance();
20432 Local<Object> object_with_hidden =
20433 Object::New(isolate);
20434 object_with_hidden->SetPrototype(hidden_prototype);
20436 // Hidden prototype with security check on the hidden prototype.
20437 Local<Object> protected_hidden_prototype =
20438 protected_hidden_proto_template->GetFunction()->NewInstance();
20439 Local<Object> object_with_protected_hidden =
20440 Object::New(isolate);
20441 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20445 // Template for object for second context. Values to test are put on it as
20447 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20448 global_template->Set(v8_str("simple"), simple_object);
20449 global_template->Set(v8_str("protected"), protected_object);
20450 global_template->Set(v8_str("global"), global_object);
20451 global_template->Set(v8_str("proxy"), proxy_object);
20452 global_template->Set(v8_str("hidden"), object_with_hidden);
20453 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20455 LocalContext context2(NULL, global_template);
20457 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20458 CHECK(result1->Equals(simple_object->GetPrototype()));
20460 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20461 CHECK(result2->Equals(Undefined(isolate)));
20463 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20464 CHECK(result3->Equals(global_object->GetPrototype()));
20466 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20467 CHECK(result4->Equals(Undefined(isolate)));
20469 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20470 CHECK(result5->Equals(
20471 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20473 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20474 CHECK(result6->Equals(Undefined(isolate)));
20478 THREADED_TEST(Regress125988) {
20479 v8::HandleScope scope(CcTest::isolate());
20480 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20481 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20483 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20484 CompileRun("var a = new Object();"
20485 "var b = new Intercept();"
20486 "var c = new Object();"
20490 "for (var i = 0; i < 3; i++) c.x;");
20491 ExpectBoolean("c.hasOwnProperty('x')", false);
20492 ExpectInt32("c.x", 23);
20493 CompileRun("a.y = 42;"
20494 "for (var i = 0; i < 3; i++) c.x;");
20495 ExpectBoolean("c.hasOwnProperty('x')", false);
20496 ExpectInt32("c.x", 23);
20497 ExpectBoolean("c.hasOwnProperty('y')", false);
20498 ExpectInt32("c.y", 42);
20502 static void TestReceiver(Local<Value> expected_result,
20503 Local<Value> expected_receiver,
20504 const char* code) {
20505 Local<Value> result = CompileRun(code);
20506 CHECK(result->IsObject());
20507 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20508 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20512 THREADED_TEST(ForeignFunctionReceiver) {
20513 v8::Isolate* isolate = CcTest::isolate();
20514 HandleScope scope(isolate);
20516 // Create two contexts with different "id" properties ('i' and 'o').
20517 // Call a function both from its own context and from a the foreign
20518 // context, and see what "this" is bound to (returning both "this"
20519 // and "this.id" for comparison).
20521 Local<Context> foreign_context = v8::Context::New(isolate);
20522 foreign_context->Enter();
20523 Local<Value> foreign_function =
20524 CompileRun("function func() { return { 0: this.id, "
20526 " toString: function() { "
20533 CHECK(foreign_function->IsFunction());
20534 foreign_context->Exit();
20536 LocalContext context;
20538 Local<String> password = v8_str("Password");
20539 // Don't get hit by security checks when accessing foreign_context's
20540 // global receiver (aka. global proxy).
20541 context->SetSecurityToken(password);
20542 foreign_context->SetSecurityToken(password);
20544 Local<String> i = v8_str("i");
20545 Local<String> o = v8_str("o");
20546 Local<String> id = v8_str("id");
20548 CompileRun("function ownfunc() { return { 0: this.id, "
20550 " toString: function() { "
20557 context->Global()->Set(v8_str("func"), foreign_function);
20559 // Sanity check the contexts.
20560 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20561 CHECK(o->Equals(context->Global()->Get(id)));
20563 // Checking local function's receiver.
20564 // Calling function using its call/apply methods.
20565 TestReceiver(o, context->Global(), "ownfunc.call()");
20566 TestReceiver(o, context->Global(), "ownfunc.apply()");
20567 // Making calls through built-in functions.
20568 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20569 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20570 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20571 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20572 // Calling with environment record as base.
20573 TestReceiver(o, context->Global(), "ownfunc()");
20574 // Calling with no base.
20575 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20577 // Checking foreign function return value.
20578 // Calling function using its call/apply methods.
20579 TestReceiver(i, foreign_context->Global(), "func.call()");
20580 TestReceiver(i, foreign_context->Global(), "func.apply()");
20581 // Calling function using another context's call/apply methods.
20582 TestReceiver(i, foreign_context->Global(),
20583 "Function.prototype.call.call(func)");
20584 TestReceiver(i, foreign_context->Global(),
20585 "Function.prototype.call.apply(func)");
20586 TestReceiver(i, foreign_context->Global(),
20587 "Function.prototype.apply.call(func)");
20588 TestReceiver(i, foreign_context->Global(),
20589 "Function.prototype.apply.apply(func)");
20590 // Making calls through built-in functions.
20591 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20592 // ToString(func()) is func()[0], i.e., the returned this.id.
20593 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20594 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20595 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20597 // Calling with environment record as base.
20598 TestReceiver(i, foreign_context->Global(), "func()");
20599 // Calling with no base.
20600 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20604 uint8_t callback_fired = 0;
20607 void CallCompletedCallback1() {
20608 i::OS::Print("Firing callback 1.\n");
20609 callback_fired ^= 1; // Toggle first bit.
20613 void CallCompletedCallback2() {
20614 i::OS::Print("Firing callback 2.\n");
20615 callback_fired ^= 2; // Toggle second bit.
20619 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20620 int32_t level = args[0]->Int32Value();
20623 i::OS::Print("Entering recursion level %d.\n", level);
20625 i::Vector<char> script_vector(script, sizeof(script));
20626 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20627 CompileRun(script_vector.start());
20628 i::OS::Print("Leaving recursion level %d.\n", level);
20629 CHECK_EQ(0, callback_fired);
20631 i::OS::Print("Recursion ends.\n");
20632 CHECK_EQ(0, callback_fired);
20637 TEST(CallCompletedCallback) {
20639 v8::HandleScope scope(env->GetIsolate());
20640 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20641 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20642 env->Global()->Set(v8_str("recursion"),
20643 recursive_runtime->GetFunction());
20644 // Adding the same callback a second time has no effect.
20645 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20646 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20647 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20648 i::OS::Print("--- Script (1) ---\n");
20649 Local<Script> script = v8::Script::Compile(
20650 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20652 CHECK_EQ(3, callback_fired);
20654 i::OS::Print("\n--- Script (2) ---\n");
20655 callback_fired = 0;
20656 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20658 CHECK_EQ(2, callback_fired);
20660 i::OS::Print("\n--- Function ---\n");
20661 callback_fired = 0;
20662 Local<Function> recursive_function =
20663 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20664 v8::Handle<Value> args[] = { v8_num(0) };
20665 recursive_function->Call(env->Global(), 1, args);
20666 CHECK_EQ(2, callback_fired);
20670 void CallCompletedCallbackNoException() {
20671 v8::HandleScope scope(CcTest::isolate());
20672 CompileRun("1+1;");
20676 void CallCompletedCallbackException() {
20677 v8::HandleScope scope(CcTest::isolate());
20678 CompileRun("throw 'second exception';");
20682 TEST(CallCompletedCallbackOneException) {
20684 v8::HandleScope scope(env->GetIsolate());
20685 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20686 CompileRun("throw 'exception';");
20690 TEST(CallCompletedCallbackTwoExceptions) {
20692 v8::HandleScope scope(env->GetIsolate());
20693 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20694 CompileRun("throw 'first exception';");
20698 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20699 v8::HandleScope scope(info.GetIsolate());
20700 CompileRun("ext1Calls++;");
20704 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20705 v8::HandleScope scope(info.GetIsolate());
20706 CompileRun("ext2Calls++;");
20710 TEST(EnqueueMicrotask) {
20712 v8::HandleScope scope(env->GetIsolate());
20714 "var ext1Calls = 0;"
20715 "var ext2Calls = 0;");
20716 CompileRun("1+1;");
20717 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20718 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20720 env->GetIsolate()->EnqueueMicrotask(
20721 Function::New(env->GetIsolate(), MicrotaskOne));
20722 CompileRun("1+1;");
20723 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20724 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20726 env->GetIsolate()->EnqueueMicrotask(
20727 Function::New(env->GetIsolate(), MicrotaskOne));
20728 env->GetIsolate()->EnqueueMicrotask(
20729 Function::New(env->GetIsolate(), MicrotaskTwo));
20730 CompileRun("1+1;");
20731 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20732 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20734 env->GetIsolate()->EnqueueMicrotask(
20735 Function::New(env->GetIsolate(), MicrotaskTwo));
20736 CompileRun("1+1;");
20737 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20738 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20740 CompileRun("1+1;");
20741 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20742 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20746 TEST(SetAutorunMicrotasks) {
20748 v8::HandleScope scope(env->GetIsolate());
20750 "var ext1Calls = 0;"
20751 "var ext2Calls = 0;");
20752 CompileRun("1+1;");
20753 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20754 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20756 env->GetIsolate()->EnqueueMicrotask(
20757 Function::New(env->GetIsolate(), MicrotaskOne));
20758 CompileRun("1+1;");
20759 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20760 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20762 env->GetIsolate()->SetAutorunMicrotasks(false);
20763 env->GetIsolate()->EnqueueMicrotask(
20764 Function::New(env->GetIsolate(), MicrotaskOne));
20765 env->GetIsolate()->EnqueueMicrotask(
20766 Function::New(env->GetIsolate(), MicrotaskTwo));
20767 CompileRun("1+1;");
20768 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20769 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20771 env->GetIsolate()->RunMicrotasks();
20772 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20773 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20775 env->GetIsolate()->EnqueueMicrotask(
20776 Function::New(env->GetIsolate(), MicrotaskTwo));
20777 CompileRun("1+1;");
20778 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20779 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20781 env->GetIsolate()->RunMicrotasks();
20782 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20783 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20785 env->GetIsolate()->SetAutorunMicrotasks(true);
20786 env->GetIsolate()->EnqueueMicrotask(
20787 Function::New(env->GetIsolate(), MicrotaskTwo));
20788 CompileRun("1+1;");
20789 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20790 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20792 env->GetIsolate()->EnqueueMicrotask(
20793 Function::New(env->GetIsolate(), MicrotaskTwo));
20795 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20796 CompileRun("1+1;");
20797 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20801 CompileRun("1+1;");
20802 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20803 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20807 static int probes_counter = 0;
20808 static int misses_counter = 0;
20809 static int updates_counter = 0;
20812 static int* LookupCounter(const char* name) {
20813 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20814 return &probes_counter;
20815 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20816 return &misses_counter;
20817 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20818 return &updates_counter;
20824 static const char* kMegamorphicTestProgram =
20825 "function ClassA() { };"
20826 "function ClassB() { };"
20827 "ClassA.prototype.foo = function() { };"
20828 "ClassB.prototype.foo = function() { };"
20829 "function fooify(obj) { obj.foo(); };"
20830 "var a = new ClassA();"
20831 "var b = new ClassB();"
20832 "for (var i = 0; i < 10000; i++) {"
20838 static void StubCacheHelper(bool primary) {
20839 V8::SetCounterFunction(LookupCounter);
20840 USE(kMegamorphicTestProgram);
20842 i::FLAG_native_code_counters = true;
20844 i::FLAG_test_primary_stub_cache = true;
20846 i::FLAG_test_secondary_stub_cache = true;
20848 i::FLAG_crankshaft = false;
20850 v8::HandleScope scope(env->GetIsolate());
20851 int initial_probes = probes_counter;
20852 int initial_misses = misses_counter;
20853 int initial_updates = updates_counter;
20854 CompileRun(kMegamorphicTestProgram);
20855 int probes = probes_counter - initial_probes;
20856 int misses = misses_counter - initial_misses;
20857 int updates = updates_counter - initial_updates;
20858 CHECK_LT(updates, 10);
20859 CHECK_LT(misses, 10);
20860 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20861 // before megamorphism. The number of probes will only work once we teach the
20862 // serializer to embed references to counters in the stubs, given that the
20863 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20864 CHECK_GE(probes, 0);
20869 TEST(SecondaryStubCache) {
20870 StubCacheHelper(true);
20874 TEST(PrimaryStubCache) {
20875 StubCacheHelper(false);
20879 static int cow_arrays_created_runtime = 0;
20882 static int* LookupCounterCOWArrays(const char* name) {
20883 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20884 return &cow_arrays_created_runtime;
20890 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20891 V8::SetCounterFunction(LookupCounterCOWArrays);
20893 i::FLAG_native_code_counters = true;
20895 v8::HandleScope scope(env->GetIsolate());
20896 int initial_cow_arrays = cow_arrays_created_runtime;
20897 CompileRun("var o = [1, 2, 3];");
20898 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20899 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20900 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20901 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20902 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20907 TEST(StaticGetters) {
20908 LocalContext context;
20909 i::Factory* factory = CcTest::i_isolate()->factory();
20910 v8::Isolate* isolate = CcTest::isolate();
20911 v8::HandleScope scope(isolate);
20912 i::Handle<i::Object> undefined_value = factory->undefined_value();
20913 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20914 i::Handle<i::Object> null_value = factory->null_value();
20915 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20916 i::Handle<i::Object> true_value = factory->true_value();
20917 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20918 i::Handle<i::Object> false_value = factory->false_value();
20919 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20923 UNINITIALIZED_TEST(IsolateEmbedderData) {
20924 CcTest::DisableAutomaticDispose();
20925 v8::Isolate* isolate = v8::Isolate::New();
20927 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20928 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20929 CHECK_EQ(NULL, isolate->GetData(slot));
20930 CHECK_EQ(NULL, i_isolate->GetData(slot));
20932 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20933 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20934 isolate->SetData(slot, data);
20936 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20937 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20938 CHECK_EQ(data, isolate->GetData(slot));
20939 CHECK_EQ(data, i_isolate->GetData(slot));
20941 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20942 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20943 isolate->SetData(slot, data);
20945 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20946 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20947 CHECK_EQ(data, isolate->GetData(slot));
20948 CHECK_EQ(data, i_isolate->GetData(slot));
20951 isolate->Dispose();
20955 TEST(StringEmpty) {
20956 LocalContext context;
20957 i::Factory* factory = CcTest::i_isolate()->factory();
20958 v8::Isolate* isolate = CcTest::isolate();
20959 v8::HandleScope scope(isolate);
20960 i::Handle<i::Object> empty_string = factory->empty_string();
20961 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20965 static int instance_checked_getter_count = 0;
20966 static void InstanceCheckedGetter(
20967 Local<String> name,
20968 const v8::PropertyCallbackInfo<v8::Value>& info) {
20969 CHECK_EQ(name, v8_str("foo"));
20970 instance_checked_getter_count++;
20971 info.GetReturnValue().Set(v8_num(11));
20975 static int instance_checked_setter_count = 0;
20976 static void InstanceCheckedSetter(Local<String> name,
20977 Local<Value> value,
20978 const v8::PropertyCallbackInfo<void>& info) {
20979 CHECK_EQ(name, v8_str("foo"));
20980 CHECK_EQ(value, v8_num(23));
20981 instance_checked_setter_count++;
20985 static void CheckInstanceCheckedResult(int getters,
20987 bool expects_callbacks,
20988 TryCatch* try_catch) {
20989 if (expects_callbacks) {
20990 CHECK(!try_catch->HasCaught());
20991 CHECK_EQ(getters, instance_checked_getter_count);
20992 CHECK_EQ(setters, instance_checked_setter_count);
20994 CHECK(try_catch->HasCaught());
20995 CHECK_EQ(0, instance_checked_getter_count);
20996 CHECK_EQ(0, instance_checked_setter_count);
20998 try_catch->Reset();
21002 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21003 instance_checked_getter_count = 0;
21004 instance_checked_setter_count = 0;
21005 TryCatch try_catch;
21007 // Test path through generic runtime code.
21008 CompileRun("obj.foo");
21009 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21010 CompileRun("obj.foo = 23");
21011 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21013 // Test path through generated LoadIC and StoredIC.
21014 CompileRun("function test_get(o) { o.foo; }"
21016 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21017 CompileRun("test_get(obj);");
21018 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21019 CompileRun("test_get(obj);");
21020 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21021 CompileRun("function test_set(o) { o.foo = 23; }"
21023 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21024 CompileRun("test_set(obj);");
21025 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21026 CompileRun("test_set(obj);");
21027 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21029 // Test path through optimized code.
21030 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21032 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21033 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21035 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21037 // Cleanup so that closures start out fresh in next check.
21038 CompileRun("%DeoptimizeFunction(test_get);"
21039 "%ClearFunctionTypeFeedback(test_get);"
21040 "%DeoptimizeFunction(test_set);"
21041 "%ClearFunctionTypeFeedback(test_set);");
21045 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21046 v8::internal::FLAG_allow_natives_syntax = true;
21047 LocalContext context;
21048 v8::HandleScope scope(context->GetIsolate());
21050 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21051 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21052 inst->SetAccessor(v8_str("foo"),
21053 InstanceCheckedGetter, InstanceCheckedSetter,
21057 v8::AccessorSignature::New(context->GetIsolate(), templ));
21058 context->Global()->Set(v8_str("f"), templ->GetFunction());
21060 printf("Testing positive ...\n");
21061 CompileRun("var obj = new f();");
21062 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21063 CheckInstanceCheckedAccessors(true);
21065 printf("Testing negative ...\n");
21066 CompileRun("var obj = {};"
21067 "obj.__proto__ = new f();");
21068 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21069 CheckInstanceCheckedAccessors(false);
21073 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21074 v8::internal::FLAG_allow_natives_syntax = true;
21075 LocalContext context;
21076 v8::HandleScope scope(context->GetIsolate());
21078 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21079 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21080 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21081 inst->SetAccessor(v8_str("foo"),
21082 InstanceCheckedGetter, InstanceCheckedSetter,
21086 v8::AccessorSignature::New(context->GetIsolate(), templ));
21087 context->Global()->Set(v8_str("f"), templ->GetFunction());
21089 printf("Testing positive ...\n");
21090 CompileRun("var obj = new f();");
21091 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21092 CheckInstanceCheckedAccessors(true);
21094 printf("Testing negative ...\n");
21095 CompileRun("var obj = {};"
21096 "obj.__proto__ = new f();");
21097 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21098 CheckInstanceCheckedAccessors(false);
21102 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21103 v8::internal::FLAG_allow_natives_syntax = true;
21104 LocalContext context;
21105 v8::HandleScope scope(context->GetIsolate());
21107 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21108 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21109 proto->SetAccessor(v8_str("foo"),
21110 InstanceCheckedGetter, InstanceCheckedSetter,
21114 v8::AccessorSignature::New(context->GetIsolate(), templ));
21115 context->Global()->Set(v8_str("f"), templ->GetFunction());
21117 printf("Testing positive ...\n");
21118 CompileRun("var obj = new f();");
21119 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21120 CheckInstanceCheckedAccessors(true);
21122 printf("Testing negative ...\n");
21123 CompileRun("var obj = {};"
21124 "obj.__proto__ = new f();");
21125 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21126 CheckInstanceCheckedAccessors(false);
21128 printf("Testing positive with modified prototype chain ...\n");
21129 CompileRun("var obj = new f();"
21131 "pro.__proto__ = obj.__proto__;"
21132 "obj.__proto__ = pro;");
21133 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21134 CheckInstanceCheckedAccessors(true);
21138 TEST(TryFinallyMessage) {
21139 LocalContext context;
21140 v8::HandleScope scope(context->GetIsolate());
21142 // Test that the original error message is not lost if there is a
21143 // recursive call into Javascript is done in the finally block, e.g. to
21144 // initialize an IC. (crbug.com/129171)
21145 TryCatch try_catch;
21146 const char* trigger_ic =
21148 " throw new Error('test'); \n"
21151 " x++; \n" // Trigger an IC initialization here.
21153 CompileRun(trigger_ic);
21154 CHECK(try_catch.HasCaught());
21155 Local<Message> message = try_catch.Message();
21156 CHECK(!message.IsEmpty());
21157 CHECK_EQ(2, message->GetLineNumber());
21161 // Test that the original exception message is indeed overwritten if
21162 // a new error is thrown in the finally block.
21163 TryCatch try_catch;
21164 const char* throw_again =
21166 " throw new Error('test'); \n"
21170 " throw new Error('again'); \n" // This is the new uncaught error.
21172 CompileRun(throw_again);
21173 CHECK(try_catch.HasCaught());
21174 Local<Message> message = try_catch.Message();
21175 CHECK(!message.IsEmpty());
21176 CHECK_EQ(6, message->GetLineNumber());
21181 static void Helper137002(bool do_store,
21183 bool remove_accessor,
21184 bool interceptor) {
21185 LocalContext context;
21186 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21188 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21190 templ->SetAccessor(v8_str("foo"),
21191 GetterWhichReturns42,
21192 SetterWhichSetsYOnThisTo23);
21194 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21196 // Turn monomorphic on slow object with native accessor, then turn
21197 // polymorphic, finally optimize to create negative lookup and fail.
21198 CompileRun(do_store ?
21199 "function f(x) { x.foo = void 0; }" :
21200 "function f(x) { return x.foo; }");
21201 CompileRun("obj.y = void 0;");
21202 if (!interceptor) {
21203 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21205 CompileRun("obj.__proto__ = null;"
21206 "f(obj); f(obj); f(obj);");
21208 CompileRun("f({});");
21210 CompileRun("obj.y = void 0;"
21211 "%OptimizeFunctionOnNextCall(f);");
21212 if (remove_accessor) {
21213 CompileRun("delete obj.foo;");
21215 CompileRun("var result = f(obj);");
21217 CompileRun("result = obj.y;");
21219 if (remove_accessor && !interceptor) {
21220 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21222 CHECK_EQ(do_store ? 23 : 42,
21223 context->Global()->Get(v8_str("result"))->Int32Value());
21228 THREADED_TEST(Regress137002a) {
21229 i::FLAG_allow_natives_syntax = true;
21230 i::FLAG_compilation_cache = false;
21231 v8::HandleScope scope(CcTest::isolate());
21232 for (int i = 0; i < 16; i++) {
21233 Helper137002(i & 8, i & 4, i & 2, i & 1);
21238 THREADED_TEST(Regress137002b) {
21239 i::FLAG_allow_natives_syntax = true;
21240 LocalContext context;
21241 v8::Isolate* isolate = context->GetIsolate();
21242 v8::HandleScope scope(isolate);
21243 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21244 templ->SetAccessor(v8_str("foo"),
21245 GetterWhichReturns42,
21246 SetterWhichSetsYOnThisTo23);
21247 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21249 // Turn monomorphic on slow object with native accessor, then just
21250 // delete the property and fail.
21251 CompileRun("function load(x) { return x.foo; }"
21252 "function store(x) { x.foo = void 0; }"
21253 "function keyed_load(x, key) { return x[key]; }"
21254 // Second version of function has a different source (add void 0)
21255 // so that it does not share code with the first version. This
21256 // ensures that the ICs are monomorphic.
21257 "function load2(x) { void 0; return x.foo; }"
21258 "function store2(x) { void 0; x.foo = void 0; }"
21259 "function keyed_load2(x, key) { void 0; return x[key]; }"
21262 "obj.__proto__ = null;"
21264 "subobj.y = void 0;"
21265 "subobj.__proto__ = obj;"
21266 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21268 // Make the ICs monomorphic.
21269 "load(obj); load(obj);"
21270 "load2(subobj); load2(subobj);"
21271 "store(obj); store(obj);"
21272 "store2(subobj); store2(subobj);"
21273 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21274 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21276 // Actually test the shiny new ICs and better not crash. This
21277 // serves as a regression test for issue 142088 as well.
21282 "keyed_load(obj, 'foo');"
21283 "keyed_load2(subobj, 'foo');"
21285 // Delete the accessor. It better not be called any more now.
21288 "subobj.y = void 0;"
21290 "var load_result = load(obj);"
21291 "var load_result2 = load2(subobj);"
21292 "var keyed_load_result = keyed_load(obj, 'foo');"
21293 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21296 "var y_from_obj = obj.y;"
21297 "var y_from_subobj = subobj.y;");
21298 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21299 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21300 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21301 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21302 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21303 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21307 THREADED_TEST(Regress142088) {
21308 i::FLAG_allow_natives_syntax = true;
21309 LocalContext context;
21310 v8::Isolate* isolate = context->GetIsolate();
21311 v8::HandleScope scope(isolate);
21312 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21313 templ->SetAccessor(v8_str("foo"),
21314 GetterWhichReturns42,
21315 SetterWhichSetsYOnThisTo23);
21316 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21318 CompileRun("function load(x) { return x.foo; }"
21319 "var o = Object.create(obj);"
21320 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21321 "load(o); load(o); load(o); load(o);");
21325 THREADED_TEST(Regress137496) {
21326 i::FLAG_expose_gc = true;
21327 LocalContext context;
21328 v8::HandleScope scope(context->GetIsolate());
21330 // Compile a try-finally clause where the finally block causes a GC
21331 // while there still is a message pending for external reporting.
21332 TryCatch try_catch;
21333 try_catch.SetVerbose(true);
21334 CompileRun("try { throw new Error(); } finally { gc(); }");
21335 CHECK(try_catch.HasCaught());
21339 THREADED_TEST(Regress149912) {
21340 LocalContext context;
21341 v8::HandleScope scope(context->GetIsolate());
21342 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21343 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21344 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21345 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21349 THREADED_TEST(Regress157124) {
21350 LocalContext context;
21351 v8::Isolate* isolate = context->GetIsolate();
21352 v8::HandleScope scope(isolate);
21353 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21354 Local<Object> obj = templ->NewInstance();
21355 obj->GetIdentityHash();
21356 obj->DeleteHiddenValue(v8_str("Bug"));
21360 THREADED_TEST(Regress2535) {
21361 i::FLAG_harmony_collections = true;
21362 LocalContext context;
21363 v8::HandleScope scope(context->GetIsolate());
21364 Local<Value> set_value = CompileRun("new Set();");
21365 Local<Object> set_object(Local<Object>::Cast(set_value));
21366 CHECK_EQ(0, set_object->InternalFieldCount());
21367 Local<Value> map_value = CompileRun("new Map();");
21368 Local<Object> map_object(Local<Object>::Cast(map_value));
21369 CHECK_EQ(0, map_object->InternalFieldCount());
21373 THREADED_TEST(Regress2746) {
21374 LocalContext context;
21375 v8::Isolate* isolate = context->GetIsolate();
21376 v8::HandleScope scope(isolate);
21377 Local<Object> obj = Object::New(isolate);
21378 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21379 obj->SetHiddenValue(key, v8::Undefined(isolate));
21380 Local<Value> value = obj->GetHiddenValue(key);
21381 CHECK(!value.IsEmpty());
21382 CHECK(value->IsUndefined());
21386 THREADED_TEST(Regress260106) {
21387 LocalContext context;
21388 v8::Isolate* isolate = context->GetIsolate();
21389 v8::HandleScope scope(isolate);
21390 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21392 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21393 Local<Function> function = templ->GetFunction();
21394 CHECK(!function.IsEmpty());
21395 CHECK(function->IsFunction());
21399 THREADED_TEST(JSONParseObject) {
21400 LocalContext context;
21401 HandleScope scope(context->GetIsolate());
21402 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21403 Handle<Object> global = context->Global();
21404 global->Set(v8_str("obj"), obj);
21405 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21409 THREADED_TEST(JSONParseNumber) {
21410 LocalContext context;
21411 HandleScope scope(context->GetIsolate());
21412 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21413 Handle<Object> global = context->Global();
21414 global->Set(v8_str("obj"), obj);
21415 ExpectString("JSON.stringify(obj)", "42");
21420 class ThreadInterruptTest {
21422 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21423 ~ThreadInterruptTest() {}
21426 InterruptThread i_thread(this);
21430 CHECK_EQ(kExpectedValue, sem_value_);
21434 static const int kExpectedValue = 1;
21436 class InterruptThread : public i::Thread {
21438 explicit InterruptThread(ThreadInterruptTest* test)
21439 : Thread("InterruptThread"), test_(test) {}
21441 virtual void Run() {
21442 struct sigaction action;
21444 // Ensure that we'll enter waiting condition
21447 // Setup signal handler
21448 memset(&action, 0, sizeof(action));
21449 action.sa_handler = SignalHandler;
21450 sigaction(SIGCHLD, &action, NULL);
21453 kill(getpid(), SIGCHLD);
21455 // Ensure that if wait has returned because of error
21458 // Set value and signal semaphore
21459 test_->sem_value_ = 1;
21460 test_->sem_.Signal();
21463 static void SignalHandler(int signal) {
21467 ThreadInterruptTest* test_;
21471 volatile int sem_value_;
21475 THREADED_TEST(SemaphoreInterruption) {
21476 ThreadInterruptTest().RunTest();
21480 #endif // V8_OS_POSIX
21483 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21485 v8::AccessType type,
21486 Local<Value> data) {
21487 i::PrintF("Named access blocked.\n");
21492 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21494 v8::AccessType type,
21495 Local<Value> data) {
21496 i::PrintF("Indexed access blocked.\n");
21501 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21506 TEST(JSONStringifyAccessCheck) {
21507 v8::V8::Initialize();
21508 v8::Isolate* isolate = CcTest::isolate();
21509 v8::HandleScope scope(isolate);
21511 // Create an ObjectTemplate for global objects and install access
21512 // check callbacks that will block access.
21513 v8::Handle<v8::ObjectTemplate> global_template =
21514 v8::ObjectTemplate::New(isolate);
21515 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21516 IndexAccessAlwaysBlocked);
21518 // Create a context and set an x property on it's global object.
21519 LocalContext context0(NULL, global_template);
21520 v8::Handle<v8::Object> global0 = context0->Global();
21521 global0->Set(v8_str("x"), v8_num(42));
21522 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21524 for (int i = 0; i < 2; i++) {
21526 // Install a toJSON function on the second run.
21527 v8::Handle<v8::FunctionTemplate> toJSON =
21528 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21530 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21532 // Create a context with a different security token so that the
21533 // failed access check callback will be called on each access.
21534 LocalContext context1(NULL, global_template);
21535 context1->Global()->Set(v8_str("other"), global0);
21537 ExpectString("JSON.stringify(other)", "{}");
21538 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21539 "{\"a\":{},\"b\":[\"c\"]}");
21540 ExpectString("JSON.stringify([other, 'b', 'c'])",
21541 "[{},\"b\",\"c\"]");
21543 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21544 array->Set(0, v8_str("a"));
21545 array->Set(1, v8_str("b"));
21546 context1->Global()->Set(v8_str("array"), array);
21547 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21548 array->TurnOnAccessCheck();
21549 ExpectString("JSON.stringify(array)", "[]");
21550 ExpectString("JSON.stringify([array])", "[[]]");
21551 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21556 bool access_check_fail_thrown = false;
21557 bool catch_callback_called = false;
21560 // Failed access check callback that performs a GC on each invocation.
21561 void FailedAccessCheckThrows(Local<v8::Object> target,
21562 v8::AccessType type,
21563 Local<v8::Value> data) {
21564 access_check_fail_thrown = true;
21565 i::PrintF("Access check failed. Error thrown.\n");
21566 CcTest::isolate()->ThrowException(
21567 v8::Exception::Error(v8_str("cross context")));
21571 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21572 for (int i = 0; i < args.Length(); i++) {
21573 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21575 catch_callback_called = true;
21579 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21580 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21584 void CheckCorrectThrow(const char* script) {
21585 // Test that the script, when wrapped into a try-catch, triggers the catch
21586 // clause due to failed access check throwing an exception.
21587 // The subsequent try-catch should run without any exception.
21588 access_check_fail_thrown = false;
21589 catch_callback_called = false;
21590 i::ScopedVector<char> source(1024);
21591 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21592 CompileRun(source.start());
21593 CHECK(access_check_fail_thrown);
21594 CHECK(catch_callback_called);
21596 access_check_fail_thrown = false;
21597 catch_callback_called = false;
21598 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21599 CHECK(!access_check_fail_thrown);
21600 CHECK(!catch_callback_called);
21604 TEST(AccessCheckThrows) {
21605 i::FLAG_allow_natives_syntax = true;
21606 v8::V8::Initialize();
21607 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21608 v8::Isolate* isolate = CcTest::isolate();
21609 v8::HandleScope scope(isolate);
21611 // Create an ObjectTemplate for global objects and install access
21612 // check callbacks that will block access.
21613 v8::Handle<v8::ObjectTemplate> global_template =
21614 v8::ObjectTemplate::New(isolate);
21615 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21616 IndexAccessAlwaysBlocked);
21618 // Create a context and set an x property on it's global object.
21619 LocalContext context0(NULL, global_template);
21620 context0->Global()->Set(v8_str("x"), v8_num(42));
21621 v8::Handle<v8::Object> global0 = context0->Global();
21623 // Create a context with a different security token so that the
21624 // failed access check callback will be called on each access.
21625 LocalContext context1(NULL, global_template);
21626 context1->Global()->Set(v8_str("other"), global0);
21628 v8::Handle<v8::FunctionTemplate> catcher_fun =
21629 v8::FunctionTemplate::New(isolate, CatcherCallback);
21630 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21632 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21633 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21634 context1->Global()->Set(v8_str("has_own_property"),
21635 has_own_property_fun->GetFunction());
21637 { v8::TryCatch try_catch;
21638 access_check_fail_thrown = false;
21639 CompileRun("other.x;");
21640 CHECK(access_check_fail_thrown);
21641 CHECK(try_catch.HasCaught());
21644 CheckCorrectThrow("other.x");
21645 CheckCorrectThrow("other[1]");
21646 CheckCorrectThrow("JSON.stringify(other)");
21647 CheckCorrectThrow("has_own_property(other, 'x')");
21648 CheckCorrectThrow("%GetProperty(other, 'x')");
21649 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21650 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21651 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21652 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21653 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21654 CheckCorrectThrow("%HasProperty(other, 'x')");
21655 CheckCorrectThrow("%HasElement(other, 1)");
21656 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21657 CheckCorrectThrow("%GetPropertyNames(other)");
21658 // PROPERTY_ATTRIBUTES_NONE = 0
21659 CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21660 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21661 "other, 'x', null, null, 1)");
21663 // Reset the failed access check callback so it does not influence
21664 // the other tests.
21665 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21669 THREADED_TEST(Regress256330) {
21670 i::FLAG_allow_natives_syntax = true;
21671 LocalContext context;
21672 v8::HandleScope scope(context->GetIsolate());
21673 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21674 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21675 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21676 CompileRun("\"use strict\"; var o = new Bug;"
21677 "function f(o) { o.x = 10; };"
21678 "f(o); f(o); f(o);"
21679 "%OptimizeFunctionOnNextCall(f);"
21681 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21685 THREADED_TEST(CrankshaftInterceptorSetter) {
21686 i::FLAG_allow_natives_syntax = true;
21687 v8::HandleScope scope(CcTest::isolate());
21688 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21689 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21691 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21692 CompileRun("var obj = new Obj;"
21693 // Initialize fields to avoid transitions later.
21695 "obj.accessor_age = 42;"
21696 "function setter(i) { this.accessor_age = i; };"
21697 "function getter() { return this.accessor_age; };"
21698 "function setAge(i) { obj.age = i; };"
21699 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21703 "%OptimizeFunctionOnNextCall(setAge);"
21705 // All stores went through the interceptor.
21706 ExpectInt32("obj.interceptor_age", 4);
21707 ExpectInt32("obj.accessor_age", 42);
21711 THREADED_TEST(CrankshaftInterceptorGetter) {
21712 i::FLAG_allow_natives_syntax = true;
21713 v8::HandleScope scope(CcTest::isolate());
21714 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21715 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21717 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21718 CompileRun("var obj = new Obj;"
21719 // Initialize fields to avoid transitions later.
21721 "obj.accessor_age = 42;"
21722 "function getter() { return this.accessor_age; };"
21723 "function getAge() { return obj.interceptor_age; };"
21724 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21728 "%OptimizeFunctionOnNextCall(getAge);");
21729 // Access through interceptor.
21730 ExpectInt32("getAge()", 1);
21734 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21735 i::FLAG_allow_natives_syntax = true;
21736 v8::HandleScope scope(CcTest::isolate());
21737 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21738 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21740 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21741 CompileRun("var obj = new Obj;"
21742 "obj.__proto__.interceptor_age = 42;"
21744 "function getAge() { return obj.interceptor_age; };");
21745 ExpectInt32("getAge();", 100);
21746 ExpectInt32("getAge();", 100);
21747 ExpectInt32("getAge();", 100);
21748 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21749 // Access through interceptor.
21750 ExpectInt32("getAge();", 100);
21754 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21755 i::FLAG_allow_natives_syntax = true;
21756 v8::HandleScope scope(CcTest::isolate());
21757 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21758 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21760 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21761 CompileRun("var obj = new Obj;"
21762 "obj.age = 100000;"
21763 "function setAge(i) { obj.age = i };"
21767 "%OptimizeFunctionOnNextCall(setAge);"
21769 ExpectInt32("obj.age", 100000);
21770 ExpectInt32("obj.interceptor_age", 103);
21774 class RequestInterruptTestBase {
21776 RequestInterruptTestBase()
21778 isolate_(env_->GetIsolate()),
21781 should_continue_(true) {
21784 virtual ~RequestInterruptTestBase() { }
21786 virtual void TestBody() = 0;
21789 InterruptThread i_thread(this);
21792 v8::HandleScope handle_scope(isolate_);
21796 isolate_->ClearInterrupt();
21798 // Verify we arrived here because interruptor was called
21799 // not due to a bug causing us to exit the loop too early.
21800 CHECK(!should_continue());
21803 void WakeUpInterruptor() {
21807 bool should_continue() const { return should_continue_; }
21809 bool ShouldContinue() {
21811 if (--warmup_ == 0) {
21812 WakeUpInterruptor();
21816 return should_continue_;
21820 static void ShouldContinueCallback(
21821 const v8::FunctionCallbackInfo<Value>& info) {
21822 RequestInterruptTestBase* test =
21823 reinterpret_cast<RequestInterruptTestBase*>(
21824 info.Data().As<v8::External>()->Value());
21825 info.GetReturnValue().Set(test->ShouldContinue());
21828 class InterruptThread : public i::Thread {
21830 explicit InterruptThread(RequestInterruptTestBase* test)
21831 : Thread("RequestInterruptTest"), test_(test) {}
21833 virtual void Run() {
21834 test_->sem_.Wait();
21835 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21838 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21839 reinterpret_cast<RequestInterruptTestBase*>(data)->
21840 should_continue_ = false;
21844 RequestInterruptTestBase* test_;
21848 v8::Isolate* isolate_;
21851 bool should_continue_;
21855 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21857 virtual void TestBody() {
21858 Local<Function> func = Function::New(
21859 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21860 env_->Global()->Set(v8_str("ShouldContinue"), func);
21862 CompileRun("while (ShouldContinue()) { }");
21867 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21869 virtual void TestBody() {
21870 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21871 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21872 proto->Set(v8_str("shouldContinue"), Function::New(
21873 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21874 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21876 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21881 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21883 virtual void TestBody() {
21884 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21885 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21886 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21887 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21888 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21890 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21895 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21897 virtual void TestBody() {
21898 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21899 t->InstanceTemplate()->SetNativeDataProperty(
21900 v8_str("shouldContinue"),
21901 &ShouldContinueNativeGetter,
21903 v8::External::New(isolate_, this));
21904 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21906 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21910 static void ShouldContinueNativeGetter(
21911 Local<String> property,
21912 const v8::PropertyCallbackInfo<v8::Value>& info) {
21913 RequestInterruptTestBase* test =
21914 reinterpret_cast<RequestInterruptTestBase*>(
21915 info.Data().As<v8::External>()->Value());
21916 info.GetReturnValue().Set(test->ShouldContinue());
21921 class RequestInterruptTestWithMethodCallAndInterceptor
21922 : public RequestInterruptTestBase {
21924 virtual void TestBody() {
21925 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21926 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21927 proto->Set(v8_str("shouldContinue"), Function::New(
21928 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21929 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21930 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21932 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21934 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21938 static void EmptyInterceptor(
21939 Local<String> property,
21940 const v8::PropertyCallbackInfo<v8::Value>& info) {
21945 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21947 virtual void TestBody() {
21948 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21950 WakeUpInterruptorCallback,
21951 v8::External::New(isolate_, this)));
21953 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21955 ShouldContinueCallback,
21956 v8::External::New(isolate_, this)));
21958 i::FLAG_allow_natives_syntax = true;
21959 CompileRun("function loopish(o) {"
21961 " while (o.abs(1) > 0) {"
21962 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21964 " if (--pre === 0) WakeUpInterruptor(o === Math);"
21969 "var obj = {abs: function () { return i-- }, x: null};"
21972 "%OptimizeFunctionOnNextCall(loopish);"
21975 i::FLAG_allow_natives_syntax = false;
21979 static void WakeUpInterruptorCallback(
21980 const v8::FunctionCallbackInfo<Value>& info) {
21981 if (!info[0]->BooleanValue()) return;
21983 RequestInterruptTestBase* test =
21984 reinterpret_cast<RequestInterruptTestBase*>(
21985 info.Data().As<v8::External>()->Value());
21986 test->WakeUpInterruptor();
21989 static void ShouldContinueCallback(
21990 const v8::FunctionCallbackInfo<Value>& info) {
21991 RequestInterruptTestBase* test =
21992 reinterpret_cast<RequestInterruptTestBase*>(
21993 info.Data().As<v8::External>()->Value());
21994 info.GetReturnValue().Set(test->should_continue());
21999 TEST(RequestInterruptTestWithFunctionCall) {
22000 RequestInterruptTestWithFunctionCall().RunTest();
22004 TEST(RequestInterruptTestWithMethodCall) {
22005 RequestInterruptTestWithMethodCall().RunTest();
22009 TEST(RequestInterruptTestWithAccessor) {
22010 RequestInterruptTestWithAccessor().RunTest();
22014 TEST(RequestInterruptTestWithNativeAccessor) {
22015 RequestInterruptTestWithNativeAccessor().RunTest();
22019 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22020 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22024 TEST(RequestInterruptTestWithMathAbs) {
22025 RequestInterruptTestWithMathAbs().RunTest();
22029 static Local<Value> function_new_expected_env;
22030 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22031 CHECK_EQ(function_new_expected_env, info.Data());
22032 info.GetReturnValue().Set(17);
22036 THREADED_TEST(FunctionNew) {
22038 v8::Isolate* isolate = env->GetIsolate();
22039 v8::HandleScope scope(isolate);
22040 Local<Object> data = v8::Object::New(isolate);
22041 function_new_expected_env = data;
22042 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22043 env->Global()->Set(v8_str("func"), func);
22044 Local<Value> result = CompileRun("func();");
22045 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22046 // Verify function not cached
22047 int serial_number =
22048 i::Smi::cast(v8::Utils::OpenHandle(*func)
22049 ->shared()->get_api_func_data()->serial_number())->value();
22050 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22051 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22052 i::Handle<i::Object> elm =
22053 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22054 CHECK(elm->IsUndefined());
22055 // Verify that each Function::New creates a new function instance
22056 Local<Object> data2 = v8::Object::New(isolate);
22057 function_new_expected_env = data2;
22058 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22059 CHECK(!func2->IsNull());
22060 CHECK_NE(func, func2);
22061 env->Global()->Set(v8_str("func2"), func2);
22062 Local<Value> result2 = CompileRun("func2();");
22063 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22067 TEST(EscapeableHandleScope) {
22068 HandleScope outer_scope(CcTest::isolate());
22069 LocalContext context;
22070 const int runs = 10;
22071 Local<String> values[runs];
22072 for (int i = 0; i < runs; i++) {
22073 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22074 Local<String> value;
22075 if (i != 0) value = v8_str("escape value");
22076 values[i] = inner_scope.Escape(value);
22078 for (int i = 0; i < runs; i++) {
22079 Local<String> expected;
22081 CHECK_EQ(v8_str("escape value"), values[i]);
22083 CHECK(values[i].IsEmpty());
22089 static void SetterWhichExpectsThisAndHolderToDiffer(
22090 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22091 CHECK(info.Holder() != info.This());
22095 TEST(Regress239669) {
22096 LocalContext context;
22097 v8::Isolate* isolate = context->GetIsolate();
22098 v8::HandleScope scope(isolate);
22099 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22100 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22101 context->Global()->Set(v8_str("P"), templ->NewInstance());
22106 "C1.prototype = P;"
22107 "for (var i = 0; i < 4; i++ ) {"
22113 class ApiCallOptimizationChecker {
22115 static Local<Object> data;
22116 static Local<Object> receiver;
22117 static Local<Object> holder;
22118 static Local<Object> callee;
22121 static void OptimizationCallback(
22122 const v8::FunctionCallbackInfo<v8::Value>& info) {
22123 CHECK(callee == info.Callee());
22124 CHECK(data == info.Data());
22125 CHECK(receiver == info.This());
22126 if (info.Length() == 1) {
22127 CHECK_EQ(v8_num(1), info[0]);
22129 CHECK(holder == info.Holder());
22131 info.GetReturnValue().Set(v8_str("returned"));
22135 enum SignatureType {
22137 kSignatureOnReceiver,
22138 kSignatureOnPrototype
22142 SignatureType signature_types[] =
22143 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22144 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22145 SignatureType signature_type = signature_types[i];
22146 for (int j = 0; j < 2; j++) {
22147 bool global = j == 0;
22148 int key = signature_type +
22149 ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22150 Run(signature_type, global, key);
22155 void Run(SignatureType signature_type, bool global, int key) {
22156 v8::Isolate* isolate = CcTest::isolate();
22157 v8::HandleScope scope(isolate);
22158 // Build a template for signature checks.
22159 Local<v8::ObjectTemplate> signature_template;
22160 Local<v8::Signature> signature;
22162 Local<v8::FunctionTemplate> parent_template =
22163 FunctionTemplate::New(isolate);
22164 parent_template->SetHiddenPrototype(true);
22165 Local<v8::FunctionTemplate> function_template
22166 = FunctionTemplate::New(isolate);
22167 function_template->Inherit(parent_template);
22168 switch (signature_type) {
22171 case kSignatureOnReceiver:
22172 signature = v8::Signature::New(isolate, function_template);
22174 case kSignatureOnPrototype:
22175 signature = v8::Signature::New(isolate, parent_template);
22178 signature_template = function_template->InstanceTemplate();
22180 // Global object must pass checks.
22181 Local<v8::Context> context =
22182 v8::Context::New(isolate, NULL, signature_template);
22183 v8::Context::Scope context_scope(context);
22184 // Install regular object that can pass signature checks.
22185 Local<Object> function_receiver = signature_template->NewInstance();
22186 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22187 // Get the holder objects.
22188 Local<Object> inner_global =
22189 Local<Object>::Cast(context->Global()->GetPrototype());
22190 // Install functions on hidden prototype object if there is one.
22191 data = Object::New(isolate);
22192 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22193 isolate, OptimizationCallback, data, signature);
22194 Local<Function> function = function_template->GetFunction();
22195 Local<Object> global_holder = inner_global;
22196 Local<Object> function_holder = function_receiver;
22197 if (signature_type == kSignatureOnPrototype) {
22198 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22199 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22201 global_holder->Set(v8_str("g_f"), function);
22202 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22203 function_holder->Set(v8_str("f"), function);
22204 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22205 // Initialize expected values.
22209 receiver = context->Global();
22210 holder = inner_global;
22212 holder = function_receiver;
22213 // If not using a signature, add something else to the prototype chain
22214 // to test the case that holder != receiver
22215 if (signature_type == kNoSignature) {
22216 receiver = Local<Object>::Cast(CompileRun(
22217 "var receiver_subclass = {};\n"
22218 "receiver_subclass.__proto__ = function_receiver;\n"
22219 "receiver_subclass"));
22221 receiver = Local<Object>::Cast(CompileRun(
22222 "var receiver_subclass = function_receiver;\n"
22223 "receiver_subclass"));
22226 // With no signature, the holder is not set.
22227 if (signature_type == kNoSignature) holder = receiver;
22228 // build wrap_function
22229 i::ScopedVector<char> wrap_function(200);
22233 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22234 "function wrap_get_%d() { return this.g_acc; }\n"
22235 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22240 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22241 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22242 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22245 // build source string
22246 i::ScopedVector<char> source(1000);
22249 "%s\n" // wrap functions
22250 "function wrap_f() { return wrap_f_%d(); }\n"
22251 "function wrap_get() { return wrap_get_%d(); }\n"
22252 "function wrap_set() { return wrap_set_%d(); }\n"
22253 "check = function(returned) {\n"
22254 " if (returned !== 'returned') { throw returned; }\n"
22257 "check(wrap_f());\n"
22258 "check(wrap_f());\n"
22259 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22260 "check(wrap_f());\n"
22262 "check(wrap_get());\n"
22263 "check(wrap_get());\n"
22264 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22265 "check(wrap_get());\n"
22267 "check = function(returned) {\n"
22268 " if (returned !== 1) { throw returned; }\n"
22270 "check(wrap_set());\n"
22271 "check(wrap_set());\n"
22272 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22273 "check(wrap_set());\n",
22274 wrap_function.start(), key, key, key, key, key, key);
22275 v8::TryCatch try_catch;
22276 CompileRun(source.start());
22277 ASSERT(!try_catch.HasCaught());
22278 CHECK_EQ(9, count);
22283 Local<Object> ApiCallOptimizationChecker::data;
22284 Local<Object> ApiCallOptimizationChecker::receiver;
22285 Local<Object> ApiCallOptimizationChecker::holder;
22286 Local<Object> ApiCallOptimizationChecker::callee;
22287 int ApiCallOptimizationChecker::count = 0;
22290 TEST(TestFunctionCallOptimization) {
22291 i::FLAG_allow_natives_syntax = true;
22292 ApiCallOptimizationChecker checker;
22297 static const char* last_event_message;
22298 static int last_event_status;
22299 void StoringEventLoggerCallback(const char* message, int status) {
22300 last_event_message = message;
22301 last_event_status = status;
22305 TEST(EventLogging) {
22306 v8::Isolate* isolate = CcTest::isolate();
22307 isolate->SetEventLogger(StoringEventLoggerCallback);
22308 v8::internal::HistogramTimer* histogramTimer =
22309 new v8::internal::HistogramTimer(
22310 "V8.Test", 0, 10000, 50,
22311 reinterpret_cast<v8::internal::Isolate*>(isolate));
22312 histogramTimer->Start();
22313 CHECK_EQ("V8.Test", last_event_message);
22314 CHECK_EQ(0, last_event_status);
22315 histogramTimer->Stop();
22316 CHECK_EQ("V8.Test", last_event_message);
22317 CHECK_EQ(1, last_event_status);
22322 i::FLAG_harmony_promises = true;
22324 LocalContext context;
22325 v8::Isolate* isolate = context->GetIsolate();
22326 v8::HandleScope scope(isolate);
22327 Handle<Object> global = context->Global();
22330 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22331 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22332 Handle<v8::Promise> p = pr->GetPromise();
22333 Handle<v8::Promise> r = rr->GetPromise();
22335 // IsPromise predicate.
22336 CHECK(p->IsPromise());
22337 CHECK(r->IsPromise());
22338 Handle<Value> o = v8::Object::New(isolate);
22339 CHECK(!o->IsPromise());
22341 // Resolution and rejection.
22342 pr->Resolve(v8::Integer::New(isolate, 1));
22343 CHECK(p->IsPromise());
22344 rr->Reject(v8::Integer::New(isolate, 2));
22345 CHECK(r->IsPromise());
22347 // Chaining non-pending promises.
22351 "function f1(x) { x1 = x; return x+1 };\n"
22352 "function f2(x) { x2 = x; return x+1 };\n");
22353 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22354 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22357 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22358 isolate->RunMicrotasks();
22359 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22362 isolate->RunMicrotasks();
22363 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22366 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22367 isolate->RunMicrotasks();
22368 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22371 isolate->RunMicrotasks();
22372 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22374 // Chaining pending promises.
22375 CompileRun("x1 = x2 = 0;");
22376 pr = v8::Promise::Resolver::New(isolate);
22377 rr = v8::Promise::Resolver::New(isolate);
22379 pr->GetPromise()->Chain(f1);
22380 rr->GetPromise()->Catch(f2);
22381 isolate->RunMicrotasks();
22382 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22383 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22385 pr->Resolve(v8::Integer::New(isolate, 1));
22386 rr->Reject(v8::Integer::New(isolate, 2));
22387 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22388 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22390 isolate->RunMicrotasks();
22391 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22392 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22395 CompileRun("x1 = x2 = 0;");
22396 pr = v8::Promise::Resolver::New(isolate);
22397 pr->GetPromise()->Chain(f1)->Chain(f2);
22398 pr->Resolve(v8::Integer::New(isolate, 3));
22399 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22400 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22401 isolate->RunMicrotasks();
22402 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22403 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22405 CompileRun("x1 = x2 = 0;");
22406 rr = v8::Promise::Resolver::New(isolate);
22407 rr->GetPromise()->Catch(f1)->Chain(f2);
22408 rr->Reject(v8::Integer::New(isolate, 3));
22409 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22410 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22411 isolate->RunMicrotasks();
22412 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22413 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22417 TEST(DisallowJavascriptExecutionScope) {
22418 LocalContext context;
22419 v8::Isolate* isolate = context->GetIsolate();
22420 v8::HandleScope scope(isolate);
22421 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22422 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22427 TEST(AllowJavascriptExecutionScope) {
22428 LocalContext context;
22429 v8::Isolate* isolate = context->GetIsolate();
22430 v8::HandleScope scope(isolate);
22431 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22432 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22433 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22434 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22435 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22441 TEST(ThrowOnJavascriptExecution) {
22442 LocalContext context;
22443 v8::Isolate* isolate = context->GetIsolate();
22444 v8::HandleScope scope(isolate);
22445 v8::TryCatch try_catch;
22446 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22447 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22449 CHECK(try_catch.HasCaught());
22453 TEST(Regress354123) {
22454 LocalContext current;
22455 v8::Isolate* isolate = current->GetIsolate();
22456 v8::HandleScope scope(isolate);
22458 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22459 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22460 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22462 // Test access using __proto__ from the prototype chain.
22463 named_access_count = 0;
22464 CompileRun("friend.__proto__ = {};");
22465 CHECK_EQ(2, named_access_count);
22466 CompileRun("friend.__proto__;");
22467 CHECK_EQ(4, named_access_count);
22469 // Test access using __proto__ as a hijacked function (A).
22470 named_access_count = 0;
22471 CompileRun("var p = Object.prototype;"
22472 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22473 "f.call(friend, {});");
22474 CHECK_EQ(1, named_access_count);
22475 CompileRun("var p = Object.prototype;"
22476 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22477 "f.call(friend);");
22478 CHECK_EQ(2, named_access_count);
22480 // Test access using __proto__ as a hijacked function (B).
22481 named_access_count = 0;
22482 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22483 "f.call(friend, {});");
22484 CHECK_EQ(1, named_access_count);
22485 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22486 "f.call(friend);");
22487 CHECK_EQ(2, named_access_count);
22489 // Test access using Object.setPrototypeOf reflective method.
22490 named_access_count = 0;
22491 CompileRun("Object.setPrototypeOf(friend, {});");
22492 CHECK_EQ(1, named_access_count);
22493 CompileRun("Object.getPrototypeOf(friend);");
22494 CHECK_EQ(2, named_access_count);
22498 TEST(CaptureStackTraceForStackOverflow) {
22499 v8::internal::FLAG_stack_size = 150;
22500 LocalContext current;
22501 v8::Isolate* isolate = current->GetIsolate();
22502 v8::HandleScope scope(isolate);
22503 V8::SetCaptureStackTraceForUncaughtExceptions(
22504 true, 10, v8::StackTrace::kDetailed);
22505 v8::TryCatch try_catch;
22506 CompileRun("(function f(x) { f(x+1); })(0)");
22507 CHECK(try_catch.HasCaught());