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->StartCpuProfiling(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 = 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 = 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 = 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 = 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::DefaultPersistentValueMapTraits<K, V>::Impl Impl;
3502 static const bool kIsWeak = true;
3503 struct WeakCallbackDataType {
3507 static WeakCallbackDataType* WeakCallbackParameter(
3508 Impl* impl, const K& key, Local<V> value) {
3509 WeakCallbackDataType* data = new WeakCallbackDataType;
3514 static Impl* ImplFromWeakCallbackData(
3515 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3516 return data.GetParameter()->impl;
3518 static K KeyFromWeakCallbackData(
3519 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3520 return data.GetParameter()->key;
3522 static void DisposeCallbackData(WeakCallbackDataType* data) {
3525 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3526 Impl* impl, K key) { }
3530 template<typename Map>
3531 static void TestPersistentValueMap() {
3533 v8::Isolate* isolate = env->GetIsolate();
3535 v8::internal::GlobalHandles* global_handles =
3536 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3537 int initial_handle_count = global_handles->global_handles_count();
3538 CHECK_EQ(0, static_cast<int>(map.Size()));
3540 HandleScope scope(isolate);
3541 Local<v8::Object> obj = map.Get(7);
3542 CHECK(obj.IsEmpty());
3543 Local<v8::Object> expected = v8::Object::New(isolate);
3544 map.Set(7, expected);
3545 CHECK_EQ(1, static_cast<int>(map.Size()));
3547 CHECK_EQ(expected, obj);
3548 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3549 CHECK_EQ(0, static_cast<int>(map.Size()));
3550 CHECK(expected == removed);
3551 removed = map.Remove(7);
3552 CHECK(removed.IsEmpty());
3553 map.Set(8, expected);
3554 CHECK_EQ(1, static_cast<int>(map.Size()));
3555 map.Set(8, expected);
3556 CHECK_EQ(1, static_cast<int>(map.Size()));
3558 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3560 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3561 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3565 CHECK_EQ(0, static_cast<int>(map.Size()));
3566 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3570 TEST(PersistentValueMap) {
3571 // Default case, w/o weak callbacks:
3572 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3574 // Custom traits with weak callbacks:
3575 typedef v8::StdPersistentValueMap<int, v8::Object,
3576 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3577 TestPersistentValueMap<WeakPersistentValueMap>();
3581 THREADED_TEST(GlobalHandleUpcast) {
3582 v8::Isolate* isolate = CcTest::isolate();
3583 v8::HandleScope scope(isolate);
3584 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3585 v8::Persistent<String> global_string(isolate, local);
3586 v8::Persistent<Value>& global_value =
3587 v8::Persistent<Value>::Cast(global_string);
3588 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3589 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3590 global_string.Reset();
3594 THREADED_TEST(HandleEquality) {
3595 v8::Isolate* isolate = CcTest::isolate();
3596 v8::Persistent<String> global1;
3597 v8::Persistent<String> global2;
3599 v8::HandleScope scope(isolate);
3600 global1.Reset(isolate, v8_str("str"));
3601 global2.Reset(isolate, v8_str("str2"));
3603 CHECK_EQ(global1 == global1, true);
3604 CHECK_EQ(global1 != global1, false);
3606 v8::HandleScope scope(isolate);
3607 Local<String> local1 = Local<String>::New(isolate, global1);
3608 Local<String> local2 = Local<String>::New(isolate, global2);
3610 CHECK_EQ(global1 == local1, true);
3611 CHECK_EQ(global1 != local1, false);
3612 CHECK_EQ(local1 == global1, true);
3613 CHECK_EQ(local1 != global1, false);
3615 CHECK_EQ(global1 == local2, false);
3616 CHECK_EQ(global1 != local2, true);
3617 CHECK_EQ(local2 == global1, false);
3618 CHECK_EQ(local2 != global1, true);
3620 CHECK_EQ(local1 == local2, false);
3621 CHECK_EQ(local1 != local2, true);
3623 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3624 CHECK_EQ(local1 == anotherLocal1, true);
3625 CHECK_EQ(local1 != anotherLocal1, false);
3632 THREADED_TEST(LocalHandle) {
3633 v8::HandleScope scope(CcTest::isolate());
3634 v8::Local<String> local =
3635 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3636 CHECK_EQ(local->Length(), 3);
3640 class WeakCallCounter {
3642 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3643 int id() { return id_; }
3644 void increment() { number_of_weak_calls_++; }
3645 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3648 int number_of_weak_calls_;
3652 template<typename T>
3653 struct WeakCallCounterAndPersistent {
3654 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3655 : counter(counter) {}
3656 WeakCallCounter* counter;
3657 v8::Persistent<T> handle;
3661 template <typename T>
3662 static void WeakPointerCallback(
3663 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3664 CHECK_EQ(1234, data.GetParameter()->counter->id());
3665 data.GetParameter()->counter->increment();
3666 data.GetParameter()->handle.Reset();
3670 template<typename T>
3671 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3672 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3676 THREADED_TEST(ApiObjectGroups) {
3678 v8::Isolate* iso = env->GetIsolate();
3679 HandleScope scope(iso);
3681 WeakCallCounter counter(1234);
3683 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3684 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3685 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3686 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3687 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3688 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3691 HandleScope scope(iso);
3692 g1s1.handle.Reset(iso, Object::New(iso));
3693 g1s2.handle.Reset(iso, Object::New(iso));
3694 g1c1.handle.Reset(iso, Object::New(iso));
3695 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3696 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3697 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3699 g2s1.handle.Reset(iso, Object::New(iso));
3700 g2s2.handle.Reset(iso, Object::New(iso));
3701 g2c1.handle.Reset(iso, Object::New(iso));
3702 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3703 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3704 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3707 WeakCallCounterAndPersistent<Value> root(&counter);
3708 root.handle.Reset(iso, g1s1.handle); // make a root.
3710 // Connect group 1 and 2, make a cycle.
3712 HandleScope scope(iso);
3713 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3714 Set(0, Local<Value>::New(iso, g2s2.handle)));
3715 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3716 Set(0, Local<Value>::New(iso, g1s1.handle)));
3720 UniqueId id1 = MakeUniqueId(g1s1.handle);
3721 UniqueId id2 = MakeUniqueId(g2s2.handle);
3722 iso->SetObjectGroupId(g1s1.handle, id1);
3723 iso->SetObjectGroupId(g1s2.handle, id1);
3724 iso->SetReferenceFromGroup(id1, g1c1.handle);
3725 iso->SetObjectGroupId(g2s1.handle, id2);
3726 iso->SetObjectGroupId(g2s2.handle, id2);
3727 iso->SetReferenceFromGroup(id2, g2c1.handle);
3729 // Do a single full GC, ensure incremental marking is stopped.
3730 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3732 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3734 // All object should be alive.
3735 CHECK_EQ(0, counter.NumberOfWeakCalls());
3738 root.handle.SetWeak(&root, &WeakPointerCallback);
3739 // But make children strong roots---all the objects (except for children)
3740 // should be collectable now.
3741 g1c1.handle.ClearWeak();
3742 g2c1.handle.ClearWeak();
3744 // Groups are deleted, rebuild groups.
3746 UniqueId id1 = MakeUniqueId(g1s1.handle);
3747 UniqueId id2 = MakeUniqueId(g2s2.handle);
3748 iso->SetObjectGroupId(g1s1.handle, id1);
3749 iso->SetObjectGroupId(g1s2.handle, id1);
3750 iso->SetReferenceFromGroup(id1, g1c1.handle);
3751 iso->SetObjectGroupId(g2s1.handle, id2);
3752 iso->SetObjectGroupId(g2s2.handle, id2);
3753 iso->SetReferenceFromGroup(id2, g2c1.handle);
3756 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3758 // All objects should be gone. 5 global handles in total.
3759 CHECK_EQ(5, counter.NumberOfWeakCalls());
3761 // And now make children weak again and collect them.
3762 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3763 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3765 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3766 CHECK_EQ(7, counter.NumberOfWeakCalls());
3770 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3772 v8::Isolate* iso = env->GetIsolate();
3773 HandleScope scope(iso);
3775 WeakCallCounter counter(1234);
3777 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3778 WeakCallCounterAndPersistent<String> g1s2(&counter);
3779 WeakCallCounterAndPersistent<String> g1c1(&counter);
3780 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3781 WeakCallCounterAndPersistent<String> g2s2(&counter);
3782 WeakCallCounterAndPersistent<String> g2c1(&counter);
3785 HandleScope scope(iso);
3786 g1s1.handle.Reset(iso, Object::New(iso));
3787 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3788 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3789 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3790 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3791 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3793 g2s1.handle.Reset(iso, Object::New(iso));
3794 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3795 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3796 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3797 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3798 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3801 WeakCallCounterAndPersistent<Value> root(&counter);
3802 root.handle.Reset(iso, g1s1.handle); // make a root.
3804 // Connect group 1 and 2, make a cycle.
3806 HandleScope scope(iso);
3807 CHECK(Local<Object>::New(iso, g1s1.handle)
3808 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3809 CHECK(Local<Object>::New(iso, g2s1.handle)
3810 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3814 UniqueId id1 = MakeUniqueId(g1s1.handle);
3815 UniqueId id2 = MakeUniqueId(g2s2.handle);
3816 iso->SetObjectGroupId(g1s1.handle, id1);
3817 iso->SetObjectGroupId(g1s2.handle, id1);
3818 iso->SetReference(g1s1.handle, g1c1.handle);
3819 iso->SetObjectGroupId(g2s1.handle, id2);
3820 iso->SetObjectGroupId(g2s2.handle, id2);
3821 iso->SetReferenceFromGroup(id2, g2c1.handle);
3823 // Do a single full GC, ensure incremental marking is stopped.
3824 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3826 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3828 // All object should be alive.
3829 CHECK_EQ(0, counter.NumberOfWeakCalls());
3832 root.handle.SetWeak(&root, &WeakPointerCallback);
3833 // But make children strong roots---all the objects (except for children)
3834 // should be collectable now.
3835 g1c1.handle.ClearWeak();
3836 g2c1.handle.ClearWeak();
3838 // Groups are deleted, rebuild groups.
3840 UniqueId id1 = MakeUniqueId(g1s1.handle);
3841 UniqueId id2 = MakeUniqueId(g2s2.handle);
3842 iso->SetObjectGroupId(g1s1.handle, id1);
3843 iso->SetObjectGroupId(g1s2.handle, id1);
3844 iso->SetReference(g1s1.handle, g1c1.handle);
3845 iso->SetObjectGroupId(g2s1.handle, id2);
3846 iso->SetObjectGroupId(g2s2.handle, id2);
3847 iso->SetReferenceFromGroup(id2, g2c1.handle);
3850 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3852 // All objects should be gone. 5 global handles in total.
3853 CHECK_EQ(5, counter.NumberOfWeakCalls());
3855 // And now make children weak again and collect them.
3856 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3857 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3859 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3860 CHECK_EQ(7, counter.NumberOfWeakCalls());
3864 THREADED_TEST(ApiObjectGroupsCycle) {
3866 v8::Isolate* iso = env->GetIsolate();
3867 HandleScope scope(iso);
3869 WeakCallCounter counter(1234);
3871 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3872 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3873 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3874 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3875 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3876 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3877 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3878 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3881 HandleScope scope(iso);
3882 g1s1.handle.Reset(iso, Object::New(iso));
3883 g1s2.handle.Reset(iso, Object::New(iso));
3884 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3885 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3886 CHECK(g1s1.handle.IsWeak());
3887 CHECK(g1s2.handle.IsWeak());
3889 g2s1.handle.Reset(iso, Object::New(iso));
3890 g2s2.handle.Reset(iso, Object::New(iso));
3891 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3892 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3893 CHECK(g2s1.handle.IsWeak());
3894 CHECK(g2s2.handle.IsWeak());
3896 g3s1.handle.Reset(iso, Object::New(iso));
3897 g3s2.handle.Reset(iso, Object::New(iso));
3898 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3899 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3900 CHECK(g3s1.handle.IsWeak());
3901 CHECK(g3s2.handle.IsWeak());
3903 g4s1.handle.Reset(iso, Object::New(iso));
3904 g4s2.handle.Reset(iso, Object::New(iso));
3905 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3906 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3907 CHECK(g4s1.handle.IsWeak());
3908 CHECK(g4s2.handle.IsWeak());
3911 WeakCallCounterAndPersistent<Value> root(&counter);
3912 root.handle.Reset(iso, g1s1.handle); // make a root.
3914 // Connect groups. We're building the following cycle:
3915 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3918 UniqueId id1 = MakeUniqueId(g1s1.handle);
3919 UniqueId id2 = MakeUniqueId(g2s1.handle);
3920 UniqueId id3 = MakeUniqueId(g3s1.handle);
3921 UniqueId id4 = MakeUniqueId(g4s1.handle);
3922 iso->SetObjectGroupId(g1s1.handle, id1);
3923 iso->SetObjectGroupId(g1s2.handle, id1);
3924 iso->SetReferenceFromGroup(id1, g2s1.handle);
3925 iso->SetObjectGroupId(g2s1.handle, id2);
3926 iso->SetObjectGroupId(g2s2.handle, id2);
3927 iso->SetReferenceFromGroup(id2, g3s1.handle);
3928 iso->SetObjectGroupId(g3s1.handle, id3);
3929 iso->SetObjectGroupId(g3s2.handle, id3);
3930 iso->SetReferenceFromGroup(id3, g4s1.handle);
3931 iso->SetObjectGroupId(g4s1.handle, id4);
3932 iso->SetObjectGroupId(g4s2.handle, id4);
3933 iso->SetReferenceFromGroup(id4, g1s1.handle);
3935 // Do a single full GC
3936 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3938 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3940 // All object should be alive.
3941 CHECK_EQ(0, counter.NumberOfWeakCalls());
3944 root.handle.SetWeak(&root, &WeakPointerCallback);
3946 // Groups are deleted, rebuild groups.
3948 UniqueId id1 = MakeUniqueId(g1s1.handle);
3949 UniqueId id2 = MakeUniqueId(g2s1.handle);
3950 UniqueId id3 = MakeUniqueId(g3s1.handle);
3951 UniqueId id4 = MakeUniqueId(g4s1.handle);
3952 iso->SetObjectGroupId(g1s1.handle, id1);
3953 iso->SetObjectGroupId(g1s2.handle, id1);
3954 iso->SetReferenceFromGroup(id1, g2s1.handle);
3955 iso->SetObjectGroupId(g2s1.handle, id2);
3956 iso->SetObjectGroupId(g2s2.handle, id2);
3957 iso->SetReferenceFromGroup(id2, g3s1.handle);
3958 iso->SetObjectGroupId(g3s1.handle, id3);
3959 iso->SetObjectGroupId(g3s2.handle, id3);
3960 iso->SetReferenceFromGroup(id3, g4s1.handle);
3961 iso->SetObjectGroupId(g4s1.handle, id4);
3962 iso->SetObjectGroupId(g4s2.handle, id4);
3963 iso->SetReferenceFromGroup(id4, g1s1.handle);
3966 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3968 // All objects should be gone. 9 global handles in total.
3969 CHECK_EQ(9, counter.NumberOfWeakCalls());
3973 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3974 // on the buildbots, so was made non-threaded for the time being.
3975 TEST(ApiObjectGroupsCycleForScavenger) {
3976 i::FLAG_stress_compaction = false;
3977 i::FLAG_gc_global = false;
3979 v8::Isolate* iso = env->GetIsolate();
3980 HandleScope scope(iso);
3982 WeakCallCounter counter(1234);
3984 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3985 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3986 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3987 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3988 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3989 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3992 HandleScope scope(iso);
3993 g1s1.handle.Reset(iso, Object::New(iso));
3994 g1s2.handle.Reset(iso, Object::New(iso));
3995 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3996 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3998 g2s1.handle.Reset(iso, Object::New(iso));
3999 g2s2.handle.Reset(iso, Object::New(iso));
4000 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4001 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4003 g3s1.handle.Reset(iso, Object::New(iso));
4004 g3s2.handle.Reset(iso, Object::New(iso));
4005 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4006 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4010 WeakCallCounterAndPersistent<Value> root(&counter);
4011 root.handle.Reset(iso, g1s1.handle);
4012 root.handle.MarkPartiallyDependent();
4014 // Connect groups. We're building the following cycle:
4015 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4018 HandleScope handle_scope(iso);
4019 g1s1.handle.MarkPartiallyDependent();
4020 g1s2.handle.MarkPartiallyDependent();
4021 g2s1.handle.MarkPartiallyDependent();
4022 g2s2.handle.MarkPartiallyDependent();
4023 g3s1.handle.MarkPartiallyDependent();
4024 g3s2.handle.MarkPartiallyDependent();
4025 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4026 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4027 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4028 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4029 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4030 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4031 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4032 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4033 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4034 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4035 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4036 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4039 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4041 heap->CollectGarbage(i::NEW_SPACE);
4043 // All objects should be alive.
4044 CHECK_EQ(0, counter.NumberOfWeakCalls());
4047 root.handle.SetWeak(&root, &WeakPointerCallback);
4048 root.handle.MarkPartiallyDependent();
4050 // Groups are deleted, rebuild groups.
4052 HandleScope handle_scope(iso);
4053 g1s1.handle.MarkPartiallyDependent();
4054 g1s2.handle.MarkPartiallyDependent();
4055 g2s1.handle.MarkPartiallyDependent();
4056 g2s2.handle.MarkPartiallyDependent();
4057 g3s1.handle.MarkPartiallyDependent();
4058 g3s2.handle.MarkPartiallyDependent();
4059 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4060 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4061 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4062 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4063 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4064 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4065 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4066 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4067 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4068 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4069 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4070 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4073 heap->CollectGarbage(i::NEW_SPACE);
4075 // All objects should be gone. 7 global handles in total.
4076 CHECK_EQ(7, counter.NumberOfWeakCalls());
4080 THREADED_TEST(ScriptException) {
4082 v8::HandleScope scope(env->GetIsolate());
4083 Local<Script> script = v8_compile("throw 'panama!';");
4084 v8::TryCatch try_catch;
4085 Local<Value> result = script->Run();
4086 CHECK(result.IsEmpty());
4087 CHECK(try_catch.HasCaught());
4088 String::Utf8Value exception_value(try_catch.Exception());
4089 CHECK_EQ(*exception_value, "panama!");
4093 TEST(TryCatchCustomException) {
4095 v8::HandleScope scope(env->GetIsolate());
4096 v8::TryCatch try_catch;
4097 CompileRun("function CustomError() { this.a = 'b'; }"
4098 "(function f() { throw new CustomError(); })();");
4099 CHECK(try_catch.HasCaught());
4100 CHECK(try_catch.Exception()->ToObject()->
4101 Get(v8_str("a"))->Equals(v8_str("b")));
4105 bool message_received;
4108 static void check_message_0(v8::Handle<v8::Message> message,
4109 v8::Handle<Value> data) {
4110 CHECK_EQ(5.76, data->NumberValue());
4111 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4112 CHECK(!message->IsSharedCrossOrigin());
4113 message_received = true;
4117 THREADED_TEST(MessageHandler0) {
4118 message_received = false;
4119 v8::HandleScope scope(CcTest::isolate());
4120 CHECK(!message_received);
4121 LocalContext context;
4122 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4123 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4125 CHECK(message_received);
4126 // clear out the message listener
4127 v8::V8::RemoveMessageListeners(check_message_0);
4131 static void check_message_1(v8::Handle<v8::Message> message,
4132 v8::Handle<Value> data) {
4133 CHECK(data->IsNumber());
4134 CHECK_EQ(1337, data->Int32Value());
4135 CHECK(!message->IsSharedCrossOrigin());
4136 message_received = true;
4140 TEST(MessageHandler1) {
4141 message_received = false;
4142 v8::HandleScope scope(CcTest::isolate());
4143 CHECK(!message_received);
4144 v8::V8::AddMessageListener(check_message_1);
4145 LocalContext context;
4146 CompileRun("throw 1337;");
4147 CHECK(message_received);
4148 // clear out the message listener
4149 v8::V8::RemoveMessageListeners(check_message_1);
4153 static void check_message_2(v8::Handle<v8::Message> message,
4154 v8::Handle<Value> data) {
4155 LocalContext context;
4156 CHECK(data->IsObject());
4157 v8::Local<v8::Value> hidden_property =
4158 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4159 CHECK(v8_str("hidden value")->Equals(hidden_property));
4160 CHECK(!message->IsSharedCrossOrigin());
4161 message_received = true;
4165 TEST(MessageHandler2) {
4166 message_received = false;
4167 v8::HandleScope scope(CcTest::isolate());
4168 CHECK(!message_received);
4169 v8::V8::AddMessageListener(check_message_2);
4170 LocalContext context;
4171 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4172 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4173 v8_str("hidden value"));
4174 context->Global()->Set(v8_str("error"), error);
4175 CompileRun("throw error;");
4176 CHECK(message_received);
4177 // clear out the message listener
4178 v8::V8::RemoveMessageListeners(check_message_2);
4182 static void check_message_3(v8::Handle<v8::Message> message,
4183 v8::Handle<Value> data) {
4184 CHECK(message->IsSharedCrossOrigin());
4185 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4186 message_received = true;
4190 TEST(MessageHandler3) {
4191 message_received = false;
4192 v8::Isolate* isolate = CcTest::isolate();
4193 v8::HandleScope scope(isolate);
4194 CHECK(!message_received);
4195 v8::V8::AddMessageListener(check_message_3);
4196 LocalContext context;
4197 v8::ScriptOrigin origin =
4198 v8::ScriptOrigin(v8_str("6.75"),
4199 v8::Integer::New(isolate, 1),
4200 v8::Integer::New(isolate, 2),
4202 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4205 CHECK(message_received);
4206 // clear out the message listener
4207 v8::V8::RemoveMessageListeners(check_message_3);
4211 static void check_message_4(v8::Handle<v8::Message> message,
4212 v8::Handle<Value> data) {
4213 CHECK(!message->IsSharedCrossOrigin());
4214 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4215 message_received = true;
4219 TEST(MessageHandler4) {
4220 message_received = false;
4221 v8::Isolate* isolate = CcTest::isolate();
4222 v8::HandleScope scope(isolate);
4223 CHECK(!message_received);
4224 v8::V8::AddMessageListener(check_message_4);
4225 LocalContext context;
4226 v8::ScriptOrigin origin =
4227 v8::ScriptOrigin(v8_str("6.75"),
4228 v8::Integer::New(isolate, 1),
4229 v8::Integer::New(isolate, 2),
4230 v8::False(isolate));
4231 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4234 CHECK(message_received);
4235 // clear out the message listener
4236 v8::V8::RemoveMessageListeners(check_message_4);
4240 static void check_message_5a(v8::Handle<v8::Message> message,
4241 v8::Handle<Value> data) {
4242 CHECK(message->IsSharedCrossOrigin());
4243 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4244 message_received = true;
4248 static void check_message_5b(v8::Handle<v8::Message> message,
4249 v8::Handle<Value> data) {
4250 CHECK(!message->IsSharedCrossOrigin());
4251 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4252 message_received = true;
4256 TEST(MessageHandler5) {
4257 message_received = false;
4258 v8::Isolate* isolate = CcTest::isolate();
4259 v8::HandleScope scope(isolate);
4260 CHECK(!message_received);
4261 v8::V8::AddMessageListener(check_message_5a);
4262 LocalContext context;
4263 v8::ScriptOrigin origin =
4264 v8::ScriptOrigin(v8_str("6.75"),
4265 v8::Integer::New(isolate, 1),
4266 v8::Integer::New(isolate, 2),
4268 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4271 CHECK(message_received);
4272 // clear out the message listener
4273 v8::V8::RemoveMessageListeners(check_message_5a);
4275 message_received = false;
4276 v8::V8::AddMessageListener(check_message_5b);
4278 v8::ScriptOrigin(v8_str("6.75"),
4279 v8::Integer::New(isolate, 1),
4280 v8::Integer::New(isolate, 2),
4281 v8::False(isolate));
4282 script = Script::Compile(v8_str("throw 'error'"),
4285 CHECK(message_received);
4286 // clear out the message listener
4287 v8::V8::RemoveMessageListeners(check_message_5b);
4291 THREADED_TEST(GetSetProperty) {
4292 LocalContext context;
4293 v8::Isolate* isolate = context->GetIsolate();
4294 v8::HandleScope scope(isolate);
4295 context->Global()->Set(v8_str("foo"), v8_num(14));
4296 context->Global()->Set(v8_str("12"), v8_num(92));
4297 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4298 context->Global()->Set(v8_num(13), v8_num(56));
4299 Local<Value> foo = CompileRun("this.foo");
4300 CHECK_EQ(14, foo->Int32Value());
4301 Local<Value> twelve = CompileRun("this[12]");
4302 CHECK_EQ(92, twelve->Int32Value());
4303 Local<Value> sixteen = CompileRun("this[16]");
4304 CHECK_EQ(32, sixteen->Int32Value());
4305 Local<Value> thirteen = CompileRun("this[13]");
4306 CHECK_EQ(56, thirteen->Int32Value());
4308 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4309 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4310 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4312 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4313 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4314 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4316 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4317 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4318 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4322 THREADED_TEST(PropertyAttributes) {
4323 LocalContext context;
4324 v8::HandleScope scope(context->GetIsolate());
4326 Local<String> prop = v8_str("none");
4327 context->Global()->Set(prop, v8_num(7));
4328 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4330 prop = v8_str("read_only");
4331 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4332 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4333 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4334 CompileRun("read_only = 9");
4335 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4336 context->Global()->Set(prop, v8_num(10));
4337 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4339 prop = v8_str("dont_delete");
4340 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4341 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4342 CompileRun("delete dont_delete");
4343 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4344 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4346 prop = v8_str("dont_enum");
4347 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4348 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4350 prop = v8_str("absent");
4351 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4352 Local<Value> fake_prop = v8_num(1);
4353 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4356 Local<Value> exception =
4357 CompileRun("({ toString: function() { throw 'exception';} })");
4358 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4359 CHECK(try_catch.HasCaught());
4360 String::Utf8Value exception_value(try_catch.Exception());
4361 CHECK_EQ("exception", *exception_value);
4366 THREADED_TEST(Array) {
4367 LocalContext context;
4368 v8::HandleScope scope(context->GetIsolate());
4369 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4370 CHECK_EQ(0, array->Length());
4371 CHECK(array->Get(0)->IsUndefined());
4372 CHECK(!array->Has(0));
4373 CHECK(array->Get(100)->IsUndefined());
4374 CHECK(!array->Has(100));
4375 array->Set(2, v8_num(7));
4376 CHECK_EQ(3, array->Length());
4377 CHECK(!array->Has(0));
4378 CHECK(!array->Has(1));
4379 CHECK(array->Has(2));
4380 CHECK_EQ(7, array->Get(2)->Int32Value());
4381 Local<Value> obj = CompileRun("[1, 2, 3]");
4382 Local<v8::Array> arr = obj.As<v8::Array>();
4383 CHECK_EQ(3, arr->Length());
4384 CHECK_EQ(1, arr->Get(0)->Int32Value());
4385 CHECK_EQ(2, arr->Get(1)->Int32Value());
4386 CHECK_EQ(3, arr->Get(2)->Int32Value());
4387 array = v8::Array::New(context->GetIsolate(), 27);
4388 CHECK_EQ(27, array->Length());
4389 array = v8::Array::New(context->GetIsolate(), -27);
4390 CHECK_EQ(0, array->Length());
4394 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4395 v8::EscapableHandleScope scope(args.GetIsolate());
4396 ApiTestFuzzer::Fuzz();
4397 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4398 for (int i = 0; i < args.Length(); i++)
4399 result->Set(i, args[i]);
4400 args.GetReturnValue().Set(scope.Escape(result));
4404 THREADED_TEST(Vector) {
4405 v8::Isolate* isolate = CcTest::isolate();
4406 v8::HandleScope scope(isolate);
4407 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4408 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4409 LocalContext context(0, global);
4411 const char* fun = "f()";
4412 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4413 CHECK_EQ(0, a0->Length());
4415 const char* fun2 = "f(11)";
4416 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4417 CHECK_EQ(1, a1->Length());
4418 CHECK_EQ(11, a1->Get(0)->Int32Value());
4420 const char* fun3 = "f(12, 13)";
4421 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4422 CHECK_EQ(2, a2->Length());
4423 CHECK_EQ(12, a2->Get(0)->Int32Value());
4424 CHECK_EQ(13, a2->Get(1)->Int32Value());
4426 const char* fun4 = "f(14, 15, 16)";
4427 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4428 CHECK_EQ(3, a3->Length());
4429 CHECK_EQ(14, a3->Get(0)->Int32Value());
4430 CHECK_EQ(15, a3->Get(1)->Int32Value());
4431 CHECK_EQ(16, a3->Get(2)->Int32Value());
4433 const char* fun5 = "f(17, 18, 19, 20)";
4434 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4435 CHECK_EQ(4, a4->Length());
4436 CHECK_EQ(17, a4->Get(0)->Int32Value());
4437 CHECK_EQ(18, a4->Get(1)->Int32Value());
4438 CHECK_EQ(19, a4->Get(2)->Int32Value());
4439 CHECK_EQ(20, a4->Get(3)->Int32Value());
4443 THREADED_TEST(FunctionCall) {
4444 LocalContext context;
4445 v8::Isolate* isolate = context->GetIsolate();
4446 v8::HandleScope scope(isolate);
4450 " for (var i = 0; i < arguments.length; i++) {"
4451 " result.push(arguments[i]);"
4455 "function ReturnThisSloppy() {"
4458 "function ReturnThisStrict() {"
4462 Local<Function> Foo =
4463 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4464 Local<Function> ReturnThisSloppy =
4465 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4466 Local<Function> ReturnThisStrict =
4467 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4469 v8::Handle<Value>* args0 = NULL;
4470 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4471 CHECK_EQ(0, a0->Length());
4473 v8::Handle<Value> args1[] = { v8_num(1.1) };
4474 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4475 CHECK_EQ(1, a1->Length());
4476 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4478 v8::Handle<Value> args2[] = { v8_num(2.2),
4480 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4481 CHECK_EQ(2, a2->Length());
4482 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4483 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4485 v8::Handle<Value> args3[] = { v8_num(4.4),
4488 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4489 CHECK_EQ(3, a3->Length());
4490 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4491 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4492 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4494 v8::Handle<Value> args4[] = { v8_num(7.7),
4498 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4499 CHECK_EQ(4, a4->Length());
4500 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4501 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4502 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4503 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4505 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4506 CHECK(r1->StrictEquals(context->Global()));
4507 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4508 CHECK(r2->StrictEquals(context->Global()));
4509 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4510 CHECK(r3->IsNumberObject());
4511 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4512 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4513 CHECK(r4->IsStringObject());
4514 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4515 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4516 CHECK(r5->IsBooleanObject());
4517 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4519 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4520 CHECK(r6->IsUndefined());
4521 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4522 CHECK(r7->IsNull());
4523 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4524 CHECK(r8->StrictEquals(v8_num(42)));
4525 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4526 CHECK(r9->StrictEquals(v8_str("hello")));
4527 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4528 CHECK(r10->StrictEquals(v8::True(isolate)));
4532 THREADED_TEST(ConstructCall) {
4533 LocalContext context;
4534 v8::Isolate* isolate = context->GetIsolate();
4535 v8::HandleScope scope(isolate);
4539 " for (var i = 0; i < arguments.length; i++) {"
4540 " result.push(arguments[i]);"
4544 Local<Function> Foo =
4545 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4547 v8::Handle<Value>* args0 = NULL;
4548 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4549 CHECK_EQ(0, a0->Length());
4551 v8::Handle<Value> args1[] = { v8_num(1.1) };
4552 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4553 CHECK_EQ(1, a1->Length());
4554 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4556 v8::Handle<Value> args2[] = { v8_num(2.2),
4558 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4559 CHECK_EQ(2, a2->Length());
4560 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4561 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4563 v8::Handle<Value> args3[] = { v8_num(4.4),
4566 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4567 CHECK_EQ(3, a3->Length());
4568 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4569 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4570 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4572 v8::Handle<Value> args4[] = { v8_num(7.7),
4576 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4577 CHECK_EQ(4, a4->Length());
4578 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4579 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4580 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4581 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4585 static void CheckUncle(v8::TryCatch* try_catch) {
4586 CHECK(try_catch->HasCaught());
4587 String::Utf8Value str_value(try_catch->Exception());
4588 CHECK_EQ(*str_value, "uncle?");
4593 THREADED_TEST(ConversionNumber) {
4595 v8::HandleScope scope(env->GetIsolate());
4596 // Very large number.
4597 CompileRun("var obj = Math.pow(2,32) * 1237;");
4598 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4599 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4600 CHECK_EQ(0, obj->ToInt32()->Value());
4601 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4603 CompileRun("var obj = -1234567890123;");
4604 obj = env->Global()->Get(v8_str("obj"));
4605 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4606 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4607 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4608 // Small positive integer.
4609 CompileRun("var obj = 42;");
4610 obj = env->Global()->Get(v8_str("obj"));
4611 CHECK_EQ(42.0, obj->ToNumber()->Value());
4612 CHECK_EQ(42, obj->ToInt32()->Value());
4613 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4614 // Negative integer.
4615 CompileRun("var obj = -37;");
4616 obj = env->Global()->Get(v8_str("obj"));
4617 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4618 CHECK_EQ(-37, obj->ToInt32()->Value());
4619 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4620 // Positive non-int32 integer.
4621 CompileRun("var obj = 0x81234567;");
4622 obj = env->Global()->Get(v8_str("obj"));
4623 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4624 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4625 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4627 CompileRun("var obj = 42.3;");
4628 obj = env->Global()->Get(v8_str("obj"));
4629 CHECK_EQ(42.3, obj->ToNumber()->Value());
4630 CHECK_EQ(42, obj->ToInt32()->Value());
4631 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4632 // Large negative fraction.
4633 CompileRun("var obj = -5726623061.75;");
4634 obj = env->Global()->Get(v8_str("obj"));
4635 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4636 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4637 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4641 THREADED_TEST(isNumberType) {
4643 v8::HandleScope scope(env->GetIsolate());
4644 // Very large number.
4645 CompileRun("var obj = Math.pow(2,32) * 1237;");
4646 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4647 CHECK(!obj->IsInt32());
4648 CHECK(!obj->IsUint32());
4649 // Large negative number.
4650 CompileRun("var obj = -1234567890123;");
4651 obj = env->Global()->Get(v8_str("obj"));
4652 CHECK(!obj->IsInt32());
4653 CHECK(!obj->IsUint32());
4654 // Small positive integer.
4655 CompileRun("var obj = 42;");
4656 obj = env->Global()->Get(v8_str("obj"));
4657 CHECK(obj->IsInt32());
4658 CHECK(obj->IsUint32());
4659 // Negative integer.
4660 CompileRun("var obj = -37;");
4661 obj = env->Global()->Get(v8_str("obj"));
4662 CHECK(obj->IsInt32());
4663 CHECK(!obj->IsUint32());
4664 // Positive non-int32 integer.
4665 CompileRun("var obj = 0x81234567;");
4666 obj = env->Global()->Get(v8_str("obj"));
4667 CHECK(!obj->IsInt32());
4668 CHECK(obj->IsUint32());
4670 CompileRun("var obj = 42.3;");
4671 obj = env->Global()->Get(v8_str("obj"));
4672 CHECK(!obj->IsInt32());
4673 CHECK(!obj->IsUint32());
4674 // Large negative fraction.
4675 CompileRun("var obj = -5726623061.75;");
4676 obj = env->Global()->Get(v8_str("obj"));
4677 CHECK(!obj->IsInt32());
4678 CHECK(!obj->IsUint32());
4680 CompileRun("var obj = 0.0;");
4681 obj = env->Global()->Get(v8_str("obj"));
4682 CHECK(obj->IsInt32());
4683 CHECK(obj->IsUint32());
4685 CompileRun("var obj = -0.0;");
4686 obj = env->Global()->Get(v8_str("obj"));
4687 CHECK(!obj->IsInt32());
4688 CHECK(!obj->IsUint32());
4692 THREADED_TEST(ConversionException) {
4694 v8::Isolate* isolate = env->GetIsolate();
4695 v8::HandleScope scope(isolate);
4697 "function TestClass() { };"
4698 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4699 "var obj = new TestClass();");
4700 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4702 v8::TryCatch try_catch;
4704 Local<Value> to_string_result = obj->ToString();
4705 CHECK(to_string_result.IsEmpty());
4706 CheckUncle(&try_catch);
4708 Local<Value> to_number_result = obj->ToNumber();
4709 CHECK(to_number_result.IsEmpty());
4710 CheckUncle(&try_catch);
4712 Local<Value> to_integer_result = obj->ToInteger();
4713 CHECK(to_integer_result.IsEmpty());
4714 CheckUncle(&try_catch);
4716 Local<Value> to_uint32_result = obj->ToUint32();
4717 CHECK(to_uint32_result.IsEmpty());
4718 CheckUncle(&try_catch);
4720 Local<Value> to_int32_result = obj->ToInt32();
4721 CHECK(to_int32_result.IsEmpty());
4722 CheckUncle(&try_catch);
4724 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4725 CHECK(to_object_result.IsEmpty());
4726 CHECK(try_catch.HasCaught());
4729 int32_t int32_value = obj->Int32Value();
4730 CHECK_EQ(0, int32_value);
4731 CheckUncle(&try_catch);
4733 uint32_t uint32_value = obj->Uint32Value();
4734 CHECK_EQ(0, uint32_value);
4735 CheckUncle(&try_catch);
4737 double number_value = obj->NumberValue();
4738 CHECK_NE(0, std::isnan(number_value));
4739 CheckUncle(&try_catch);
4741 int64_t integer_value = obj->IntegerValue();
4742 CHECK_EQ(0.0, static_cast<double>(integer_value));
4743 CheckUncle(&try_catch);
4747 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4748 ApiTestFuzzer::Fuzz();
4749 args.GetIsolate()->ThrowException(v8_str("konto"));
4753 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4754 if (args.Length() < 1) {
4755 args.GetReturnValue().Set(false);
4758 v8::HandleScope scope(args.GetIsolate());
4759 v8::TryCatch try_catch;
4760 Local<Value> result = CompileRun(args[0]->ToString());
4761 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4762 args.GetReturnValue().Set(try_catch.HasCaught());
4766 THREADED_TEST(APICatch) {
4767 v8::Isolate* isolate = CcTest::isolate();
4768 v8::HandleScope scope(isolate);
4769 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4770 templ->Set(v8_str("ThrowFromC"),
4771 v8::FunctionTemplate::New(isolate, ThrowFromC));
4772 LocalContext context(0, templ);
4774 "var thrown = false;"
4780 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4781 CHECK(thrown->BooleanValue());
4785 THREADED_TEST(APIThrowTryCatch) {
4786 v8::Isolate* isolate = CcTest::isolate();
4787 v8::HandleScope scope(isolate);
4788 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4789 templ->Set(v8_str("ThrowFromC"),
4790 v8::FunctionTemplate::New(isolate, ThrowFromC));
4791 LocalContext context(0, templ);
4792 v8::TryCatch try_catch;
4793 CompileRun("ThrowFromC();");
4794 CHECK(try_catch.HasCaught());
4798 // Test that a try-finally block doesn't shadow a try-catch block
4799 // when setting up an external handler.
4801 // BUG(271): Some of the exception propagation does not work on the
4802 // ARM simulator because the simulator separates the C++ stack and the
4803 // JS stack. This test therefore fails on the simulator. The test is
4804 // not threaded to allow the threading tests to run on the simulator.
4805 TEST(TryCatchInTryFinally) {
4806 v8::Isolate* isolate = CcTest::isolate();
4807 v8::HandleScope scope(isolate);
4808 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4809 templ->Set(v8_str("CCatcher"),
4810 v8::FunctionTemplate::New(isolate, CCatcher));
4811 LocalContext context(0, templ);
4812 Local<Value> result = CompileRun("try {"
4814 " CCatcher('throw 7;');"
4819 CHECK(result->IsTrue());
4823 static void check_reference_error_message(
4824 v8::Handle<v8::Message> message,
4825 v8::Handle<v8::Value> data) {
4826 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4827 CHECK(message->Get()->Equals(v8_str(reference_error)));
4831 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4832 ApiTestFuzzer::Fuzz();
4837 // Test that overwritten methods are not invoked on uncaught exception
4838 // formatting. However, they are invoked when performing normal error
4839 // string conversions.
4840 TEST(APIThrowMessageOverwrittenToString) {
4841 v8::Isolate* isolate = CcTest::isolate();
4842 v8::HandleScope scope(isolate);
4843 v8::V8::AddMessageListener(check_reference_error_message);
4844 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4845 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4846 LocalContext context(NULL, templ);
4847 CompileRun("asdf;");
4848 CompileRun("var limit = {};"
4849 "limit.valueOf = fail;"
4850 "Error.stackTraceLimit = limit;");
4852 CompileRun("Array.prototype.pop = fail;");
4853 CompileRun("Object.prototype.hasOwnProperty = fail;");
4854 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4855 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4856 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4857 CompileRun("ReferenceError.prototype.toString ="
4858 " function() { return 'Whoops' }");
4859 CompileRun("asdf;");
4860 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4861 CompileRun("asdf;");
4862 CompileRun("ReferenceError.prototype.constructor = void 0;");
4863 CompileRun("asdf;");
4864 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4865 CompileRun("asdf;");
4866 CompileRun("ReferenceError.prototype = new Object();");
4867 CompileRun("asdf;");
4868 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4869 CHECK(string->Equals(v8_str("Whoops")));
4870 CompileRun("ReferenceError.prototype.constructor = new Object();"
4871 "ReferenceError.prototype.constructor.name = 1;"
4872 "Number.prototype.toString = function() { return 'Whoops'; };"
4873 "ReferenceError.prototype.toString = Object.prototype.toString;");
4874 CompileRun("asdf;");
4875 v8::V8::RemoveMessageListeners(check_reference_error_message);
4879 static void check_custom_error_tostring(
4880 v8::Handle<v8::Message> message,
4881 v8::Handle<v8::Value> data) {
4882 const char* uncaught_error = "Uncaught MyError toString";
4883 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4887 TEST(CustomErrorToString) {
4888 LocalContext context;
4889 v8::HandleScope scope(context->GetIsolate());
4890 v8::V8::AddMessageListener(check_custom_error_tostring);
4892 "function MyError(name, message) { "
4893 " this.name = name; "
4894 " this.message = message; "
4896 "MyError.prototype = Object.create(Error.prototype); "
4897 "MyError.prototype.toString = function() { "
4898 " return 'MyError toString'; "
4900 "throw new MyError('my name', 'my message'); ");
4901 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4905 static void check_custom_error_message(
4906 v8::Handle<v8::Message> message,
4907 v8::Handle<v8::Value> data) {
4908 const char* uncaught_error = "Uncaught MyError: my message";
4909 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4910 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4914 TEST(CustomErrorMessage) {
4915 LocalContext context;
4916 v8::HandleScope scope(context->GetIsolate());
4917 v8::V8::AddMessageListener(check_custom_error_message);
4921 "function MyError(msg) { "
4922 " this.name = 'MyError'; "
4923 " this.message = msg; "
4925 "MyError.prototype = new Error(); "
4926 "throw new MyError('my message'); ");
4930 "function MyError(msg) { "
4931 " this.name = 'MyError'; "
4932 " this.message = msg; "
4934 "inherits = function(childCtor, parentCtor) { "
4935 " function tempCtor() {}; "
4936 " tempCtor.prototype = parentCtor.prototype; "
4937 " childCtor.superClass_ = parentCtor.prototype; "
4938 " childCtor.prototype = new tempCtor(); "
4939 " childCtor.prototype.constructor = childCtor; "
4941 "inherits(MyError, Error); "
4942 "throw new MyError('my message'); ");
4946 "function MyError(msg) { "
4947 " this.name = 'MyError'; "
4948 " this.message = msg; "
4950 "MyError.prototype = Object.create(Error.prototype); "
4951 "throw new MyError('my message'); ");
4953 v8::V8::RemoveMessageListeners(check_custom_error_message);
4957 static void receive_message(v8::Handle<v8::Message> message,
4958 v8::Handle<v8::Value> data) {
4960 message_received = true;
4964 TEST(APIThrowMessage) {
4965 message_received = false;
4966 v8::Isolate* isolate = CcTest::isolate();
4967 v8::HandleScope scope(isolate);
4968 v8::V8::AddMessageListener(receive_message);
4969 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4970 templ->Set(v8_str("ThrowFromC"),
4971 v8::FunctionTemplate::New(isolate, ThrowFromC));
4972 LocalContext context(0, templ);
4973 CompileRun("ThrowFromC();");
4974 CHECK(message_received);
4975 v8::V8::RemoveMessageListeners(receive_message);
4979 TEST(APIThrowMessageAndVerboseTryCatch) {
4980 message_received = false;
4981 v8::Isolate* isolate = CcTest::isolate();
4982 v8::HandleScope scope(isolate);
4983 v8::V8::AddMessageListener(receive_message);
4984 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4985 templ->Set(v8_str("ThrowFromC"),
4986 v8::FunctionTemplate::New(isolate, ThrowFromC));
4987 LocalContext context(0, templ);
4988 v8::TryCatch try_catch;
4989 try_catch.SetVerbose(true);
4990 Local<Value> result = CompileRun("ThrowFromC();");
4991 CHECK(try_catch.HasCaught());
4992 CHECK(result.IsEmpty());
4993 CHECK(message_received);
4994 v8::V8::RemoveMessageListeners(receive_message);
4998 TEST(APIStackOverflowAndVerboseTryCatch) {
4999 message_received = false;
5000 LocalContext context;
5001 v8::HandleScope scope(context->GetIsolate());
5002 v8::V8::AddMessageListener(receive_message);
5003 v8::TryCatch try_catch;
5004 try_catch.SetVerbose(true);
5005 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5006 CHECK(try_catch.HasCaught());
5007 CHECK(result.IsEmpty());
5008 CHECK(message_received);
5009 v8::V8::RemoveMessageListeners(receive_message);
5013 THREADED_TEST(ExternalScriptException) {
5014 v8::Isolate* isolate = CcTest::isolate();
5015 v8::HandleScope scope(isolate);
5016 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5017 templ->Set(v8_str("ThrowFromC"),
5018 v8::FunctionTemplate::New(isolate, ThrowFromC));
5019 LocalContext context(0, templ);
5021 v8::TryCatch try_catch;
5022 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5023 CHECK(result.IsEmpty());
5024 CHECK(try_catch.HasCaught());
5025 String::Utf8Value exception_value(try_catch.Exception());
5026 CHECK_EQ("konto", *exception_value);
5031 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5032 ApiTestFuzzer::Fuzz();
5033 CHECK_EQ(4, args.Length());
5034 int count = args[0]->Int32Value();
5035 int cInterval = args[2]->Int32Value();
5037 args.GetIsolate()->ThrowException(v8_str("FromC"));
5040 Local<v8::Object> global =
5041 args.GetIsolate()->GetCurrentContext()->Global();
5042 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5043 v8::Handle<Value> argv[] = { v8_num(count - 1),
5047 if (count % cInterval == 0) {
5048 v8::TryCatch try_catch;
5049 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5050 int expected = args[3]->Int32Value();
5051 if (try_catch.HasCaught()) {
5052 CHECK_EQ(expected, count);
5053 CHECK(result.IsEmpty());
5054 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5056 CHECK_NE(expected, count);
5058 args.GetReturnValue().Set(result);
5061 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5068 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5069 ApiTestFuzzer::Fuzz();
5070 CHECK_EQ(3, args.Length());
5071 bool equality = args[0]->BooleanValue();
5072 int count = args[1]->Int32Value();
5073 int expected = args[2]->Int32Value();
5075 CHECK_EQ(count, expected);
5077 CHECK_NE(count, expected);
5082 THREADED_TEST(EvalInTryFinally) {
5083 LocalContext context;
5084 v8::HandleScope scope(context->GetIsolate());
5085 v8::TryCatch try_catch;
5086 CompileRun("(function() {"
5088 " eval('asldkf (*&^&*^');"
5093 CHECK(!try_catch.HasCaught());
5097 // This test works by making a stack of alternating JavaScript and C
5098 // activations. These activations set up exception handlers with regular
5099 // intervals, one interval for C activations and another for JavaScript
5100 // activations. When enough activations have been created an exception is
5101 // thrown and we check that the right activation catches the exception and that
5102 // no other activations do. The right activation is always the topmost one with
5103 // a handler, regardless of whether it is in JavaScript or C.
5105 // The notation used to describe a test case looks like this:
5107 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5109 // Each entry is an activation, either JS or C. The index is the count at that
5110 // level. Stars identify activations with exception handlers, the @ identifies
5111 // the exception handler that should catch the exception.
5113 // BUG(271): Some of the exception propagation does not work on the
5114 // ARM simulator because the simulator separates the C++ stack and the
5115 // JS stack. This test therefore fails on the simulator. The test is
5116 // not threaded to allow the threading tests to run on the simulator.
5117 TEST(ExceptionOrder) {
5118 v8::Isolate* isolate = CcTest::isolate();
5119 v8::HandleScope scope(isolate);
5120 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5121 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5122 templ->Set(v8_str("CThrowCountDown"),
5123 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5124 LocalContext context(0, templ);
5126 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5127 " if (count == 0) throw 'FromJS';"
5128 " if (count % jsInterval == 0) {"
5130 " var value = CThrowCountDown(count - 1,"
5134 " check(false, count, expected);"
5137 " check(true, count, expected);"
5140 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5143 Local<Function> fun =
5144 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5147 // count jsInterval cInterval expected
5149 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5150 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5151 fun->Call(fun, argc, a0);
5153 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5154 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5155 fun->Call(fun, argc, a1);
5157 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5158 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5159 fun->Call(fun, argc, a2);
5161 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5162 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5163 fun->Call(fun, argc, a3);
5165 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5166 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5167 fun->Call(fun, argc, a4);
5169 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5170 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5171 fun->Call(fun, argc, a5);
5175 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5176 ApiTestFuzzer::Fuzz();
5177 CHECK_EQ(1, args.Length());
5178 args.GetIsolate()->ThrowException(args[0]);
5182 THREADED_TEST(ThrowValues) {
5183 v8::Isolate* isolate = CcTest::isolate();
5184 v8::HandleScope scope(isolate);
5185 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5186 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5187 LocalContext context(0, templ);
5188 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5189 "function Run(obj) {"
5195 " return 'no exception';"
5197 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5198 CHECK_EQ(5, result->Length());
5199 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5200 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5201 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5202 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5203 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5204 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5205 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5209 THREADED_TEST(CatchZero) {
5210 LocalContext context;
5211 v8::HandleScope scope(context->GetIsolate());
5212 v8::TryCatch try_catch;
5213 CHECK(!try_catch.HasCaught());
5214 CompileRun("throw 10");
5215 CHECK(try_catch.HasCaught());
5216 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5218 CHECK(!try_catch.HasCaught());
5219 CompileRun("throw 0");
5220 CHECK(try_catch.HasCaught());
5221 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5225 THREADED_TEST(CatchExceptionFromWith) {
5226 LocalContext context;
5227 v8::HandleScope scope(context->GetIsolate());
5228 v8::TryCatch try_catch;
5229 CHECK(!try_catch.HasCaught());
5230 CompileRun("var o = {}; with (o) { throw 42; }");
5231 CHECK(try_catch.HasCaught());
5235 THREADED_TEST(TryCatchAndFinallyHidingException) {
5236 LocalContext context;
5237 v8::HandleScope scope(context->GetIsolate());
5238 v8::TryCatch try_catch;
5239 CHECK(!try_catch.HasCaught());
5240 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5241 CompileRun("f({toString: function() { throw 42; }});");
5242 CHECK(!try_catch.HasCaught());
5246 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5247 v8::TryCatch try_catch;
5251 THREADED_TEST(TryCatchAndFinally) {
5252 LocalContext context;
5253 v8::Isolate* isolate = context->GetIsolate();
5254 v8::HandleScope scope(isolate);
5255 context->Global()->Set(
5256 v8_str("native_with_try_catch"),
5257 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5258 v8::TryCatch try_catch;
5259 CHECK(!try_catch.HasCaught());
5262 " throw new Error('a');\n"
5264 " native_with_try_catch();\n"
5266 CHECK(try_catch.HasCaught());
5270 static void TryCatchNestedHelper(int depth) {
5272 v8::TryCatch try_catch;
5273 try_catch.SetVerbose(true);
5274 TryCatchNestedHelper(depth - 1);
5275 CHECK(try_catch.HasCaught());
5276 try_catch.ReThrow();
5278 CcTest::isolate()->ThrowException(v8_str("back"));
5283 TEST(TryCatchNested) {
5284 v8::V8::Initialize();
5285 LocalContext context;
5286 v8::HandleScope scope(context->GetIsolate());
5287 v8::TryCatch try_catch;
5288 TryCatchNestedHelper(5);
5289 CHECK(try_catch.HasCaught());
5290 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5294 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5295 CHECK(try_catch->HasCaught());
5296 Handle<Message> message = try_catch->Message();
5297 Handle<Value> resource = message->GetScriptResourceName();
5298 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5299 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5300 "Uncaught Error: a"));
5301 CHECK_EQ(1, message->GetLineNumber());
5302 CHECK_EQ(6, message->GetStartColumn());
5306 void TryCatchMixedNestingHelper(
5307 const v8::FunctionCallbackInfo<v8::Value>& args) {
5308 ApiTestFuzzer::Fuzz();
5309 v8::TryCatch try_catch;
5310 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5311 CHECK(try_catch.HasCaught());
5312 TryCatchMixedNestingCheck(&try_catch);
5313 try_catch.ReThrow();
5317 // This test ensures that an outer TryCatch in the following situation:
5318 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5319 // does not clobber the Message object generated for the inner TryCatch.
5320 // This exercises the ability of TryCatch.ReThrow() to restore the
5321 // inner pending Message before throwing the exception again.
5322 TEST(TryCatchMixedNesting) {
5323 v8::Isolate* isolate = CcTest::isolate();
5324 v8::HandleScope scope(isolate);
5325 v8::V8::Initialize();
5326 v8::TryCatch try_catch;
5327 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5328 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5329 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5330 LocalContext context(0, templ);
5331 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5332 TryCatchMixedNestingCheck(&try_catch);
5336 THREADED_TEST(Equality) {
5337 LocalContext context;
5338 v8::Isolate* isolate = context->GetIsolate();
5339 v8::HandleScope scope(context->GetIsolate());
5340 // Check that equality works at all before relying on CHECK_EQ
5341 CHECK(v8_str("a")->Equals(v8_str("a")));
5342 CHECK(!v8_str("a")->Equals(v8_str("b")));
5344 CHECK_EQ(v8_str("a"), v8_str("a"));
5345 CHECK_NE(v8_str("a"), v8_str("b"));
5346 CHECK_EQ(v8_num(1), v8_num(1));
5347 CHECK_EQ(v8_num(1.00), v8_num(1));
5348 CHECK_NE(v8_num(1), v8_num(2));
5350 // Assume String is not internalized.
5351 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5352 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5353 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5354 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5355 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5356 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5357 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5358 CHECK(!not_a_number->StrictEquals(not_a_number));
5359 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5360 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5362 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5363 v8::Persistent<v8::Object> alias(isolate, obj);
5364 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5367 CHECK(v8_str("a")->SameValue(v8_str("a")));
5368 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5369 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5370 CHECK(v8_num(1)->SameValue(v8_num(1)));
5371 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5372 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5373 CHECK(not_a_number->SameValue(not_a_number));
5374 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5375 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5379 THREADED_TEST(MultiRun) {
5380 LocalContext context;
5381 v8::HandleScope scope(context->GetIsolate());
5382 Local<Script> script = v8_compile("x");
5383 for (int i = 0; i < 10; i++)
5388 static void GetXValue(Local<String> name,
5389 const v8::PropertyCallbackInfo<v8::Value>& info) {
5390 ApiTestFuzzer::Fuzz();
5391 CHECK_EQ(info.Data(), v8_str("donut"));
5392 CHECK_EQ(name, v8_str("x"));
5393 info.GetReturnValue().Set(name);
5397 THREADED_TEST(SimplePropertyRead) {
5398 LocalContext context;
5399 v8::Isolate* isolate = context->GetIsolate();
5400 v8::HandleScope scope(isolate);
5401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5402 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5403 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5404 Local<Script> script = v8_compile("obj.x");
5405 for (int i = 0; i < 10; i++) {
5406 Local<Value> result = script->Run();
5407 CHECK_EQ(result, v8_str("x"));
5412 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5413 LocalContext context;
5414 v8::Isolate* isolate = context->GetIsolate();
5415 v8::HandleScope scope(isolate);
5416 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5417 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5418 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5420 // Uses getOwnPropertyDescriptor to check the configurable status
5421 Local<Script> script_desc = v8_compile(
5422 "var prop = Object.getOwnPropertyDescriptor( "
5424 "prop.configurable;");
5425 Local<Value> result = script_desc->Run();
5426 CHECK_EQ(result->BooleanValue(), true);
5428 // Redefine get - but still configurable
5429 Local<Script> script_define = v8_compile(
5430 "var desc = { get: function(){return 42; },"
5431 " configurable: true };"
5432 "Object.defineProperty(obj, 'x', desc);"
5434 result = script_define->Run();
5435 CHECK_EQ(result, v8_num(42));
5437 // Check that the accessor is still configurable
5438 result = script_desc->Run();
5439 CHECK_EQ(result->BooleanValue(), true);
5441 // Redefine to a non-configurable
5442 script_define = v8_compile(
5443 "var desc = { get: function(){return 43; },"
5444 " configurable: false };"
5445 "Object.defineProperty(obj, 'x', desc);"
5447 result = script_define->Run();
5448 CHECK_EQ(result, v8_num(43));
5449 result = script_desc->Run();
5450 CHECK_EQ(result->BooleanValue(), false);
5452 // Make sure that it is not possible to redefine again
5453 v8::TryCatch try_catch;
5454 result = script_define->Run();
5455 CHECK(try_catch.HasCaught());
5456 String::Utf8Value exception_value(try_catch.Exception());
5457 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5461 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5462 v8::Isolate* isolate = CcTest::isolate();
5463 v8::HandleScope scope(isolate);
5464 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5465 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5466 LocalContext context;
5467 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5469 Local<Script> script_desc = v8_compile(
5471 "Object.getOwnPropertyDescriptor( "
5473 "prop.configurable;");
5474 Local<Value> result = script_desc->Run();
5475 CHECK_EQ(result->BooleanValue(), true);
5477 Local<Script> script_define = v8_compile(
5478 "var desc = {get: function(){return 42; },"
5479 " configurable: true };"
5480 "Object.defineProperty(obj, 'x', desc);"
5482 result = script_define->Run();
5483 CHECK_EQ(result, v8_num(42));
5486 result = script_desc->Run();
5487 CHECK_EQ(result->BooleanValue(), true);
5490 script_define = v8_compile(
5491 "var desc = {get: function(){return 43; },"
5492 " configurable: false };"
5493 "Object.defineProperty(obj, 'x', desc);"
5495 result = script_define->Run();
5496 CHECK_EQ(result, v8_num(43));
5497 result = script_desc->Run();
5499 CHECK_EQ(result->BooleanValue(), false);
5501 v8::TryCatch try_catch;
5502 result = script_define->Run();
5503 CHECK(try_catch.HasCaught());
5504 String::Utf8Value exception_value(try_catch.Exception());
5505 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5509 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5511 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5515 THREADED_TEST(DefineAPIAccessorOnObject) {
5516 v8::Isolate* isolate = CcTest::isolate();
5517 v8::HandleScope scope(isolate);
5518 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5519 LocalContext context;
5521 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5522 CompileRun("var obj2 = {};");
5524 CHECK(CompileRun("obj1.x")->IsUndefined());
5525 CHECK(CompileRun("obj2.x")->IsUndefined());
5527 CHECK(GetGlobalProperty(&context, "obj1")->
5528 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5530 ExpectString("obj1.x", "x");
5531 CHECK(CompileRun("obj2.x")->IsUndefined());
5533 CHECK(GetGlobalProperty(&context, "obj2")->
5534 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5536 ExpectString("obj1.x", "x");
5537 ExpectString("obj2.x", "x");
5539 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5540 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5542 CompileRun("Object.defineProperty(obj1, 'x',"
5543 "{ get: function() { return 'y'; }, configurable: true })");
5545 ExpectString("obj1.x", "y");
5546 ExpectString("obj2.x", "x");
5548 CompileRun("Object.defineProperty(obj2, 'x',"
5549 "{ get: function() { return 'y'; }, configurable: true })");
5551 ExpectString("obj1.x", "y");
5552 ExpectString("obj2.x", "y");
5554 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5555 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5557 CHECK(GetGlobalProperty(&context, "obj1")->
5558 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5559 CHECK(GetGlobalProperty(&context, "obj2")->
5560 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5562 ExpectString("obj1.x", "x");
5563 ExpectString("obj2.x", "x");
5565 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5566 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5568 // Define getters/setters, but now make them not configurable.
5569 CompileRun("Object.defineProperty(obj1, 'x',"
5570 "{ get: function() { return 'z'; }, configurable: false })");
5571 CompileRun("Object.defineProperty(obj2, 'x',"
5572 "{ get: function() { return 'z'; }, configurable: false })");
5574 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5575 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5577 ExpectString("obj1.x", "z");
5578 ExpectString("obj2.x", "z");
5580 CHECK(!GetGlobalProperty(&context, "obj1")->
5581 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5582 CHECK(!GetGlobalProperty(&context, "obj2")->
5583 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5585 ExpectString("obj1.x", "z");
5586 ExpectString("obj2.x", "z");
5590 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5591 v8::Isolate* isolate = CcTest::isolate();
5592 v8::HandleScope scope(isolate);
5593 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5594 LocalContext context;
5596 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5597 CompileRun("var obj2 = {};");
5599 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5602 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5603 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5606 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5608 ExpectString("obj1.x", "x");
5609 ExpectString("obj2.x", "x");
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")));
5620 v8::TryCatch try_catch;
5621 CompileRun("Object.defineProperty(obj1, 'x',"
5622 "{get: function() { return 'func'; }})");
5623 CHECK(try_catch.HasCaught());
5624 String::Utf8Value exception_value(try_catch.Exception());
5625 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5628 v8::TryCatch try_catch;
5629 CompileRun("Object.defineProperty(obj2, 'x',"
5630 "{get: function() { return 'func'; }})");
5631 CHECK(try_catch.HasCaught());
5632 String::Utf8Value exception_value(try_catch.Exception());
5633 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5638 static void Get239Value(Local<String> name,
5639 const v8::PropertyCallbackInfo<v8::Value>& info) {
5640 ApiTestFuzzer::Fuzz();
5641 CHECK_EQ(info.Data(), v8_str("donut"));
5642 CHECK_EQ(name, v8_str("239"));
5643 info.GetReturnValue().Set(name);
5647 THREADED_TEST(ElementAPIAccessor) {
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(
5660 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5665 ExpectString("obj1[239]", "239");
5666 ExpectString("obj2[239]", "239");
5667 ExpectString("obj1['239']", "239");
5668 ExpectString("obj2['239']", "239");
5672 v8::Persistent<Value> xValue;
5675 static void SetXValue(Local<String> name,
5677 const v8::PropertyCallbackInfo<void>& info) {
5678 CHECK_EQ(value, v8_num(4));
5679 CHECK_EQ(info.Data(), v8_str("donut"));
5680 CHECK_EQ(name, v8_str("x"));
5681 CHECK(xValue.IsEmpty());
5682 xValue.Reset(info.GetIsolate(), value);
5686 THREADED_TEST(SimplePropertyWrite) {
5687 v8::Isolate* isolate = CcTest::isolate();
5688 v8::HandleScope scope(isolate);
5689 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5690 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5691 LocalContext context;
5692 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5693 Local<Script> script = v8_compile("obj.x = 4");
5694 for (int i = 0; i < 10; i++) {
5695 CHECK(xValue.IsEmpty());
5697 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5703 THREADED_TEST(SetterOnly) {
5704 v8::Isolate* isolate = CcTest::isolate();
5705 v8::HandleScope scope(isolate);
5706 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5707 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5708 LocalContext context;
5709 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5710 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5711 for (int i = 0; i < 10; i++) {
5712 CHECK(xValue.IsEmpty());
5714 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5720 THREADED_TEST(NoAccessors) {
5721 v8::Isolate* isolate = CcTest::isolate();
5722 v8::HandleScope scope(isolate);
5723 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5724 templ->SetAccessor(v8_str("x"),
5725 static_cast<v8::AccessorGetterCallback>(NULL),
5728 LocalContext context;
5729 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5730 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5731 for (int i = 0; i < 10; i++) {
5737 static void XPropertyGetter(Local<String> property,
5738 const v8::PropertyCallbackInfo<v8::Value>& info) {
5739 ApiTestFuzzer::Fuzz();
5740 CHECK(info.Data()->IsUndefined());
5741 info.GetReturnValue().Set(property);
5745 THREADED_TEST(NamedInterceptorPropertyRead) {
5746 v8::Isolate* isolate = CcTest::isolate();
5747 v8::HandleScope scope(isolate);
5748 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5749 templ->SetNamedPropertyHandler(XPropertyGetter);
5750 LocalContext context;
5751 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5752 Local<Script> script = v8_compile("obj.x");
5753 for (int i = 0; i < 10; i++) {
5754 Local<Value> result = script->Run();
5755 CHECK_EQ(result, v8_str("x"));
5760 THREADED_TEST(NamedInterceptorDictionaryIC) {
5761 v8::Isolate* isolate = CcTest::isolate();
5762 v8::HandleScope scope(isolate);
5763 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764 templ->SetNamedPropertyHandler(XPropertyGetter);
5765 LocalContext context;
5766 // Create an object with a named interceptor.
5767 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5768 Local<Script> script = v8_compile("interceptor_obj.x");
5769 for (int i = 0; i < 10; i++) {
5770 Local<Value> result = script->Run();
5771 CHECK_EQ(result, v8_str("x"));
5773 // Create a slow case object and a function accessing a property in
5774 // that slow case object (with dictionary probing in generated
5775 // code). Then force object with a named interceptor into slow-case,
5776 // pass it to the function, and check that the interceptor is called
5777 // instead of accessing the local property.
5778 Local<Value> result =
5779 CompileRun("function get_x(o) { return o.x; };"
5780 "var obj = { x : 42, y : 0 };"
5782 "for (var i = 0; i < 10; i++) get_x(obj);"
5783 "interceptor_obj.x = 42;"
5784 "interceptor_obj.y = 10;"
5785 "delete interceptor_obj.y;"
5786 "get_x(interceptor_obj)");
5787 CHECK_EQ(result, v8_str("x"));
5791 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5792 v8::Isolate* isolate = CcTest::isolate();
5793 v8::HandleScope scope(isolate);
5794 v8::Local<Context> context1 = Context::New(isolate);
5797 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5798 templ->SetNamedPropertyHandler(XPropertyGetter);
5799 // Create an object with a named interceptor.
5800 v8::Local<v8::Object> object = templ->NewInstance();
5801 context1->Global()->Set(v8_str("interceptor_obj"), object);
5803 // Force the object into the slow case.
5804 CompileRun("interceptor_obj.y = 0;"
5805 "delete interceptor_obj.y;");
5809 // Introduce the object into a different context.
5810 // Repeat named loads to exercise ICs.
5811 LocalContext context2;
5812 context2->Global()->Set(v8_str("interceptor_obj"), object);
5813 Local<Value> result =
5814 CompileRun("function get_x(o) { return o.x; }"
5815 "interceptor_obj.x = 42;"
5816 "for (var i=0; i != 10; i++) {"
5817 " get_x(interceptor_obj);"
5819 "get_x(interceptor_obj)");
5820 // Check that the interceptor was actually invoked.
5821 CHECK_EQ(result, v8_str("x"));
5824 // Return to the original context and force some object to the slow case
5825 // to cause the NormalizedMapCache to verify.
5827 CompileRun("var obj = { x : 0 }; delete obj.x;");
5832 static void SetXOnPrototypeGetter(
5833 Local<String> property,
5834 const v8::PropertyCallbackInfo<v8::Value>& info) {
5835 // Set x on the prototype object and do not handle the get request.
5836 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5837 proto.As<v8::Object>()->Set(v8_str("x"),
5838 v8::Integer::New(info.GetIsolate(), 23));
5842 // This is a regression test for http://crbug.com/20104. Map
5843 // transitions should not interfere with post interceptor lookup.
5844 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5845 v8::Isolate* isolate = CcTest::isolate();
5846 v8::HandleScope scope(isolate);
5847 Local<v8::FunctionTemplate> function_template =
5848 v8::FunctionTemplate::New(isolate);
5849 Local<v8::ObjectTemplate> instance_template
5850 = function_template->InstanceTemplate();
5851 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5852 LocalContext context;
5853 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5854 // Create an instance of F and introduce a map transition for x.
5855 CompileRun("var o = new F(); o.x = 23;");
5856 // Create an instance of F and invoke the getter. The result should be 23.
5857 Local<Value> result = CompileRun("o = new F(); o.x");
5858 CHECK_EQ(result->Int32Value(), 23);
5862 static void IndexedPropertyGetter(
5864 const v8::PropertyCallbackInfo<v8::Value>& info) {
5865 ApiTestFuzzer::Fuzz();
5867 info.GetReturnValue().Set(v8_num(625));
5872 static void IndexedPropertySetter(
5875 const v8::PropertyCallbackInfo<v8::Value>& info) {
5876 ApiTestFuzzer::Fuzz();
5878 info.GetReturnValue().Set(value);
5883 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5884 v8::Isolate* isolate = CcTest::isolate();
5885 v8::HandleScope scope(isolate);
5886 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5887 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5888 IndexedPropertySetter);
5889 LocalContext context;
5890 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5891 Local<Script> getter_script = v8_compile(
5892 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5893 Local<Script> setter_script = v8_compile(
5894 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5897 Local<Script> interceptor_setter_script = v8_compile(
5898 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5900 "obj.foo;"); // This setter should not run, due to the interceptor.
5901 Local<Script> interceptor_getter_script = v8_compile(
5903 Local<Value> result = getter_script->Run();
5904 CHECK_EQ(v8_num(5), result);
5905 result = setter_script->Run();
5906 CHECK_EQ(v8_num(23), result);
5907 result = interceptor_setter_script->Run();
5908 CHECK_EQ(v8_num(23), result);
5909 result = interceptor_getter_script->Run();
5910 CHECK_EQ(v8_num(625), result);
5914 static void UnboxedDoubleIndexedPropertyGetter(
5916 const v8::PropertyCallbackInfo<v8::Value>& info) {
5917 ApiTestFuzzer::Fuzz();
5919 info.GetReturnValue().Set(v8_num(index));
5924 static void UnboxedDoubleIndexedPropertySetter(
5927 const v8::PropertyCallbackInfo<v8::Value>& info) {
5928 ApiTestFuzzer::Fuzz();
5930 info.GetReturnValue().Set(v8_num(index));
5935 void UnboxedDoubleIndexedPropertyEnumerator(
5936 const v8::PropertyCallbackInfo<v8::Array>& info) {
5937 // Force the list of returned keys to be stored in a FastDoubleArray.
5938 Local<Script> indexed_property_names_script = v8_compile(
5939 "keys = new Array(); keys[125000] = 1;"
5940 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5941 "keys.length = 25; keys;");
5942 Local<Value> result = indexed_property_names_script->Run();
5943 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5947 // Make sure that the the interceptor code in the runtime properly handles
5948 // merging property name lists for double-array-backed arrays.
5949 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5950 v8::Isolate* isolate = CcTest::isolate();
5951 v8::HandleScope scope(isolate);
5952 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5953 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5954 UnboxedDoubleIndexedPropertySetter,
5957 UnboxedDoubleIndexedPropertyEnumerator);
5958 LocalContext context;
5959 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5960 // When obj is created, force it to be Stored in a FastDoubleArray.
5961 Local<Script> create_unboxed_double_script = v8_compile(
5962 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5964 "for (x in obj) {key_count++;};"
5966 Local<Value> result = create_unboxed_double_script->Run();
5967 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5968 Local<Script> key_count_check = v8_compile("key_count;");
5969 result = key_count_check->Run();
5970 CHECK_EQ(v8_num(40013), result);
5974 void SloppyArgsIndexedPropertyEnumerator(
5975 const v8::PropertyCallbackInfo<v8::Array>& info) {
5976 // Force the list of returned keys to be stored in a Arguments object.
5977 Local<Script> indexed_property_names_script = v8_compile(
5979 " return arguments;"
5981 "keys = f(0, 1, 2, 3);"
5983 Local<Object> result =
5984 Local<Object>::Cast(indexed_property_names_script->Run());
5985 // Have to populate the handle manually, as it's not Cast-able.
5986 i::Handle<i::JSObject> o =
5987 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5988 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5989 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5993 static void SloppyIndexedPropertyGetter(
5995 const v8::PropertyCallbackInfo<v8::Value>& info) {
5996 ApiTestFuzzer::Fuzz();
5998 info.GetReturnValue().Set(v8_num(index));
6003 // Make sure that the the interceptor code in the runtime properly handles
6004 // merging property name lists for non-string arguments arrays.
6005 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6006 v8::Isolate* isolate = CcTest::isolate();
6007 v8::HandleScope scope(isolate);
6008 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6009 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6013 SloppyArgsIndexedPropertyEnumerator);
6014 LocalContext context;
6015 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6016 Local<Script> create_args_script = v8_compile(
6017 "var key_count = 0;"
6018 "for (x in obj) {key_count++;} key_count;");
6019 Local<Value> result = create_args_script->Run();
6020 CHECK_EQ(v8_num(4), result);
6024 static void IdentityIndexedPropertyGetter(
6026 const v8::PropertyCallbackInfo<v8::Value>& info) {
6027 info.GetReturnValue().Set(index);
6031 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6032 v8::Isolate* isolate = CcTest::isolate();
6033 v8::HandleScope scope(isolate);
6034 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6035 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6037 LocalContext context;
6038 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6040 // Check fast object case.
6041 const char* fast_case_code =
6042 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6043 ExpectString(fast_case_code, "0");
6046 const char* slow_case_code =
6047 "obj.x = 1; delete obj.x;"
6048 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6049 ExpectString(slow_case_code, "1");
6053 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6054 v8::Isolate* isolate = CcTest::isolate();
6055 v8::HandleScope scope(isolate);
6056 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6057 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6059 LocalContext context;
6060 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6065 " for (var i = 0; i < 100; i++) {"
6067 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6073 ExpectString(code, "PASSED");
6077 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6078 v8::Isolate* isolate = CcTest::isolate();
6079 v8::HandleScope scope(isolate);
6080 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6081 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6083 LocalContext context;
6084 Local<v8::Object> obj = templ->NewInstance();
6085 obj->TurnOnAccessCheck();
6086 context->Global()->Set(v8_str("obj"), obj);
6090 " for (var i = 0; i < 100; i++) {"
6092 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6098 ExpectString(code, "PASSED");
6102 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6103 i::FLAG_allow_natives_syntax = true;
6104 v8::Isolate* isolate = CcTest::isolate();
6105 v8::HandleScope scope(isolate);
6106 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6107 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6109 LocalContext context;
6110 Local<v8::Object> obj = templ->NewInstance();
6111 context->Global()->Set(v8_str("obj"), obj);
6115 " for (var i = 0; i < 100; i++) {"
6116 " var expected = i;"
6118 " %EnableAccessChecks(obj);"
6119 " expected = undefined;"
6122 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6123 " if (i == 5) %DisableAccessChecks(obj);"
6129 ExpectString(code, "PASSED");
6133 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6134 v8::Isolate* isolate = CcTest::isolate();
6135 v8::HandleScope scope(isolate);
6136 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6137 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6139 LocalContext context;
6140 Local<v8::Object> obj = templ->NewInstance();
6141 context->Global()->Set(v8_str("obj"), obj);
6145 " for (var i = 0; i < 100; i++) {"
6147 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6153 ExpectString(code, "PASSED");
6157 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6158 v8::Isolate* isolate = CcTest::isolate();
6159 v8::HandleScope scope(isolate);
6160 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6161 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6163 LocalContext context;
6164 Local<v8::Object> obj = templ->NewInstance();
6165 context->Global()->Set(v8_str("obj"), obj);
6169 " for (var i = 0; i < 100; i++) {"
6170 " var expected = i;"
6174 " expected = undefined;"
6177 " /* probe minimal Smi number on 32-bit platforms */"
6178 " key = -(1 << 30);"
6179 " expected = undefined;"
6182 " /* probe minimal Smi number on 64-bit platforms */"
6184 " expected = undefined;"
6186 " var v = obj[key];"
6187 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6193 ExpectString(code, "PASSED");
6197 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6198 v8::Isolate* isolate = CcTest::isolate();
6199 v8::HandleScope scope(isolate);
6200 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6201 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6203 LocalContext context;
6204 Local<v8::Object> obj = templ->NewInstance();
6205 context->Global()->Set(v8_str("obj"), obj);
6209 " for (var i = 0; i < 100; i++) {"
6210 " var expected = i;"
6214 " expected = undefined;"
6216 " var v = obj[key];"
6217 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6223 ExpectString(code, "PASSED");
6227 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6228 v8::Isolate* isolate = CcTest::isolate();
6229 v8::HandleScope scope(isolate);
6230 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6231 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6233 LocalContext context;
6234 Local<v8::Object> obj = templ->NewInstance();
6235 context->Global()->Set(v8_str("obj"), obj);
6238 "var original = obj;"
6240 " for (var i = 0; i < 100; i++) {"
6241 " var expected = i;"
6243 " obj = {50: 'foobar'};"
6244 " expected = 'foobar';"
6247 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6248 " if (i == 50) obj = original;"
6254 ExpectString(code, "PASSED");
6258 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6259 v8::Isolate* isolate = CcTest::isolate();
6260 v8::HandleScope scope(isolate);
6261 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6262 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6264 LocalContext context;
6265 Local<v8::Object> obj = templ->NewInstance();
6266 context->Global()->Set(v8_str("obj"), obj);
6269 "var original = obj;"
6271 " for (var i = 0; i < 100; i++) {"
6272 " var expected = i;"
6275 " expected = undefined;"
6278 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6279 " if (i == 5) obj = original;"
6285 ExpectString(code, "PASSED");
6289 THREADED_TEST(IndexedInterceptorOnProto) {
6290 v8::Isolate* isolate = CcTest::isolate();
6291 v8::HandleScope scope(isolate);
6292 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6293 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6295 LocalContext context;
6296 Local<v8::Object> obj = templ->NewInstance();
6297 context->Global()->Set(v8_str("obj"), obj);
6300 "var o = {__proto__: obj};"
6302 " for (var i = 0; i < 100; i++) {"
6304 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6310 ExpectString(code, "PASSED");
6314 THREADED_TEST(MultiContexts) {
6315 v8::Isolate* isolate = CcTest::isolate();
6316 v8::HandleScope scope(isolate);
6317 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6318 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6321 Local<String> password = v8_str("Password");
6323 // Create an environment
6324 LocalContext context0(0, templ);
6325 context0->SetSecurityToken(password);
6326 v8::Handle<v8::Object> global0 = context0->Global();
6327 global0->Set(v8_str("custom"), v8_num(1234));
6328 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6330 // Create an independent environment
6331 LocalContext context1(0, templ);
6332 context1->SetSecurityToken(password);
6333 v8::Handle<v8::Object> global1 = context1->Global();
6334 global1->Set(v8_str("custom"), v8_num(1234));
6335 CHECK_NE(global0, global1);
6336 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6337 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6339 // Now create a new context with the old global
6340 LocalContext context2(0, templ, global1);
6341 context2->SetSecurityToken(password);
6342 v8::Handle<v8::Object> global2 = context2->Global();
6343 CHECK_EQ(global1, global2);
6344 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6345 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6349 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6350 // Make sure that functions created by cloning boilerplates cannot
6351 // communicate through their __proto__ field.
6353 v8::HandleScope scope(CcTest::isolate());
6356 v8::Handle<v8::Object> global0 =
6358 v8::Handle<v8::Object> object0 =
6359 global0->Get(v8_str("Object")).As<v8::Object>();
6360 v8::Handle<v8::Object> tostring0 =
6361 object0->Get(v8_str("toString")).As<v8::Object>();
6362 v8::Handle<v8::Object> proto0 =
6363 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6364 proto0->Set(v8_str("custom"), v8_num(1234));
6367 v8::Handle<v8::Object> global1 =
6369 v8::Handle<v8::Object> object1 =
6370 global1->Get(v8_str("Object")).As<v8::Object>();
6371 v8::Handle<v8::Object> tostring1 =
6372 object1->Get(v8_str("toString")).As<v8::Object>();
6373 v8::Handle<v8::Object> proto1 =
6374 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6375 CHECK(!proto1->Has(v8_str("custom")));
6379 THREADED_TEST(Regress892105) {
6380 // Make sure that object and array literals created by cloning
6381 // boilerplates cannot communicate through their __proto__
6382 // field. This is rather difficult to check, but we try to add stuff
6383 // to Object.prototype and Array.prototype and create a new
6384 // environment. This should succeed.
6386 v8::HandleScope scope(CcTest::isolate());
6388 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6389 "Array.prototype.arr = 4567;"
6393 Local<Script> script0 = v8_compile(source);
6394 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6397 Local<Script> script1 = v8_compile(source);
6398 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6402 THREADED_TEST(UndetectableObject) {
6404 v8::HandleScope scope(env->GetIsolate());
6406 Local<v8::FunctionTemplate> desc =
6407 v8::FunctionTemplate::New(env->GetIsolate());
6408 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6410 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6411 env->Global()->Set(v8_str("undetectable"), obj);
6413 ExpectString("undetectable.toString()", "[object Object]");
6414 ExpectString("typeof undetectable", "undefined");
6415 ExpectString("typeof(undetectable)", "undefined");
6416 ExpectBoolean("typeof undetectable == 'undefined'", true);
6417 ExpectBoolean("typeof undetectable == 'object'", false);
6418 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6419 ExpectBoolean("!undetectable", true);
6421 ExpectObject("true&&undetectable", obj);
6422 ExpectBoolean("false&&undetectable", false);
6423 ExpectBoolean("true||undetectable", true);
6424 ExpectObject("false||undetectable", obj);
6426 ExpectObject("undetectable&&true", obj);
6427 ExpectObject("undetectable&&false", obj);
6428 ExpectBoolean("undetectable||true", true);
6429 ExpectBoolean("undetectable||false", false);
6431 ExpectBoolean("undetectable==null", true);
6432 ExpectBoolean("null==undetectable", true);
6433 ExpectBoolean("undetectable==undefined", true);
6434 ExpectBoolean("undefined==undetectable", true);
6435 ExpectBoolean("undetectable==undetectable", true);
6438 ExpectBoolean("undetectable===null", false);
6439 ExpectBoolean("null===undetectable", false);
6440 ExpectBoolean("undetectable===undefined", false);
6441 ExpectBoolean("undefined===undetectable", false);
6442 ExpectBoolean("undetectable===undetectable", true);
6446 THREADED_TEST(VoidLiteral) {
6448 v8::Isolate* isolate = env->GetIsolate();
6449 v8::HandleScope scope(isolate);
6451 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6452 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6454 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6455 env->Global()->Set(v8_str("undetectable"), obj);
6457 ExpectBoolean("undefined == void 0", true);
6458 ExpectBoolean("undetectable == void 0", true);
6459 ExpectBoolean("null == void 0", true);
6460 ExpectBoolean("undefined === void 0", true);
6461 ExpectBoolean("undetectable === void 0", false);
6462 ExpectBoolean("null === void 0", false);
6464 ExpectBoolean("void 0 == undefined", true);
6465 ExpectBoolean("void 0 == undetectable", true);
6466 ExpectBoolean("void 0 == null", true);
6467 ExpectBoolean("void 0 === undefined", true);
6468 ExpectBoolean("void 0 === undetectable", false);
6469 ExpectBoolean("void 0 === null", false);
6471 ExpectString("(function() {"
6473 " return x === void 0;"
6475 " return e.toString();"
6478 "ReferenceError: x is not defined");
6479 ExpectString("(function() {"
6481 " return void 0 === x;"
6483 " return e.toString();"
6486 "ReferenceError: x is not defined");
6490 THREADED_TEST(ExtensibleOnUndetectable) {
6492 v8::Isolate* isolate = env->GetIsolate();
6493 v8::HandleScope scope(isolate);
6495 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6496 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6498 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6499 env->Global()->Set(v8_str("undetectable"), obj);
6501 Local<String> source = v8_str("undetectable.x = 42;"
6504 Local<Script> script = v8_compile(source);
6506 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6508 ExpectBoolean("Object.isExtensible(undetectable)", true);
6510 source = v8_str("Object.preventExtensions(undetectable);");
6511 script = v8_compile(source);
6513 ExpectBoolean("Object.isExtensible(undetectable)", false);
6515 source = v8_str("undetectable.y = 2000;");
6516 script = v8_compile(source);
6518 ExpectBoolean("undetectable.y == undefined", true);
6523 THREADED_TEST(UndetectableString) {
6525 v8::HandleScope scope(env->GetIsolate());
6527 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6528 String::kUndetectableString);
6529 env->Global()->Set(v8_str("undetectable"), obj);
6531 ExpectString("undetectable", "foo");
6532 ExpectString("typeof undetectable", "undefined");
6533 ExpectString("typeof(undetectable)", "undefined");
6534 ExpectBoolean("typeof undetectable == 'undefined'", true);
6535 ExpectBoolean("typeof undetectable == 'string'", false);
6536 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6537 ExpectBoolean("!undetectable", true);
6539 ExpectObject("true&&undetectable", obj);
6540 ExpectBoolean("false&&undetectable", false);
6541 ExpectBoolean("true||undetectable", true);
6542 ExpectObject("false||undetectable", obj);
6544 ExpectObject("undetectable&&true", obj);
6545 ExpectObject("undetectable&&false", obj);
6546 ExpectBoolean("undetectable||true", true);
6547 ExpectBoolean("undetectable||false", false);
6549 ExpectBoolean("undetectable==null", true);
6550 ExpectBoolean("null==undetectable", true);
6551 ExpectBoolean("undetectable==undefined", true);
6552 ExpectBoolean("undefined==undetectable", true);
6553 ExpectBoolean("undetectable==undetectable", true);
6556 ExpectBoolean("undetectable===null", false);
6557 ExpectBoolean("null===undetectable", false);
6558 ExpectBoolean("undetectable===undefined", false);
6559 ExpectBoolean("undefined===undetectable", false);
6560 ExpectBoolean("undetectable===undetectable", true);
6564 TEST(UndetectableOptimized) {
6565 i::FLAG_allow_natives_syntax = true;
6567 v8::HandleScope scope(env->GetIsolate());
6569 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6570 String::kUndetectableString);
6571 env->Global()->Set(v8_str("undetectable"), obj);
6572 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6575 "function testBranch() {"
6576 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6577 " if (%_IsUndetectableObject(detectable)) throw 2;"
6579 "function testBool() {"
6580 " var b1 = !%_IsUndetectableObject(undetectable);"
6581 " var b2 = %_IsUndetectableObject(detectable);"
6586 "%OptimizeFunctionOnNextCall(testBranch);"
6587 "%OptimizeFunctionOnNextCall(testBool);"
6588 "for (var i = 0; i < 10; i++) {"
6597 template <typename T> static void USE(T) { }
6600 // The point of this test is type checking. We run it only so compilers
6601 // don't complain about an unused function.
6602 TEST(PersistentHandles) {
6604 v8::Isolate* isolate = CcTest::isolate();
6605 v8::HandleScope scope(isolate);
6606 Local<String> str = v8_str("foo");
6607 v8::Persistent<String> p_str(isolate, str);
6609 Local<Script> scr = v8_compile("");
6610 v8::Persistent<Script> p_scr(isolate, scr);
6612 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6613 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6618 static void HandleLogDelegator(
6619 const v8::FunctionCallbackInfo<v8::Value>& args) {
6620 ApiTestFuzzer::Fuzz();
6624 THREADED_TEST(GlobalObjectTemplate) {
6625 v8::Isolate* isolate = CcTest::isolate();
6626 v8::HandleScope handle_scope(isolate);
6627 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6628 global_template->Set(v8_str("JSNI_Log"),
6629 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6630 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6631 Context::Scope context_scope(context);
6632 CompileRun("JSNI_Log('LOG')");
6636 static const char* kSimpleExtensionSource =
6642 TEST(SimpleExtensions) {
6643 v8::HandleScope handle_scope(CcTest::isolate());
6644 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6645 const char* extension_names[] = { "simpletest" };
6646 v8::ExtensionConfiguration extensions(1, extension_names);
6647 v8::Handle<Context> context =
6648 Context::New(CcTest::isolate(), &extensions);
6649 Context::Scope lock(context);
6650 v8::Handle<Value> result = CompileRun("Foo()");
6651 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6655 TEST(NullExtensions) {
6656 v8::HandleScope handle_scope(CcTest::isolate());
6657 v8::RegisterExtension(new Extension("nulltest", NULL));
6658 const char* extension_names[] = { "nulltest" };
6659 v8::ExtensionConfiguration extensions(1, extension_names);
6660 v8::Handle<Context> context =
6661 Context::New(CcTest::isolate(), &extensions);
6662 Context::Scope lock(context);
6663 v8::Handle<Value> result = CompileRun("1+3");
6664 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6668 static const char* kEmbeddedExtensionSource =
6669 "function Ret54321(){return 54321;}~~@@$"
6670 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6671 static const int kEmbeddedExtensionSourceValidLen = 34;
6674 TEST(ExtensionMissingSourceLength) {
6675 v8::HandleScope handle_scope(CcTest::isolate());
6676 v8::RegisterExtension(new Extension("srclentest_fail",
6677 kEmbeddedExtensionSource));
6678 const char* extension_names[] = { "srclentest_fail" };
6679 v8::ExtensionConfiguration extensions(1, extension_names);
6680 v8::Handle<Context> context =
6681 Context::New(CcTest::isolate(), &extensions);
6682 CHECK_EQ(0, *context);
6686 TEST(ExtensionWithSourceLength) {
6687 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6688 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6689 v8::HandleScope handle_scope(CcTest::isolate());
6690 i::ScopedVector<char> extension_name(32);
6691 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6692 v8::RegisterExtension(new Extension(extension_name.start(),
6693 kEmbeddedExtensionSource, 0, 0,
6695 const char* extension_names[1] = { extension_name.start() };
6696 v8::ExtensionConfiguration extensions(1, extension_names);
6697 v8::Handle<Context> context =
6698 Context::New(CcTest::isolate(), &extensions);
6699 if (source_len == kEmbeddedExtensionSourceValidLen) {
6700 Context::Scope lock(context);
6701 v8::Handle<Value> result = CompileRun("Ret54321()");
6702 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6704 // Anything but exactly the right length should fail to compile.
6705 CHECK_EQ(0, *context);
6711 static const char* kEvalExtensionSource1 =
6712 "function UseEval1() {"
6714 " return eval('x');"
6718 static const char* kEvalExtensionSource2 =
6722 " return eval('x');"
6724 " this.UseEval2 = e;"
6728 TEST(UseEvalFromExtension) {
6729 v8::HandleScope handle_scope(CcTest::isolate());
6730 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6731 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6732 const char* extension_names[] = { "evaltest1", "evaltest2" };
6733 v8::ExtensionConfiguration extensions(2, extension_names);
6734 v8::Handle<Context> context =
6735 Context::New(CcTest::isolate(), &extensions);
6736 Context::Scope lock(context);
6737 v8::Handle<Value> result = CompileRun("UseEval1()");
6738 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6739 result = CompileRun("UseEval2()");
6740 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6744 static const char* kWithExtensionSource1 =
6745 "function UseWith1() {"
6747 " with({x:87}) { return x; }"
6752 static const char* kWithExtensionSource2 =
6756 " with ({x:87}) { return x; }"
6758 " this.UseWith2 = e;"
6762 TEST(UseWithFromExtension) {
6763 v8::HandleScope handle_scope(CcTest::isolate());
6764 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6765 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6766 const char* extension_names[] = { "withtest1", "withtest2" };
6767 v8::ExtensionConfiguration extensions(2, extension_names);
6768 v8::Handle<Context> context =
6769 Context::New(CcTest::isolate(), &extensions);
6770 Context::Scope lock(context);
6771 v8::Handle<Value> result = CompileRun("UseWith1()");
6772 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6773 result = CompileRun("UseWith2()");
6774 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6778 TEST(AutoExtensions) {
6779 v8::HandleScope handle_scope(CcTest::isolate());
6780 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6781 extension->set_auto_enable(true);
6782 v8::RegisterExtension(extension);
6783 v8::Handle<Context> context =
6784 Context::New(CcTest::isolate());
6785 Context::Scope lock(context);
6786 v8::Handle<Value> result = CompileRun("Foo()");
6787 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6791 static const char* kSyntaxErrorInExtensionSource =
6795 // Test that a syntax error in an extension does not cause a fatal
6796 // error but results in an empty context.
6797 TEST(SyntaxErrorExtensions) {
6798 v8::HandleScope handle_scope(CcTest::isolate());
6799 v8::RegisterExtension(new Extension("syntaxerror",
6800 kSyntaxErrorInExtensionSource));
6801 const char* extension_names[] = { "syntaxerror" };
6802 v8::ExtensionConfiguration extensions(1, extension_names);
6803 v8::Handle<Context> context =
6804 Context::New(CcTest::isolate(), &extensions);
6805 CHECK(context.IsEmpty());
6809 static const char* kExceptionInExtensionSource =
6813 // Test that an exception when installing an extension does not cause
6814 // a fatal error but results in an empty context.
6815 TEST(ExceptionExtensions) {
6816 v8::HandleScope handle_scope(CcTest::isolate());
6817 v8::RegisterExtension(new Extension("exception",
6818 kExceptionInExtensionSource));
6819 const char* extension_names[] = { "exception" };
6820 v8::ExtensionConfiguration extensions(1, extension_names);
6821 v8::Handle<Context> context =
6822 Context::New(CcTest::isolate(), &extensions);
6823 CHECK(context.IsEmpty());
6827 static const char* kNativeCallInExtensionSource =
6828 "function call_runtime_last_index_of(x) {"
6829 " return %StringLastIndexOf(x, 'bob', 10);"
6833 static const char* kNativeCallTest =
6834 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6836 // Test that a native runtime calls are supported in extensions.
6837 TEST(NativeCallInExtensions) {
6838 v8::HandleScope handle_scope(CcTest::isolate());
6839 v8::RegisterExtension(new Extension("nativecall",
6840 kNativeCallInExtensionSource));
6841 const char* extension_names[] = { "nativecall" };
6842 v8::ExtensionConfiguration extensions(1, extension_names);
6843 v8::Handle<Context> context =
6844 Context::New(CcTest::isolate(), &extensions);
6845 Context::Scope lock(context);
6846 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6847 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6851 class NativeFunctionExtension : public Extension {
6853 NativeFunctionExtension(const char* name,
6855 v8::FunctionCallback fun = &Echo)
6856 : Extension(name, source),
6859 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6860 v8::Isolate* isolate,
6861 v8::Handle<v8::String> name) {
6862 return v8::FunctionTemplate::New(isolate, function_);
6865 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6866 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6869 v8::FunctionCallback function_;
6873 TEST(NativeFunctionDeclaration) {
6874 v8::HandleScope handle_scope(CcTest::isolate());
6875 const char* name = "nativedecl";
6876 v8::RegisterExtension(new NativeFunctionExtension(name,
6877 "native function foo();"));
6878 const char* extension_names[] = { name };
6879 v8::ExtensionConfiguration extensions(1, extension_names);
6880 v8::Handle<Context> context =
6881 Context::New(CcTest::isolate(), &extensions);
6882 Context::Scope lock(context);
6883 v8::Handle<Value> result = CompileRun("foo(42);");
6884 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6888 TEST(NativeFunctionDeclarationError) {
6889 v8::HandleScope handle_scope(CcTest::isolate());
6890 const char* name = "nativedeclerr";
6891 // Syntax error in extension code.
6892 v8::RegisterExtension(new NativeFunctionExtension(name,
6893 "native\nfunction foo();"));
6894 const char* extension_names[] = { name };
6895 v8::ExtensionConfiguration extensions(1, extension_names);
6896 v8::Handle<Context> context =
6897 Context::New(CcTest::isolate(), &extensions);
6898 CHECK(context.IsEmpty());
6902 TEST(NativeFunctionDeclarationErrorEscape) {
6903 v8::HandleScope handle_scope(CcTest::isolate());
6904 const char* name = "nativedeclerresc";
6905 // Syntax error in extension code - escape code in "native" means that
6906 // it's not treated as a keyword.
6907 v8::RegisterExtension(new NativeFunctionExtension(
6909 "nativ\\u0065 function foo();"));
6910 const char* extension_names[] = { name };
6911 v8::ExtensionConfiguration extensions(1, extension_names);
6912 v8::Handle<Context> context =
6913 Context::New(CcTest::isolate(), &extensions);
6914 CHECK(context.IsEmpty());
6918 static void CheckDependencies(const char* name, const char* expected) {
6919 v8::HandleScope handle_scope(CcTest::isolate());
6920 v8::ExtensionConfiguration config(1, &name);
6921 LocalContext context(&config);
6922 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6923 context->Global()->Get(v8_str("loaded")));
6934 THREADED_TEST(ExtensionDependency) {
6935 static const char* kEDeps[] = { "D" };
6936 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6937 static const char* kDDeps[] = { "B", "C" };
6938 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6939 static const char* kBCDeps[] = { "A" };
6940 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6941 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6942 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6943 CheckDependencies("A", "undefinedA");
6944 CheckDependencies("B", "undefinedAB");
6945 CheckDependencies("C", "undefinedAC");
6946 CheckDependencies("D", "undefinedABCD");
6947 CheckDependencies("E", "undefinedABCDE");
6948 v8::HandleScope handle_scope(CcTest::isolate());
6949 static const char* exts[2] = { "C", "E" };
6950 v8::ExtensionConfiguration config(2, exts);
6951 LocalContext context(&config);
6952 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6956 static const char* kExtensionTestScript =
6957 "native function A();"
6958 "native function B();"
6959 "native function C();"
6961 " if (i == 0) return A();"
6962 " if (i == 1) return B();"
6963 " if (i == 2) return C();"
6967 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6968 ApiTestFuzzer::Fuzz();
6969 if (args.IsConstructCall()) {
6970 args.This()->Set(v8_str("data"), args.Data());
6971 args.GetReturnValue().SetNull();
6974 args.GetReturnValue().Set(args.Data());
6978 class FunctionExtension : public Extension {
6980 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6981 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6982 v8::Isolate* isolate,
6983 v8::Handle<String> name);
6987 static int lookup_count = 0;
6988 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6989 v8::Isolate* isolate, v8::Handle<String> name) {
6991 if (name->Equals(v8_str("A"))) {
6992 return v8::FunctionTemplate::New(
6993 isolate, CallFun, v8::Integer::New(isolate, 8));
6994 } else if (name->Equals(v8_str("B"))) {
6995 return v8::FunctionTemplate::New(
6996 isolate, CallFun, v8::Integer::New(isolate, 7));
6997 } else if (name->Equals(v8_str("C"))) {
6998 return v8::FunctionTemplate::New(
6999 isolate, CallFun, v8::Integer::New(isolate, 6));
7001 return v8::Handle<v8::FunctionTemplate>();
7006 THREADED_TEST(FunctionLookup) {
7007 v8::RegisterExtension(new FunctionExtension());
7008 v8::HandleScope handle_scope(CcTest::isolate());
7009 static const char* exts[1] = { "functiontest" };
7010 v8::ExtensionConfiguration config(1, exts);
7011 LocalContext context(&config);
7012 CHECK_EQ(3, lookup_count);
7013 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7014 CompileRun("Foo(0)"));
7015 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7016 CompileRun("Foo(1)"));
7017 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7018 CompileRun("Foo(2)"));
7022 THREADED_TEST(NativeFunctionConstructCall) {
7023 v8::RegisterExtension(new FunctionExtension());
7024 v8::HandleScope handle_scope(CcTest::isolate());
7025 static const char* exts[1] = { "functiontest" };
7026 v8::ExtensionConfiguration config(1, exts);
7027 LocalContext context(&config);
7028 for (int i = 0; i < 10; i++) {
7029 // Run a few times to ensure that allocation of objects doesn't
7030 // change behavior of a constructor function.
7031 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7032 CompileRun("(new A()).data"));
7033 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7034 CompileRun("(new B()).data"));
7035 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7036 CompileRun("(new C()).data"));
7041 static const char* last_location;
7042 static const char* last_message;
7043 void StoringErrorCallback(const char* location, const char* message) {
7044 if (last_location == NULL) {
7045 last_location = location;
7046 last_message = message;
7051 // ErrorReporting creates a circular extensions configuration and
7052 // tests that the fatal error handler gets called. This renders V8
7053 // unusable and therefore this test cannot be run in parallel.
7054 TEST(ErrorReporting) {
7055 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7056 static const char* aDeps[] = { "B" };
7057 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7058 static const char* bDeps[] = { "A" };
7059 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7060 last_location = NULL;
7061 v8::ExtensionConfiguration config(1, bDeps);
7062 v8::Handle<Context> context =
7063 Context::New(CcTest::isolate(), &config);
7064 CHECK(context.IsEmpty());
7065 CHECK_NE(last_location, NULL);
7069 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7070 v8::Handle<Value> data) {
7071 CHECK(message->GetScriptResourceName()->IsUndefined());
7072 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7073 message->GetLineNumber();
7074 message->GetSourceLine();
7078 THREADED_TEST(ErrorWithMissingScriptInfo) {
7079 LocalContext context;
7080 v8::HandleScope scope(context->GetIsolate());
7081 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7082 CompileRun("throw Error()");
7083 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7087 struct FlagAndPersistent {
7089 v8::Persistent<v8::Object> handle;
7093 static void DisposeAndSetFlag(
7094 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7095 data.GetParameter()->handle.Reset();
7096 data.GetParameter()->flag = true;
7100 THREADED_TEST(IndependentWeakHandle) {
7101 v8::Isolate* iso = CcTest::isolate();
7102 v8::HandleScope scope(iso);
7103 v8::Handle<Context> context = Context::New(iso);
7104 Context::Scope context_scope(context);
7106 FlagAndPersistent object_a, object_b;
7109 v8::HandleScope handle_scope(iso);
7110 object_a.handle.Reset(iso, v8::Object::New(iso));
7111 object_b.handle.Reset(iso, v8::Object::New(iso));
7114 object_a.flag = false;
7115 object_b.flag = false;
7116 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7117 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7118 CHECK(!object_b.handle.IsIndependent());
7119 object_a.handle.MarkIndependent();
7120 object_b.handle.MarkIndependent();
7121 CHECK(object_b.handle.IsIndependent());
7122 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7123 CHECK(object_a.flag);
7124 CHECK(object_b.flag);
7128 static void InvokeScavenge() {
7129 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7133 static void InvokeMarkSweep() {
7134 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7138 static void ForceScavenge(
7139 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7140 data.GetParameter()->handle.Reset();
7141 data.GetParameter()->flag = true;
7146 static void ForceMarkSweep(
7147 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7148 data.GetParameter()->handle.Reset();
7149 data.GetParameter()->flag = true;
7154 THREADED_TEST(GCFromWeakCallbacks) {
7155 v8::Isolate* isolate = CcTest::isolate();
7156 v8::HandleScope scope(isolate);
7157 v8::Handle<Context> context = Context::New(isolate);
7158 Context::Scope context_scope(context);
7160 static const int kNumberOfGCTypes = 2;
7161 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7163 Callback gc_forcing_callback[kNumberOfGCTypes] =
7164 {&ForceScavenge, &ForceMarkSweep};
7166 typedef void (*GCInvoker)();
7167 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7169 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7170 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7171 FlagAndPersistent object;
7173 v8::HandleScope handle_scope(isolate);
7174 object.handle.Reset(isolate, v8::Object::New(isolate));
7176 object.flag = false;
7177 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7178 object.handle.MarkIndependent();
7179 invoke_gc[outer_gc]();
7186 static void RevivingCallback(
7187 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7188 data.GetParameter()->handle.ClearWeak();
7189 data.GetParameter()->flag = true;
7193 THREADED_TEST(IndependentHandleRevival) {
7194 v8::Isolate* isolate = CcTest::isolate();
7195 v8::HandleScope scope(isolate);
7196 v8::Handle<Context> context = Context::New(isolate);
7197 Context::Scope context_scope(context);
7199 FlagAndPersistent object;
7201 v8::HandleScope handle_scope(isolate);
7202 v8::Local<v8::Object> o = v8::Object::New(isolate);
7203 object.handle.Reset(isolate, o);
7204 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7205 v8::Local<String> y_str = v8_str("y");
7206 o->Set(y_str, y_str);
7208 object.flag = false;
7209 object.handle.SetWeak(&object, &RevivingCallback);
7210 object.handle.MarkIndependent();
7211 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7213 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7215 v8::HandleScope handle_scope(isolate);
7216 v8::Local<v8::Object> o =
7217 v8::Local<v8::Object>::New(isolate, object.handle);
7218 v8::Local<String> y_str = v8_str("y");
7219 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7220 CHECK(o->Get(y_str)->Equals(y_str));
7225 v8::Handle<Function> args_fun;
7228 static void ArgumentsTestCallback(
7229 const v8::FunctionCallbackInfo<v8::Value>& args) {
7230 ApiTestFuzzer::Fuzz();
7231 v8::Isolate* isolate = args.GetIsolate();
7232 CHECK_EQ(args_fun, args.Callee());
7233 CHECK_EQ(3, args.Length());
7234 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7235 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7236 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7237 CHECK_EQ(v8::Undefined(isolate), args[3]);
7238 v8::HandleScope scope(args.GetIsolate());
7239 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7243 THREADED_TEST(Arguments) {
7244 v8::Isolate* isolate = CcTest::isolate();
7245 v8::HandleScope scope(isolate);
7246 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7247 global->Set(v8_str("f"),
7248 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7249 LocalContext context(NULL, global);
7250 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7251 v8_compile("f(1, 2, 3)")->Run();
7255 static void NoBlockGetterX(Local<String> name,
7256 const v8::PropertyCallbackInfo<v8::Value>&) {
7260 static void NoBlockGetterI(uint32_t index,
7261 const v8::PropertyCallbackInfo<v8::Value>&) {
7265 static void PDeleter(Local<String> name,
7266 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7267 if (!name->Equals(v8_str("foo"))) {
7268 return; // not intercepted
7271 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7275 static void IDeleter(uint32_t index,
7276 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7278 return; // not intercepted
7281 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7285 THREADED_TEST(Deleter) {
7286 v8::Isolate* isolate = CcTest::isolate();
7287 v8::HandleScope scope(isolate);
7288 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7289 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7290 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7291 LocalContext context;
7292 context->Global()->Set(v8_str("k"), obj->NewInstance());
7298 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7299 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7301 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7302 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7304 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7305 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7307 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7308 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7312 static void GetK(Local<String> name,
7313 const v8::PropertyCallbackInfo<v8::Value>& info) {
7314 ApiTestFuzzer::Fuzz();
7315 if (name->Equals(v8_str("foo")) ||
7316 name->Equals(v8_str("bar")) ||
7317 name->Equals(v8_str("baz"))) {
7318 info.GetReturnValue().SetUndefined();
7323 static void IndexedGetK(uint32_t index,
7324 const v8::PropertyCallbackInfo<v8::Value>& info) {
7325 ApiTestFuzzer::Fuzz();
7326 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7330 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7331 ApiTestFuzzer::Fuzz();
7332 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7333 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7334 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7335 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7336 info.GetReturnValue().Set(result);
7340 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7341 ApiTestFuzzer::Fuzz();
7342 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7343 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7344 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7345 info.GetReturnValue().Set(result);
7349 THREADED_TEST(Enumerators) {
7350 v8::Isolate* isolate = CcTest::isolate();
7351 v8::HandleScope scope(isolate);
7352 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7353 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7354 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7355 LocalContext context;
7356 context->Global()->Set(v8_str("k"), obj->NewInstance());
7357 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7362 "k[4294967295] = 0;"
7364 "k[4294967296] = 0;"
7368 "k[30000000000] = 0;"
7371 "for (var prop in k) {"
7372 " result.push(prop);"
7375 // Check that we get all the property names returned including the
7376 // ones from the enumerators in the right order: indexed properties
7377 // in numerical order, indexed interceptor properties, named
7378 // properties in insertion order, named interceptor properties.
7379 // This order is not mandated by the spec, so this test is just
7380 // documenting our behavior.
7381 CHECK_EQ(17, result->Length());
7382 // Indexed properties in numerical order.
7383 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7384 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7385 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7386 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7387 // Indexed interceptor properties in the order they are returned
7388 // from the enumerator interceptor.
7389 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7390 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7391 // Named properties in insertion order.
7392 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7393 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7394 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7395 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7396 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7397 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7398 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7399 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7400 // Named interceptor properties.
7401 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7402 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7403 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7408 int p_getter_count2;
7411 static void PGetter(Local<String> name,
7412 const v8::PropertyCallbackInfo<v8::Value>& info) {
7413 ApiTestFuzzer::Fuzz();
7415 v8::Handle<v8::Object> global =
7416 info.GetIsolate()->GetCurrentContext()->Global();
7417 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7418 if (name->Equals(v8_str("p1"))) {
7419 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7420 } else if (name->Equals(v8_str("p2"))) {
7421 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7422 } else if (name->Equals(v8_str("p3"))) {
7423 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7424 } else if (name->Equals(v8_str("p4"))) {
7425 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7430 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7431 ApiTestFuzzer::Fuzz();
7432 LocalContext context;
7433 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7435 "o1.__proto__ = { };"
7436 "var o2 = { __proto__: o1 };"
7437 "var o3 = { __proto__: o2 };"
7438 "var o4 = { __proto__: o3 };"
7439 "for (var i = 0; i < 10; i++) o4.p4;"
7440 "for (var i = 0; i < 10; i++) o3.p3;"
7441 "for (var i = 0; i < 10; i++) o2.p2;"
7442 "for (var i = 0; i < 10; i++) o1.p1;");
7446 static void PGetter2(Local<String> name,
7447 const v8::PropertyCallbackInfo<v8::Value>& info) {
7448 ApiTestFuzzer::Fuzz();
7450 v8::Handle<v8::Object> global =
7451 info.GetIsolate()->GetCurrentContext()->Global();
7452 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7453 if (name->Equals(v8_str("p1"))) {
7454 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7455 } else if (name->Equals(v8_str("p2"))) {
7456 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7457 } else if (name->Equals(v8_str("p3"))) {
7458 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7459 } else if (name->Equals(v8_str("p4"))) {
7460 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7465 THREADED_TEST(GetterHolders) {
7466 v8::Isolate* isolate = CcTest::isolate();
7467 v8::HandleScope scope(isolate);
7468 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7469 obj->SetAccessor(v8_str("p1"), PGetter);
7470 obj->SetAccessor(v8_str("p2"), PGetter);
7471 obj->SetAccessor(v8_str("p3"), PGetter);
7472 obj->SetAccessor(v8_str("p4"), PGetter);
7475 CHECK_EQ(40, p_getter_count);
7479 THREADED_TEST(PreInterceptorHolders) {
7480 v8::Isolate* isolate = CcTest::isolate();
7481 v8::HandleScope scope(isolate);
7482 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7483 obj->SetNamedPropertyHandler(PGetter2);
7484 p_getter_count2 = 0;
7486 CHECK_EQ(40, p_getter_count2);
7490 THREADED_TEST(ObjectInstantiation) {
7491 v8::Isolate* isolate = CcTest::isolate();
7492 v8::HandleScope scope(isolate);
7493 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7494 templ->SetAccessor(v8_str("t"), PGetter2);
7495 LocalContext context;
7496 context->Global()->Set(v8_str("o"), templ->NewInstance());
7497 for (int i = 0; i < 100; i++) {
7498 v8::HandleScope inner_scope(CcTest::isolate());
7499 v8::Handle<v8::Object> obj = templ->NewInstance();
7500 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7501 context->Global()->Set(v8_str("o2"), obj);
7502 v8::Handle<Value> value =
7503 CompileRun("o.__proto__ === o2.__proto__");
7504 CHECK_EQ(v8::True(isolate), value);
7505 context->Global()->Set(v8_str("o"), obj);
7510 static int StrCmp16(uint16_t* a, uint16_t* b) {
7512 if (*a == 0 && *b == 0) return 0;
7513 if (*a != *b) return 0 + *a - *b;
7520 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7522 if (n-- == 0) return 0;
7523 if (*a == 0 && *b == 0) return 0;
7524 if (*a != *b) return 0 + *a - *b;
7531 int GetUtf8Length(Handle<String> str) {
7532 int len = str->Utf8Length();
7534 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7535 i::FlattenString(istr);
7536 len = str->Utf8Length();
7542 THREADED_TEST(StringWrite) {
7543 LocalContext context;
7544 v8::HandleScope scope(context->GetIsolate());
7545 v8::Handle<String> str = v8_str("abcde");
7546 // abc<Icelandic eth><Unicode snowman>.
7547 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7548 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7549 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7550 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7551 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7552 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7553 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7554 // single lead surrogate
7555 uint16_t lead[1] = { 0xd800 };
7556 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7557 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7558 // single trail surrogate
7559 uint16_t trail[1] = { 0xdc00 };
7560 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7561 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7563 uint16_t pair[2] = { 0xd800, 0xdc00 };
7564 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7565 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7566 const int kStride = 4; // Must match stride in for loops in JS below.
7569 "for (var i = 0; i < 0xd800; i += 4) {"
7570 " left = left + String.fromCharCode(i);"
7574 "for (var i = 0; i < 0xd800; i += 4) {"
7575 " right = String.fromCharCode(i) + right;"
7577 v8::Handle<v8::Object> global = context->Global();
7578 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7579 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7581 CHECK_EQ(5, str2->Length());
7582 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7583 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7586 char utf8buf[0xd800 * 3];
7591 memset(utf8buf, 0x1, 1000);
7592 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7594 CHECK_EQ(5, charlen);
7595 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7597 memset(utf8buf, 0x1, 1000);
7598 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7600 CHECK_EQ(5, charlen);
7601 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7603 memset(utf8buf, 0x1, 1000);
7604 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7606 CHECK_EQ(4, charlen);
7607 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7609 memset(utf8buf, 0x1, 1000);
7610 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7612 CHECK_EQ(4, charlen);
7613 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7615 memset(utf8buf, 0x1, 1000);
7616 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7618 CHECK_EQ(4, charlen);
7619 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7621 memset(utf8buf, 0x1, 1000);
7622 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7624 CHECK_EQ(3, charlen);
7625 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7627 memset(utf8buf, 0x1, 1000);
7628 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7630 CHECK_EQ(3, charlen);
7631 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7633 memset(utf8buf, 0x1, 1000);
7634 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7636 CHECK_EQ(2, charlen);
7637 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7639 // allow orphan surrogates by default
7640 memset(utf8buf, 0x1, 1000);
7641 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7643 CHECK_EQ(8, charlen);
7644 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7646 // replace orphan surrogates with unicode replacement character
7647 memset(utf8buf, 0x1, 1000);
7648 len = orphans_str->WriteUtf8(utf8buf,
7651 String::REPLACE_INVALID_UTF8);
7653 CHECK_EQ(8, charlen);
7654 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7656 // replace single lead surrogate with unicode replacement character
7657 memset(utf8buf, 0x1, 1000);
7658 len = lead_str->WriteUtf8(utf8buf,
7661 String::REPLACE_INVALID_UTF8);
7663 CHECK_EQ(1, charlen);
7664 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7666 // replace single trail surrogate with unicode replacement character
7667 memset(utf8buf, 0x1, 1000);
7668 len = trail_str->WriteUtf8(utf8buf,
7671 String::REPLACE_INVALID_UTF8);
7673 CHECK_EQ(1, charlen);
7674 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7676 // do not replace / write anything if surrogate pair does not fit the buffer
7678 memset(utf8buf, 0x1, 1000);
7679 len = pair_str->WriteUtf8(utf8buf,
7682 String::REPLACE_INVALID_UTF8);
7684 CHECK_EQ(0, charlen);
7686 memset(utf8buf, 0x1, sizeof(utf8buf));
7687 len = GetUtf8Length(left_tree);
7689 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7690 CHECK_EQ(utf8_expected, len);
7691 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7692 CHECK_EQ(utf8_expected, len);
7693 CHECK_EQ(0xd800 / kStride, charlen);
7694 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7695 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7696 CHECK_EQ(0xc0 - kStride,
7697 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7698 CHECK_EQ(1, utf8buf[utf8_expected]);
7700 memset(utf8buf, 0x1, sizeof(utf8buf));
7701 len = GetUtf8Length(right_tree);
7702 CHECK_EQ(utf8_expected, len);
7703 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7704 CHECK_EQ(utf8_expected, len);
7705 CHECK_EQ(0xd800 / kStride, charlen);
7706 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7707 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7708 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7709 CHECK_EQ(1, utf8buf[utf8_expected]);
7711 memset(buf, 0x1, sizeof(buf));
7712 memset(wbuf, 0x1, sizeof(wbuf));
7713 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7715 len = str->Write(wbuf);
7717 CHECK_EQ(0, strcmp("abcde", buf));
7718 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7719 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7721 memset(buf, 0x1, sizeof(buf));
7722 memset(wbuf, 0x1, sizeof(wbuf));
7723 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7725 len = str->Write(wbuf, 0, 4);
7727 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7728 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7729 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7731 memset(buf, 0x1, sizeof(buf));
7732 memset(wbuf, 0x1, sizeof(wbuf));
7733 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7735 len = str->Write(wbuf, 0, 5);
7737 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7738 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7739 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7741 memset(buf, 0x1, sizeof(buf));
7742 memset(wbuf, 0x1, sizeof(wbuf));
7743 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7745 len = str->Write(wbuf, 0, 6);
7747 CHECK_EQ(0, strcmp("abcde", buf));
7748 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7749 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7751 memset(buf, 0x1, sizeof(buf));
7752 memset(wbuf, 0x1, sizeof(wbuf));
7753 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7755 len = str->Write(wbuf, 4, -1);
7757 CHECK_EQ(0, strcmp("e", buf));
7758 uint16_t answer5[] = {'e', '\0'};
7759 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7761 memset(buf, 0x1, sizeof(buf));
7762 memset(wbuf, 0x1, sizeof(wbuf));
7763 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7765 len = str->Write(wbuf, 4, 6);
7767 CHECK_EQ(0, strcmp("e", buf));
7768 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7770 memset(buf, 0x1, sizeof(buf));
7771 memset(wbuf, 0x1, sizeof(wbuf));
7772 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7774 len = str->Write(wbuf, 4, 1);
7776 CHECK_EQ(0, strncmp("e\1", buf, 2));
7777 uint16_t answer6[] = {'e', 0x101};
7778 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7780 memset(buf, 0x1, sizeof(buf));
7781 memset(wbuf, 0x1, sizeof(wbuf));
7782 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7784 len = str->Write(wbuf, 3, 1);
7786 CHECK_EQ(0, strncmp("d\1", buf, 2));
7787 uint16_t answer7[] = {'d', 0x101};
7788 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7790 memset(wbuf, 0x1, sizeof(wbuf));
7792 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7794 CHECK_EQ('X', wbuf[5]);
7795 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7796 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7797 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7798 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7800 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7802 memset(buf, 0x1, sizeof(buf));
7804 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7807 String::NO_NULL_TERMINATION);
7809 CHECK_EQ('X', buf[5]);
7810 CHECK_EQ(0, strncmp("abcde", buf, 5));
7811 CHECK_NE(0, strcmp("abcde", buf));
7813 CHECK_EQ(0, strcmp("abcde", buf));
7815 memset(utf8buf, 0x1, sizeof(utf8buf));
7817 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7818 String::NO_NULL_TERMINATION);
7820 CHECK_EQ('X', utf8buf[8]);
7821 CHECK_EQ(5, charlen);
7822 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7823 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7825 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7827 memset(utf8buf, 0x1, sizeof(utf8buf));
7829 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7830 String::NO_NULL_TERMINATION);
7832 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7833 CHECK_EQ(5, charlen);
7835 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7837 memset(buf, 0x1, sizeof(buf));
7838 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7840 CHECK_EQ(0, strcmp("abc", buf));
7841 CHECK_EQ(0, buf[3]);
7842 CHECK_EQ(0, strcmp("def", buf + 4));
7844 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7845 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7846 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7850 static void Utf16Helper(
7851 LocalContext& context,
7853 const char* lengths_name,
7855 Local<v8::Array> a =
7856 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7857 Local<v8::Array> alens =
7858 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7859 for (int i = 0; i < len; i++) {
7860 Local<v8::String> string =
7861 Local<v8::String>::Cast(a->Get(i));
7862 Local<v8::Number> expected_len =
7863 Local<v8::Number>::Cast(alens->Get(i));
7864 int length = GetUtf8Length(string);
7865 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7870 static uint16_t StringGet(Handle<String> str, int index) {
7871 i::Handle<i::String> istring =
7872 v8::Utils::OpenHandle(String::Cast(*str));
7873 return istring->Get(index);
7877 static void WriteUtf8Helper(
7878 LocalContext& context,
7880 const char* lengths_name,
7882 Local<v8::Array> b =
7883 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7884 Local<v8::Array> alens =
7885 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7888 for (int i = 0; i < len; i++) {
7889 Local<v8::String> string =
7890 Local<v8::String>::Cast(b->Get(i));
7891 Local<v8::Number> expected_len =
7892 Local<v8::Number>::Cast(alens->Get(i));
7893 int utf8_length = static_cast<int>(expected_len->Value());
7894 for (int j = utf8_length + 1; j >= 0; j--) {
7895 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7896 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7899 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7901 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7902 CHECK_GE(utf8_length + 1, utf8_written);
7903 CHECK_GE(utf8_length, utf8_written2);
7904 for (int k = 0; k < utf8_written2; k++) {
7905 CHECK_EQ(buffer[k], buffer2[k]);
7907 CHECK(nchars * 3 >= utf8_written - 1);
7908 CHECK(nchars <= utf8_written);
7909 if (j == utf8_length + 1) {
7910 CHECK_EQ(utf8_written2, utf8_length);
7911 CHECK_EQ(utf8_written2 + 1, utf8_written);
7913 CHECK_EQ(buffer[utf8_written], 42);
7914 if (j > utf8_length) {
7915 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7916 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7917 Handle<String> roundtrip = v8_str(buffer);
7918 CHECK(roundtrip->Equals(string));
7920 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7922 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7924 uint16_t trail = StringGet(string, nchars - 1);
7925 uint16_t lead = StringGet(string, nchars - 2);
7926 if (((lead & 0xfc00) == 0xd800) &&
7927 ((trail & 0xfc00) == 0xdc00)) {
7928 unsigned char u1 = buffer2[utf8_written2 - 4];
7929 unsigned char u2 = buffer2[utf8_written2 - 3];
7930 unsigned char u3 = buffer2[utf8_written2 - 2];
7931 unsigned char u4 = buffer2[utf8_written2 - 1];
7932 CHECK_EQ((u1 & 0xf8), 0xf0);
7933 CHECK_EQ((u2 & 0xc0), 0x80);
7934 CHECK_EQ((u3 & 0xc0), 0x80);
7935 CHECK_EQ((u4 & 0xc0), 0x80);
7936 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7937 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7938 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7939 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7940 CHECK_EQ((u1 & 0x3), c >> 18);
7948 THREADED_TEST(Utf16) {
7949 LocalContext context;
7950 v8::HandleScope scope(context->GetIsolate());
7952 "var pad = '01234567890123456789';"
7954 "var plens = [20, 3, 3];"
7955 "p.push('01234567890123456789');"
7956 "var lead = 0xd800;"
7957 "var trail = 0xdc00;"
7958 "p.push(String.fromCharCode(0xd800));"
7959 "p.push(String.fromCharCode(0xdc00));"
7964 "for (var i = 0; i < 3; i++) {"
7965 " p[1] = String.fromCharCode(lead++);"
7966 " for (var j = 0; j < 3; j++) {"
7967 " p[2] = String.fromCharCode(trail++);"
7968 " a.push(p[i] + p[j]);"
7969 " b.push(p[i] + p[j]);"
7970 " c.push(p[i] + p[j]);"
7971 " alens.push(plens[i] + plens[j]);"
7974 "alens[5] -= 2;" // Here the surrogate pairs match up.
7979 "for (var m = 0; m < 9; m++) {"
7980 " for (var n = 0; n < 9; n++) {"
7981 " a2.push(a[m] + a[n]);"
7982 " b2.push(b[m] + b[n]);"
7983 " var newc = 'x' + c[m] + c[n] + 'y';"
7984 " c2.push(newc.substring(1, newc.length - 1));"
7985 " var utf = alens[m] + alens[n];" // And here.
7986 // The 'n's that start with 0xdc.. are 6-8
7987 // The 'm's that end with 0xd8.. are 1, 4 and 7
7988 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7989 " a2lens.push(utf);"
7992 Utf16Helper(context, "a", "alens", 9);
7993 Utf16Helper(context, "a2", "a2lens", 81);
7994 WriteUtf8Helper(context, "b", "alens", 9);
7995 WriteUtf8Helper(context, "b2", "a2lens", 81);
7996 WriteUtf8Helper(context, "c2", "a2lens", 81);
8000 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8001 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8002 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8003 return *is1 == *is2;
8006 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8008 Handle<String> symbol1 =
8009 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8010 Handle<String> symbol2 =
8011 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8012 CHECK(SameSymbol(symbol1, symbol2));
8016 THREADED_TEST(Utf16Symbol) {
8017 LocalContext context;
8018 v8::HandleScope scope(context->GetIsolate());
8020 Handle<String> symbol1 = v8::String::NewFromUtf8(
8021 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8022 Handle<String> symbol2 = v8::String::NewFromUtf8(
8023 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8024 CHECK(SameSymbol(symbol1, symbol2));
8026 SameSymbolHelper(context->GetIsolate(),
8027 "\360\220\220\205", // 4 byte encoding.
8028 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8029 SameSymbolHelper(context->GetIsolate(),
8030 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8031 "\360\220\220\206"); // 4 byte encoding.
8032 SameSymbolHelper(context->GetIsolate(),
8033 "x\360\220\220\205", // 4 byte encoding.
8034 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8035 SameSymbolHelper(context->GetIsolate(),
8036 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8037 "x\360\220\220\206"); // 4 byte encoding.
8039 "var sym0 = 'benedictus';"
8040 "var sym0b = 'S\303\270ren';"
8041 "var sym1 = '\355\240\201\355\260\207';"
8042 "var sym2 = '\360\220\220\210';"
8043 "var sym3 = 'x\355\240\201\355\260\207';"
8044 "var sym4 = 'x\360\220\220\210';"
8045 "if (sym1.length != 2) throw sym1;"
8046 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8047 "if (sym2.length != 2) throw sym2;"
8048 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8049 "if (sym3.length != 3) throw sym3;"
8050 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8051 "if (sym4.length != 3) throw sym4;"
8052 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8053 Handle<String> sym0 = v8::String::NewFromUtf8(
8054 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8055 Handle<String> sym0b = v8::String::NewFromUtf8(
8056 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8057 Handle<String> sym1 =
8058 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8059 v8::String::kInternalizedString);
8060 Handle<String> sym2 =
8061 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8062 v8::String::kInternalizedString);
8063 Handle<String> sym3 = v8::String::NewFromUtf8(
8064 context->GetIsolate(), "x\355\240\201\355\260\207",
8065 v8::String::kInternalizedString);
8066 Handle<String> sym4 =
8067 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8068 v8::String::kInternalizedString);
8069 v8::Local<v8::Object> global = context->Global();
8070 Local<Value> s0 = global->Get(v8_str("sym0"));
8071 Local<Value> s0b = global->Get(v8_str("sym0b"));
8072 Local<Value> s1 = global->Get(v8_str("sym1"));
8073 Local<Value> s2 = global->Get(v8_str("sym2"));
8074 Local<Value> s3 = global->Get(v8_str("sym3"));
8075 Local<Value> s4 = global->Get(v8_str("sym4"));
8076 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8077 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8078 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8079 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8080 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8081 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8085 THREADED_TEST(ToArrayIndex) {
8086 LocalContext context;
8087 v8::Isolate* isolate = context->GetIsolate();
8088 v8::HandleScope scope(isolate);
8090 v8::Handle<String> str = v8_str("42");
8091 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8092 CHECK(!index.IsEmpty());
8093 CHECK_EQ(42.0, index->Uint32Value());
8094 str = v8_str("42asdf");
8095 index = str->ToArrayIndex();
8096 CHECK(index.IsEmpty());
8097 str = v8_str("-42");
8098 index = str->ToArrayIndex();
8099 CHECK(index.IsEmpty());
8100 str = v8_str("4294967295");
8101 index = str->ToArrayIndex();
8102 CHECK(!index.IsEmpty());
8103 CHECK_EQ(4294967295.0, index->Uint32Value());
8104 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8105 index = num->ToArrayIndex();
8106 CHECK(!index.IsEmpty());
8107 CHECK_EQ(1.0, index->Uint32Value());
8108 num = v8::Number::New(isolate, -1);
8109 index = num->ToArrayIndex();
8110 CHECK(index.IsEmpty());
8111 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8112 index = obj->ToArrayIndex();
8113 CHECK(index.IsEmpty());
8117 THREADED_TEST(ErrorConstruction) {
8118 LocalContext context;
8119 v8::HandleScope scope(context->GetIsolate());
8121 v8::Handle<String> foo = v8_str("foo");
8122 v8::Handle<String> message = v8_str("message");
8123 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8124 CHECK(range_error->IsObject());
8125 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8126 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8127 CHECK(reference_error->IsObject());
8128 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8129 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8130 CHECK(syntax_error->IsObject());
8131 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8132 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8133 CHECK(type_error->IsObject());
8134 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8135 v8::Handle<Value> error = v8::Exception::Error(foo);
8136 CHECK(error->IsObject());
8137 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8141 static void YGetter(Local<String> name,
8142 const v8::PropertyCallbackInfo<v8::Value>& info) {
8143 ApiTestFuzzer::Fuzz();
8144 info.GetReturnValue().Set(v8_num(10));
8148 static void YSetter(Local<String> name,
8150 const v8::PropertyCallbackInfo<void>& info) {
8151 if (info.This()->Has(name)) {
8152 info.This()->Delete(name);
8154 info.This()->Set(name, value);
8158 THREADED_TEST(DeleteAccessor) {
8159 v8::Isolate* isolate = CcTest::isolate();
8160 v8::HandleScope scope(isolate);
8161 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8162 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8163 LocalContext context;
8164 v8::Handle<v8::Object> holder = obj->NewInstance();
8165 context->Global()->Set(v8_str("holder"), holder);
8166 v8::Handle<Value> result = CompileRun(
8167 "holder.y = 11; holder.y = 12; holder.y");
8168 CHECK_EQ(12, result->Uint32Value());
8172 THREADED_TEST(TypeSwitch) {
8173 v8::Isolate* isolate = CcTest::isolate();
8174 v8::HandleScope scope(isolate);
8175 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8176 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8177 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8178 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8179 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8180 LocalContext context;
8181 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8182 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8183 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8184 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8185 for (int i = 0; i < 10; i++) {
8186 CHECK_EQ(0, type_switch->match(obj0));
8187 CHECK_EQ(1, type_switch->match(obj1));
8188 CHECK_EQ(2, type_switch->match(obj2));
8189 CHECK_EQ(3, type_switch->match(obj3));
8190 CHECK_EQ(3, type_switch->match(obj3));
8191 CHECK_EQ(2, type_switch->match(obj2));
8192 CHECK_EQ(1, type_switch->match(obj1));
8193 CHECK_EQ(0, type_switch->match(obj0));
8198 // For use within the TestSecurityHandler() test.
8199 static bool g_security_callback_result = false;
8200 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8202 v8::AccessType type,
8203 Local<Value> data) {
8204 // Always allow read access.
8205 if (type == v8::ACCESS_GET)
8208 // Sometimes allow other access.
8209 return g_security_callback_result;
8213 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8215 v8::AccessType type,
8216 Local<Value> data) {
8217 // Always allow read access.
8218 if (type == v8::ACCESS_GET)
8221 // Sometimes allow other access.
8222 return g_security_callback_result;
8226 static int trouble_nesting = 0;
8227 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8228 ApiTestFuzzer::Fuzz();
8231 // Call a JS function that throws an uncaught exception.
8232 Local<v8::Object> arg_this =
8233 args.GetIsolate()->GetCurrentContext()->Global();
8234 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8235 arg_this->Get(v8_str("trouble_callee")) :
8236 arg_this->Get(v8_str("trouble_caller"));
8237 CHECK(trouble_callee->IsFunction());
8238 args.GetReturnValue().Set(
8239 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8243 static int report_count = 0;
8244 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8245 v8::Handle<Value>) {
8250 // Counts uncaught exceptions, but other tests running in parallel
8251 // also have uncaught exceptions.
8252 TEST(ApiUncaughtException) {
8255 v8::Isolate* isolate = env->GetIsolate();
8256 v8::HandleScope scope(isolate);
8257 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8259 Local<v8::FunctionTemplate> fun =
8260 v8::FunctionTemplate::New(isolate, TroubleCallback);
8261 v8::Local<v8::Object> global = env->Global();
8262 global->Set(v8_str("trouble"), fun->GetFunction());
8265 "function trouble_callee() {"
8269 "function trouble_caller() {"
8272 Local<Value> trouble = global->Get(v8_str("trouble"));
8273 CHECK(trouble->IsFunction());
8274 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8275 CHECK(trouble_callee->IsFunction());
8276 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8277 CHECK(trouble_caller->IsFunction());
8278 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8279 CHECK_EQ(1, report_count);
8280 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8283 static const char* script_resource_name = "ExceptionInNativeScript.js";
8284 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8285 v8::Handle<Value>) {
8286 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8287 CHECK(!name_val.IsEmpty() && name_val->IsString());
8288 v8::String::Utf8Value name(message->GetScriptResourceName());
8289 CHECK_EQ(script_resource_name, *name);
8290 CHECK_EQ(3, message->GetLineNumber());
8291 v8::String::Utf8Value source_line(message->GetSourceLine());
8292 CHECK_EQ(" new o.foo();", *source_line);
8296 TEST(ExceptionInNativeScript) {
8298 v8::Isolate* isolate = env->GetIsolate();
8299 v8::HandleScope scope(isolate);
8300 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8302 Local<v8::FunctionTemplate> fun =
8303 v8::FunctionTemplate::New(isolate, TroubleCallback);
8304 v8::Local<v8::Object> global = env->Global();
8305 global->Set(v8_str("trouble"), fun->GetFunction());
8307 CompileRunWithOrigin(
8308 "function trouble() {\n"
8312 script_resource_name);
8313 Local<Value> trouble = global->Get(v8_str("trouble"));
8314 CHECK(trouble->IsFunction());
8315 Function::Cast(*trouble)->Call(global, 0, NULL);
8316 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8320 TEST(CompilationErrorUsingTryCatchHandler) {
8322 v8::HandleScope scope(env->GetIsolate());
8323 v8::TryCatch try_catch;
8324 v8_compile("This doesn't &*&@#$&*^ compile.");
8325 CHECK_NE(NULL, *try_catch.Exception());
8326 CHECK(try_catch.HasCaught());
8330 TEST(TryCatchFinallyUsingTryCatchHandler) {
8332 v8::HandleScope scope(env->GetIsolate());
8333 v8::TryCatch try_catch;
8334 CompileRun("try { throw ''; } catch (e) {}");
8335 CHECK(!try_catch.HasCaught());
8336 CompileRun("try { throw ''; } finally {}");
8337 CHECK(try_catch.HasCaught());
8341 "try { throw ''; } finally { return; }"
8343 CHECK(!try_catch.HasCaught());
8346 " { try { throw ''; } finally { throw 0; }"
8348 CHECK(try_catch.HasCaught());
8352 // SecurityHandler can't be run twice
8353 TEST(SecurityHandler) {
8354 v8::Isolate* isolate = CcTest::isolate();
8355 v8::HandleScope scope0(isolate);
8356 v8::Handle<v8::ObjectTemplate> global_template =
8357 v8::ObjectTemplate::New(isolate);
8358 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8359 IndexedSecurityTestCallback);
8360 // Create an environment
8361 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8364 v8::Handle<v8::Object> global0 = context0->Global();
8365 v8::Handle<Script> script0 = v8_compile("foo = 111");
8367 global0->Set(v8_str("0"), v8_num(999));
8368 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8369 CHECK_EQ(111, foo0->Int32Value());
8370 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8371 CHECK_EQ(999, z0->Int32Value());
8373 // Create another environment, should fail security checks.
8374 v8::HandleScope scope1(isolate);
8376 v8::Handle<Context> context1 =
8377 Context::New(isolate, NULL, global_template);
8380 v8::Handle<v8::Object> global1 = context1->Global();
8381 global1->Set(v8_str("othercontext"), global0);
8382 // This set will fail the security check.
8383 v8::Handle<Script> script1 =
8384 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8386 // This read will pass the security check.
8387 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8388 CHECK_EQ(111, foo1->Int32Value());
8389 // This read will pass the security check.
8390 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8391 CHECK_EQ(999, z1->Int32Value());
8393 // Create another environment, should pass security checks.
8394 { g_security_callback_result = true; // allow security handler to pass.
8395 v8::HandleScope scope2(isolate);
8396 LocalContext context2;
8397 v8::Handle<v8::Object> global2 = context2->Global();
8398 global2->Set(v8_str("othercontext"), global0);
8399 v8::Handle<Script> script2 =
8400 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8402 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8403 CHECK_EQ(333, foo2->Int32Value());
8404 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8405 CHECK_EQ(888, z2->Int32Value());
8413 THREADED_TEST(SecurityChecks) {
8415 v8::HandleScope handle_scope(env1->GetIsolate());
8416 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8418 Local<Value> foo = v8_str("foo");
8419 Local<Value> bar = v8_str("bar");
8421 // Set to the same domain.
8422 env1->SetSecurityToken(foo);
8424 // Create a function in env1.
8425 CompileRun("spy=function(){return spy;}");
8426 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8427 CHECK(spy->IsFunction());
8429 // Create another function accessing global objects.
8430 CompileRun("spy2=function(){return new this.Array();}");
8431 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8432 CHECK(spy2->IsFunction());
8434 // Switch to env2 in the same domain and invoke spy on env2.
8436 env2->SetSecurityToken(foo);
8438 Context::Scope scope_env2(env2);
8439 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8440 CHECK(result->IsFunction());
8444 env2->SetSecurityToken(bar);
8445 Context::Scope scope_env2(env2);
8447 // Call cross_domain_call, it should throw an exception
8448 v8::TryCatch try_catch;
8449 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8450 CHECK(try_catch.HasCaught());
8455 // Regression test case for issue 1183439.
8456 THREADED_TEST(SecurityChecksForPrototypeChain) {
8457 LocalContext current;
8458 v8::HandleScope scope(current->GetIsolate());
8459 v8::Handle<Context> other = Context::New(current->GetIsolate());
8461 // Change context to be able to get to the Object function in the
8462 // other context without hitting the security checks.
8463 v8::Local<Value> other_object;
8464 { Context::Scope scope(other);
8465 other_object = other->Global()->Get(v8_str("Object"));
8466 other->Global()->Set(v8_num(42), v8_num(87));
8469 current->Global()->Set(v8_str("other"), other->Global());
8470 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8472 // Make sure the security check fails here and we get an undefined
8473 // result instead of getting the Object function. Repeat in a loop
8474 // to make sure to exercise the IC code.
8475 v8::Local<Script> access_other0 = v8_compile("other.Object");
8476 v8::Local<Script> access_other1 = v8_compile("other[42]");
8477 for (int i = 0; i < 5; i++) {
8478 CHECK(!access_other0->Run()->Equals(other_object));
8479 CHECK(access_other0->Run()->IsUndefined());
8480 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8481 CHECK(access_other1->Run()->IsUndefined());
8484 // Create an object that has 'other' in its prototype chain and make
8485 // sure we cannot access the Object function indirectly through
8486 // that. Repeat in a loop to make sure to exercise the IC code.
8487 v8_compile("function F() { };"
8488 "F.prototype = other;"
8489 "var f = new F();")->Run();
8490 v8::Local<Script> access_f0 = v8_compile("f.Object");
8491 v8::Local<Script> access_f1 = v8_compile("f[42]");
8492 for (int j = 0; j < 5; j++) {
8493 CHECK(!access_f0->Run()->Equals(other_object));
8494 CHECK(access_f0->Run()->IsUndefined());
8495 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8496 CHECK(access_f1->Run()->IsUndefined());
8499 // Now it gets hairy: Set the prototype for the other global object
8500 // to be the current global object. The prototype chain for 'f' now
8501 // goes through 'other' but ends up in the current global object.
8502 { Context::Scope scope(other);
8503 other->Global()->Set(v8_str("__proto__"), current->Global());
8505 // Set a named and an index property on the current global
8506 // object. To force the lookup to go through the other global object,
8507 // the properties must not exist in the other global object.
8508 current->Global()->Set(v8_str("foo"), v8_num(100));
8509 current->Global()->Set(v8_num(99), v8_num(101));
8510 // Try to read the properties from f and make sure that the access
8511 // gets stopped by the security checks on the other global object.
8512 Local<Script> access_f2 = v8_compile("f.foo");
8513 Local<Script> access_f3 = v8_compile("f[99]");
8514 for (int k = 0; k < 5; k++) {
8515 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8516 CHECK(access_f2->Run()->IsUndefined());
8517 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8518 CHECK(access_f3->Run()->IsUndefined());
8523 THREADED_TEST(CrossDomainDelete) {
8525 v8::HandleScope handle_scope(env1->GetIsolate());
8526 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8528 Local<Value> foo = v8_str("foo");
8529 Local<Value> bar = v8_str("bar");
8531 // Set to the same domain.
8532 env1->SetSecurityToken(foo);
8533 env2->SetSecurityToken(foo);
8535 env1->Global()->Set(v8_str("prop"), v8_num(3));
8536 env2->Global()->Set(v8_str("env1"), env1->Global());
8538 // Change env2 to a different domain and delete env1.prop.
8539 env2->SetSecurityToken(bar);
8541 Context::Scope scope_env2(env2);
8542 Local<Value> result =
8543 CompileRun("delete env1.prop");
8544 CHECK(result->IsFalse());
8547 // Check that env1.prop still exists.
8548 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8549 CHECK(v->IsNumber());
8550 CHECK_EQ(3, v->Int32Value());
8554 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8556 v8::HandleScope handle_scope(env1->GetIsolate());
8557 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8559 Local<Value> foo = v8_str("foo");
8560 Local<Value> bar = v8_str("bar");
8562 // Set to the same domain.
8563 env1->SetSecurityToken(foo);
8564 env2->SetSecurityToken(foo);
8566 env1->Global()->Set(v8_str("prop"), v8_num(3));
8567 env2->Global()->Set(v8_str("env1"), env1->Global());
8569 // env1.prop is enumerable in env2.
8570 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8572 Context::Scope scope_env2(env2);
8573 Local<Value> result = CompileRun(test);
8574 CHECK(result->IsTrue());
8577 // Change env2 to a different domain and test again.
8578 env2->SetSecurityToken(bar);
8580 Context::Scope scope_env2(env2);
8581 Local<Value> result = CompileRun(test);
8582 CHECK(result->IsFalse());
8587 THREADED_TEST(CrossDomainForIn) {
8589 v8::HandleScope handle_scope(env1->GetIsolate());
8590 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8592 Local<Value> foo = v8_str("foo");
8593 Local<Value> bar = v8_str("bar");
8595 // Set to the same domain.
8596 env1->SetSecurityToken(foo);
8597 env2->SetSecurityToken(foo);
8599 env1->Global()->Set(v8_str("prop"), v8_num(3));
8600 env2->Global()->Set(v8_str("env1"), env1->Global());
8602 // Change env2 to a different domain and set env1's global object
8603 // as the __proto__ of an object in env2 and enumerate properties
8604 // in for-in. It shouldn't enumerate properties on env1's global
8606 env2->SetSecurityToken(bar);
8608 Context::Scope scope_env2(env2);
8609 Local<Value> result =
8610 CompileRun("(function(){var obj = {'__proto__':env1};"
8611 "for (var p in obj)"
8612 " if (p == 'prop') return false;"
8613 "return true;})()");
8614 CHECK(result->IsTrue());
8619 TEST(ContextDetachGlobal) {
8621 v8::HandleScope handle_scope(env1->GetIsolate());
8622 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8624 Local<v8::Object> global1 = env1->Global();
8626 Local<Value> foo = v8_str("foo");
8628 // Set to the same domain.
8629 env1->SetSecurityToken(foo);
8630 env2->SetSecurityToken(foo);
8635 // Create a function in env2 and add a reference to it in env1.
8636 Local<v8::Object> global2 = env2->Global();
8637 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8638 CompileRun("function getProp() {return prop;}");
8640 env1->Global()->Set(v8_str("getProp"),
8641 global2->Get(v8_str("getProp")));
8643 // Detach env2's global, and reuse the global object of env2
8645 env2->DetachGlobal();
8647 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8649 v8::Handle<v8::ObjectTemplate>(),
8651 env3->SetSecurityToken(v8_str("bar"));
8654 Local<v8::Object> global3 = env3->Global();
8655 CHECK_EQ(global2, global3);
8656 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8657 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8658 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8659 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8662 // Call getProp in env1, and it should return the value 1
8664 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8665 CHECK(get_prop->IsFunction());
8666 v8::TryCatch try_catch;
8667 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8668 CHECK(!try_catch.HasCaught());
8669 CHECK_EQ(1, r->Int32Value());
8672 // Check that env3 is not accessible from env1
8674 Local<Value> r = global3->Get(v8_str("prop2"));
8675 CHECK(r->IsUndefined());
8680 TEST(DetachGlobal) {
8682 v8::HandleScope scope(env1->GetIsolate());
8684 // Create second environment.
8685 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8687 Local<Value> foo = v8_str("foo");
8689 // Set same security token for env1 and env2.
8690 env1->SetSecurityToken(foo);
8691 env2->SetSecurityToken(foo);
8693 // Create a property on the global object in env2.
8695 v8::Context::Scope scope(env2);
8696 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8699 // Create a reference to env2 global from env1 global.
8700 env1->Global()->Set(v8_str("other"), env2->Global());
8702 // Check that we have access to other.p in env2 from env1.
8703 Local<Value> result = CompileRun("other.p");
8704 CHECK(result->IsInt32());
8705 CHECK_EQ(42, result->Int32Value());
8707 // Hold on to global from env2 and detach global from env2.
8708 Local<v8::Object> global2 = env2->Global();
8709 env2->DetachGlobal();
8711 // Check that the global has been detached. No other.p property can
8713 result = CompileRun("other.p");
8714 CHECK(result->IsUndefined());
8716 // Reuse global2 for env3.
8717 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8719 v8::Handle<v8::ObjectTemplate>(),
8721 CHECK_EQ(global2, env3->Global());
8723 // Start by using the same security token for env3 as for env1 and env2.
8724 env3->SetSecurityToken(foo);
8726 // Create a property on the global object in env3.
8728 v8::Context::Scope scope(env3);
8729 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8732 // Check that other.p is now the property in env3 and that we have access.
8733 result = CompileRun("other.p");
8734 CHECK(result->IsInt32());
8735 CHECK_EQ(24, result->Int32Value());
8737 // Change security token for env3 to something different from env1 and env2.
8738 env3->SetSecurityToken(v8_str("bar"));
8740 // Check that we do not have access to other.p in env1. |other| is now
8741 // the global object for env3 which has a different security token,
8742 // so access should be blocked.
8743 result = CompileRun("other.p");
8744 CHECK(result->IsUndefined());
8748 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8749 info.GetReturnValue().Set(
8750 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8754 TEST(DetachedAccesses) {
8756 v8::HandleScope scope(env1->GetIsolate());
8758 // Create second environment.
8759 Local<ObjectTemplate> inner_global_template =
8760 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8761 inner_global_template ->SetAccessorProperty(
8762 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8763 v8::Local<Context> env2 =
8764 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8766 Local<Value> foo = v8_str("foo");
8768 // Set same security token for env1 and env2.
8769 env1->SetSecurityToken(foo);
8770 env2->SetSecurityToken(foo);
8772 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8775 v8::Context::Scope scope(env2);
8776 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8778 "function bound_x() { return x; }"
8779 "function get_x() { return this.x; }"
8780 "function get_x_w() { return (function() {return this.x;})(); }");
8781 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8782 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8783 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8784 env1->Global()->Set(
8786 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8789 Local<Object> env2_global = env2->Global();
8790 env2_global->TurnOnAccessCheck();
8791 env2->DetachGlobal();
8793 Local<Value> result;
8794 result = CompileRun("bound_x()");
8795 CHECK_EQ(v8_str("env2_x"), result);
8796 result = CompileRun("get_x()");
8797 CHECK(result->IsUndefined());
8798 result = CompileRun("get_x_w()");
8799 CHECK(result->IsUndefined());
8800 result = CompileRun("this_x()");
8801 CHECK_EQ(v8_str("env2_x"), result);
8803 // Reattach env2's proxy
8804 env2 = Context::New(env1->GetIsolate(),
8806 v8::Handle<v8::ObjectTemplate>(),
8808 env2->SetSecurityToken(foo);
8810 v8::Context::Scope scope(env2);
8811 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8812 env2->Global()->Set(v8_str("env1"), env1->Global());
8813 result = CompileRun(
8815 "for (var i = 0; i < 4; i++ ) {"
8816 " results.push(env1.bound_x());"
8817 " results.push(env1.get_x());"
8818 " results.push(env1.get_x_w());"
8819 " results.push(env1.this_x());"
8822 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8823 CHECK_EQ(16, results->Length());
8824 for (int i = 0; i < 16; i += 4) {
8825 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8826 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8827 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8828 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8832 result = CompileRun(
8834 "for (var i = 0; i < 4; i++ ) {"
8835 " results.push(bound_x());"
8836 " results.push(get_x());"
8837 " results.push(get_x_w());"
8838 " results.push(this_x());"
8841 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8842 CHECK_EQ(16, results->Length());
8843 for (int i = 0; i < 16; i += 4) {
8844 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8845 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8846 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8847 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8850 result = CompileRun(
8852 "for (var i = 0; i < 4; i++ ) {"
8853 " results.push(this.bound_x());"
8854 " results.push(this.get_x());"
8855 " results.push(this.get_x_w());"
8856 " results.push(this.this_x());"
8859 results = Local<v8::Array>::Cast(result);
8860 CHECK_EQ(16, results->Length());
8861 for (int i = 0; i < 16; i += 4) {
8862 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8863 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8864 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8865 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8870 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8871 static bool NamedAccessBlocker(Local<v8::Object> global,
8873 v8::AccessType type,
8874 Local<Value> data) {
8875 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8876 allowed_access_type[type];
8880 static bool IndexedAccessBlocker(Local<v8::Object> global,
8882 v8::AccessType type,
8883 Local<Value> data) {
8884 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8885 allowed_access_type[type];
8889 static int g_echo_value_1 = -1;
8890 static int g_echo_value_2 = -1;
8893 static void EchoGetter(
8895 const v8::PropertyCallbackInfo<v8::Value>& info) {
8896 info.GetReturnValue().Set(v8_num(g_echo_value_1));
8900 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8901 info.GetReturnValue().Set(v8_num(g_echo_value_2));
8905 static void EchoSetter(Local<String> name,
8907 const v8::PropertyCallbackInfo<void>&) {
8908 if (value->IsNumber())
8909 g_echo_value_1 = value->Int32Value();
8913 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8914 v8::Handle<v8::Value> value = info[0];
8915 if (value->IsNumber())
8916 g_echo_value_2 = value->Int32Value();
8920 static void UnreachableGetter(
8922 const v8::PropertyCallbackInfo<v8::Value>& info) {
8923 CHECK(false); // This function should not be called..
8927 static void UnreachableSetter(Local<String>,
8929 const v8::PropertyCallbackInfo<void>&) {
8930 CHECK(false); // This function should nto be called.
8934 static void UnreachableFunction(
8935 const v8::FunctionCallbackInfo<v8::Value>& info) {
8936 CHECK(false); // This function should not be called..
8940 TEST(AccessControl) {
8941 v8::Isolate* isolate = CcTest::isolate();
8942 v8::HandleScope handle_scope(isolate);
8943 v8::Handle<v8::ObjectTemplate> global_template =
8944 v8::ObjectTemplate::New(isolate);
8946 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8947 IndexedAccessBlocker);
8949 // Add an accessor accessible by cross-domain JS code.
8950 global_template->SetAccessor(
8951 v8_str("accessible_prop"),
8952 EchoGetter, EchoSetter,
8953 v8::Handle<Value>(),
8954 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8957 global_template->SetAccessorProperty(
8958 v8_str("accessible_js_prop"),
8959 v8::FunctionTemplate::New(isolate, EchoGetter),
8960 v8::FunctionTemplate::New(isolate, EchoSetter),
8962 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8964 // Add an accessor that is not accessible by cross-domain JS code.
8965 global_template->SetAccessor(v8_str("blocked_prop"),
8966 UnreachableGetter, UnreachableSetter,
8967 v8::Handle<Value>(),
8970 global_template->SetAccessorProperty(
8971 v8_str("blocked_js_prop"),
8972 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8973 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8977 // Create an environment
8978 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8981 v8::Handle<v8::Object> global0 = context0->Global();
8983 // Define a property with JS getter and setter.
8985 "function getter() { return 'getter'; };\n"
8986 "function setter() { return 'setter'; }\n"
8987 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8989 Local<Value> getter = global0->Get(v8_str("getter"));
8990 Local<Value> setter = global0->Get(v8_str("setter"));
8992 // And define normal element.
8993 global0->Set(239, v8_str("239"));
8995 // Define an element with JS getter and setter.
8997 "function el_getter() { return 'el_getter'; };\n"
8998 "function el_setter() { return 'el_setter'; };\n"
8999 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9001 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9002 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9004 v8::HandleScope scope1(isolate);
9006 v8::Local<Context> context1 = Context::New(isolate);
9009 v8::Handle<v8::Object> global1 = context1->Global();
9010 global1->Set(v8_str("other"), global0);
9012 // Access blocked property.
9013 CompileRun("other.blocked_prop = 1");
9015 ExpectUndefined("other.blocked_prop");
9017 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9018 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9020 // Enable ACCESS_HAS
9021 allowed_access_type[v8::ACCESS_HAS] = true;
9022 ExpectUndefined("other.blocked_prop");
9023 // ... and now we can get the descriptor...
9025 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9026 // ... and enumerate the property.
9027 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9028 allowed_access_type[v8::ACCESS_HAS] = false;
9030 // Access blocked element.
9031 CompileRun("other[239] = 1");
9033 ExpectUndefined("other[239]");
9034 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9035 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9037 // Enable ACCESS_HAS
9038 allowed_access_type[v8::ACCESS_HAS] = true;
9039 ExpectUndefined("other[239]");
9040 // ... and now we can get the descriptor...
9041 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9042 // ... and enumerate the property.
9043 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9044 allowed_access_type[v8::ACCESS_HAS] = false;
9046 // Access a property with JS accessor.
9047 CompileRun("other.js_accessor_p = 2");
9049 ExpectUndefined("other.js_accessor_p");
9051 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9053 // Enable ACCESS_HAS.
9054 allowed_access_type[v8::ACCESS_HAS] = true;
9055 ExpectUndefined("other.js_accessor_p");
9057 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9059 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9061 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9062 allowed_access_type[v8::ACCESS_HAS] = false;
9064 // Enable both ACCESS_HAS and ACCESS_GET.
9065 allowed_access_type[v8::ACCESS_HAS] = true;
9066 allowed_access_type[v8::ACCESS_GET] = true;
9068 ExpectString("other.js_accessor_p", "getter");
9070 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9072 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9074 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9076 allowed_access_type[v8::ACCESS_GET] = false;
9077 allowed_access_type[v8::ACCESS_HAS] = false;
9079 // Enable both ACCESS_HAS and ACCESS_SET.
9080 allowed_access_type[v8::ACCESS_HAS] = true;
9081 allowed_access_type[v8::ACCESS_SET] = true;
9083 ExpectUndefined("other.js_accessor_p");
9085 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9087 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9089 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9091 allowed_access_type[v8::ACCESS_SET] = false;
9092 allowed_access_type[v8::ACCESS_HAS] = false;
9094 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9095 allowed_access_type[v8::ACCESS_HAS] = true;
9096 allowed_access_type[v8::ACCESS_GET] = true;
9097 allowed_access_type[v8::ACCESS_SET] = true;
9099 ExpectString("other.js_accessor_p", "getter");
9101 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9103 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9105 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9107 allowed_access_type[v8::ACCESS_SET] = false;
9108 allowed_access_type[v8::ACCESS_GET] = false;
9109 allowed_access_type[v8::ACCESS_HAS] = false;
9111 // Access an element with JS accessor.
9112 CompileRun("other[42] = 2");
9114 ExpectUndefined("other[42]");
9115 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9117 // Enable ACCESS_HAS.
9118 allowed_access_type[v8::ACCESS_HAS] = true;
9119 ExpectUndefined("other[42]");
9120 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9121 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9122 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9123 allowed_access_type[v8::ACCESS_HAS] = false;
9125 // Enable both ACCESS_HAS and ACCESS_GET.
9126 allowed_access_type[v8::ACCESS_HAS] = true;
9127 allowed_access_type[v8::ACCESS_GET] = true;
9129 ExpectString("other[42]", "el_getter");
9130 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9131 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9132 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9134 allowed_access_type[v8::ACCESS_GET] = false;
9135 allowed_access_type[v8::ACCESS_HAS] = false;
9137 // Enable both ACCESS_HAS and ACCESS_SET.
9138 allowed_access_type[v8::ACCESS_HAS] = true;
9139 allowed_access_type[v8::ACCESS_SET] = true;
9141 ExpectUndefined("other[42]");
9142 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9143 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9144 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9146 allowed_access_type[v8::ACCESS_SET] = false;
9147 allowed_access_type[v8::ACCESS_HAS] = false;
9149 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9150 allowed_access_type[v8::ACCESS_HAS] = true;
9151 allowed_access_type[v8::ACCESS_GET] = true;
9152 allowed_access_type[v8::ACCESS_SET] = true;
9154 ExpectString("other[42]", "el_getter");
9155 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9156 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9157 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9159 allowed_access_type[v8::ACCESS_SET] = false;
9160 allowed_access_type[v8::ACCESS_GET] = false;
9161 allowed_access_type[v8::ACCESS_HAS] = false;
9163 v8::Handle<Value> value;
9165 // Access accessible property
9166 value = CompileRun("other.accessible_prop = 3");
9167 CHECK(value->IsNumber());
9168 CHECK_EQ(3, value->Int32Value());
9169 CHECK_EQ(3, g_echo_value_1);
9171 // Access accessible js property
9172 value = CompileRun("other.accessible_js_prop = 3");
9173 CHECK(value->IsNumber());
9174 CHECK_EQ(3, value->Int32Value());
9175 CHECK_EQ(3, g_echo_value_2);
9177 value = CompileRun("other.accessible_prop");
9178 CHECK(value->IsNumber());
9179 CHECK_EQ(3, value->Int32Value());
9181 value = CompileRun("other.accessible_js_prop");
9182 CHECK(value->IsNumber());
9183 CHECK_EQ(3, value->Int32Value());
9186 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9187 CHECK(value->IsNumber());
9188 CHECK_EQ(3, value->Int32Value());
9191 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9192 CHECK(value->IsNumber());
9193 CHECK_EQ(3, value->Int32Value());
9195 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9196 CHECK(value->IsTrue());
9198 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9199 CHECK(value->IsTrue());
9201 // Enumeration doesn't enumerate accessors from inaccessible objects in
9202 // the prototype chain even if the accessors are in themselves accessible.
9204 CompileRun("(function(){var obj = {'__proto__':other};"
9205 "for (var p in obj)"
9206 " if (p == 'accessible_prop' ||"
9207 " p == 'accessible_js_prop' ||"
9208 " p == 'blocked_js_prop' ||"
9209 " p == 'blocked_js_prop') {"
9212 "return true;})()");
9213 CHECK(value->IsTrue());
9220 TEST(AccessControlES5) {
9221 v8::Isolate* isolate = CcTest::isolate();
9222 v8::HandleScope handle_scope(isolate);
9223 v8::Handle<v8::ObjectTemplate> global_template =
9224 v8::ObjectTemplate::New(isolate);
9226 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9227 IndexedAccessBlocker);
9229 // Add accessible accessor.
9230 global_template->SetAccessor(
9231 v8_str("accessible_prop"),
9232 EchoGetter, EchoSetter,
9233 v8::Handle<Value>(),
9234 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9237 // Add an accessor that is not accessible by cross-domain JS code.
9238 global_template->SetAccessor(v8_str("blocked_prop"),
9239 UnreachableGetter, UnreachableSetter,
9240 v8::Handle<Value>(),
9243 // Create an environment
9244 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9247 v8::Handle<v8::Object> global0 = context0->Global();
9249 v8::Local<Context> context1 = Context::New(isolate);
9251 v8::Handle<v8::Object> global1 = context1->Global();
9252 global1->Set(v8_str("other"), global0);
9254 // Regression test for issue 1154.
9255 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9257 ExpectUndefined("other.blocked_prop");
9259 // Regression test for issue 1027.
9260 CompileRun("Object.defineProperty(\n"
9261 " other, 'blocked_prop', {configurable: false})");
9262 ExpectUndefined("other.blocked_prop");
9264 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9266 // Regression test for issue 1171.
9267 ExpectTrue("Object.isExtensible(other)");
9268 CompileRun("Object.preventExtensions(other)");
9269 ExpectTrue("Object.isExtensible(other)");
9271 // Object.seal and Object.freeze.
9272 CompileRun("Object.freeze(other)");
9273 ExpectTrue("Object.isExtensible(other)");
9275 CompileRun("Object.seal(other)");
9276 ExpectTrue("Object.isExtensible(other)");
9278 // Regression test for issue 1250.
9279 // Make sure that we can set the accessible accessors value using normal
9281 CompileRun("other.accessible_prop = 42");
9282 CHECK_EQ(42, g_echo_value_1);
9284 v8::Handle<Value> value;
9285 // We follow Safari in ignoring assignments to host object accessors.
9286 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9287 value = CompileRun("other.accessible_prop == 42");
9288 CHECK(value->IsTrue());
9292 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9294 v8::AccessType type,
9295 Local<Value> data) {
9300 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9302 v8::AccessType type,
9303 Local<Value> data) {
9308 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9309 v8::Isolate* isolate = CcTest::isolate();
9310 v8::HandleScope handle_scope(isolate);
9311 v8::Handle<v8::ObjectTemplate> obj_template =
9312 v8::ObjectTemplate::New(isolate);
9314 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9315 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9316 GetOwnPropertyNamesIndexedBlocker);
9318 // Create an environment
9319 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9322 v8::Handle<v8::Object> global0 = context0->Global();
9324 v8::HandleScope scope1(CcTest::isolate());
9326 v8::Local<Context> context1 = Context::New(isolate);
9329 v8::Handle<v8::Object> global1 = context1->Global();
9330 global1->Set(v8_str("other"), global0);
9331 global1->Set(v8_str("object"), obj_template->NewInstance());
9333 v8::Handle<Value> value;
9335 // Attempt to get the property names of the other global object and
9336 // of an object that requires access checks. Accessing the other
9337 // global object should be blocked by access checks on the global
9338 // proxy object. Accessing the object that requires access checks
9339 // is blocked by the access checks on the object itself.
9340 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9341 CHECK(value->IsTrue());
9343 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9344 CHECK(value->IsTrue());
9351 static void IndexedPropertyEnumerator(
9352 const v8::PropertyCallbackInfo<v8::Array>& info) {
9353 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9354 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9355 result->Set(1, v8::Object::New(info.GetIsolate()));
9356 info.GetReturnValue().Set(result);
9360 static void NamedPropertyEnumerator(
9361 const v8::PropertyCallbackInfo<v8::Array>& info) {
9362 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9363 result->Set(0, v8_str("x"));
9364 result->Set(1, v8::Object::New(info.GetIsolate()));
9365 info.GetReturnValue().Set(result);
9369 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9370 v8::Isolate* isolate = CcTest::isolate();
9371 v8::HandleScope handle_scope(isolate);
9372 v8::Handle<v8::ObjectTemplate> obj_template =
9373 v8::ObjectTemplate::New(isolate);
9375 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9376 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9377 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9378 IndexedPropertyEnumerator);
9379 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9380 NamedPropertyEnumerator);
9382 LocalContext context;
9383 v8::Handle<v8::Object> global = context->Global();
9384 global->Set(v8_str("object"), obj_template->NewInstance());
9386 v8::Handle<v8::Value> result =
9387 CompileRun("Object.getOwnPropertyNames(object)");
9388 CHECK(result->IsArray());
9389 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9390 CHECK_EQ(3, result_array->Length());
9391 CHECK(result_array->Get(0)->IsString());
9392 CHECK(result_array->Get(1)->IsString());
9393 CHECK(result_array->Get(2)->IsString());
9394 CHECK_EQ(v8_str("7"), result_array->Get(0));
9395 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9396 CHECK_EQ(v8_str("x"), result_array->Get(2));
9400 static void ConstTenGetter(Local<String> name,
9401 const v8::PropertyCallbackInfo<v8::Value>& info) {
9402 info.GetReturnValue().Set(v8_num(10));
9406 THREADED_TEST(CrossDomainAccessors) {
9407 v8::Isolate* isolate = CcTest::isolate();
9408 v8::HandleScope handle_scope(isolate);
9410 v8::Handle<v8::FunctionTemplate> func_template =
9411 v8::FunctionTemplate::New(isolate);
9413 v8::Handle<v8::ObjectTemplate> global_template =
9414 func_template->InstanceTemplate();
9416 v8::Handle<v8::ObjectTemplate> proto_template =
9417 func_template->PrototypeTemplate();
9419 // Add an accessor to proto that's accessible by cross-domain JS code.
9420 proto_template->SetAccessor(v8_str("accessible"),
9422 v8::Handle<Value>(),
9425 // Add an accessor that is not accessible by cross-domain JS code.
9426 global_template->SetAccessor(v8_str("unreachable"),
9427 UnreachableGetter, 0,
9428 v8::Handle<Value>(),
9431 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9434 Local<v8::Object> global = context0->Global();
9435 // Add a normal property that shadows 'accessible'
9436 global->Set(v8_str("accessible"), v8_num(11));
9438 // Enter a new context.
9439 v8::HandleScope scope1(CcTest::isolate());
9440 v8::Local<Context> context1 = Context::New(isolate);
9443 v8::Handle<v8::Object> global1 = context1->Global();
9444 global1->Set(v8_str("other"), global);
9446 // Should return 10, instead of 11
9447 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9448 CHECK(value->IsNumber());
9449 CHECK_EQ(10, value->Int32Value());
9451 value = v8_compile("other.unreachable")->Run();
9452 CHECK(value->IsUndefined());
9459 static int named_access_count = 0;
9460 static int indexed_access_count = 0;
9462 static bool NamedAccessCounter(Local<v8::Object> global,
9464 v8::AccessType type,
9465 Local<Value> data) {
9466 named_access_count++;
9471 static bool IndexedAccessCounter(Local<v8::Object> global,
9473 v8::AccessType type,
9474 Local<Value> data) {
9475 indexed_access_count++;
9480 // This one is too easily disturbed by other tests.
9481 TEST(AccessControlIC) {
9482 named_access_count = 0;
9483 indexed_access_count = 0;
9485 v8::Isolate* isolate = CcTest::isolate();
9486 v8::HandleScope handle_scope(isolate);
9488 // Create an environment.
9489 v8::Local<Context> context0 = Context::New(isolate);
9492 // Create an object that requires access-check functions to be
9493 // called for cross-domain access.
9494 v8::Handle<v8::ObjectTemplate> object_template =
9495 v8::ObjectTemplate::New(isolate);
9496 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9497 IndexedAccessCounter);
9498 Local<v8::Object> object = object_template->NewInstance();
9500 v8::HandleScope scope1(isolate);
9502 // Create another environment.
9503 v8::Local<Context> context1 = Context::New(isolate);
9506 // Make easy access to the object from the other environment.
9507 v8::Handle<v8::Object> global1 = context1->Global();
9508 global1->Set(v8_str("obj"), object);
9510 v8::Handle<Value> value;
9512 // Check that the named access-control function is called every time.
9513 CompileRun("function testProp(obj) {"
9514 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9515 " for (var j = 0; j < 10; j++) obj.prop;"
9518 value = CompileRun("testProp(obj)");
9519 CHECK(value->IsNumber());
9520 CHECK_EQ(1, value->Int32Value());
9521 CHECK_EQ(21, named_access_count);
9523 // Check that the named access-control function is called every time.
9524 CompileRun("var p = 'prop';"
9525 "function testKeyed(obj) {"
9526 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9527 " for (var j = 0; j < 10; j++) obj[p];"
9530 // Use obj which requires access checks. No inline caching is used
9532 value = CompileRun("testKeyed(obj)");
9533 CHECK(value->IsNumber());
9534 CHECK_EQ(1, value->Int32Value());
9535 CHECK_EQ(42, named_access_count);
9536 // Force the inline caches into generic state and try again.
9537 CompileRun("testKeyed({ a: 0 })");
9538 CompileRun("testKeyed({ b: 0 })");
9539 value = CompileRun("testKeyed(obj)");
9540 CHECK(value->IsNumber());
9541 CHECK_EQ(1, value->Int32Value());
9542 CHECK_EQ(63, named_access_count);
9544 // Check that the indexed access-control function is called every time.
9545 CompileRun("function testIndexed(obj) {"
9546 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9547 " for (var j = 0; j < 10; j++) obj[0];"
9550 value = CompileRun("testIndexed(obj)");
9551 CHECK(value->IsNumber());
9552 CHECK_EQ(1, value->Int32Value());
9553 CHECK_EQ(21, indexed_access_count);
9554 // Force the inline caches into generic state.
9555 CompileRun("testIndexed(new Array(1))");
9556 // Test that the indexed access check is called.
9557 value = CompileRun("testIndexed(obj)");
9558 CHECK(value->IsNumber());
9559 CHECK_EQ(1, value->Int32Value());
9560 CHECK_EQ(42, indexed_access_count);
9562 // Check that the named access check is called when invoking
9563 // functions on an object that requires access checks.
9564 CompileRun("obj.f = function() {}");
9565 CompileRun("function testCallNormal(obj) {"
9566 " for (var i = 0; i < 10; i++) obj.f();"
9568 CompileRun("testCallNormal(obj)");
9569 CHECK_EQ(74, named_access_count);
9571 // Force obj into slow case.
9572 value = CompileRun("delete obj.prop");
9573 CHECK(value->BooleanValue());
9574 // Force inline caches into dictionary probing mode.
9575 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9576 // Test that the named access check is called.
9577 value = CompileRun("testProp(obj);");
9578 CHECK(value->IsNumber());
9579 CHECK_EQ(1, value->Int32Value());
9580 CHECK_EQ(96, named_access_count);
9582 // Force the call inline cache into dictionary probing mode.
9583 CompileRun("o.f = function() {}; testCallNormal(o)");
9584 // Test that the named access check is still called for each
9585 // invocation of the function.
9586 value = CompileRun("testCallNormal(obj)");
9587 CHECK_EQ(106, named_access_count);
9594 static bool NamedAccessFlatten(Local<v8::Object> global,
9596 v8::AccessType type,
9597 Local<Value> data) {
9601 CHECK(name->IsString());
9603 memset(buf, 0x1, sizeof(buf));
9604 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9609 memset(buf, 0x1, sizeof(buf));
9610 len = name.As<String>()->Write(buf2);
9617 static bool IndexedAccessFlatten(Local<v8::Object> global,
9619 v8::AccessType type,
9620 Local<Value> data) {
9625 // Regression test. In access checks, operations that may cause
9626 // garbage collection are not allowed. It used to be the case that
9627 // using the Write operation on a string could cause a garbage
9628 // collection due to flattening of the string. This is no longer the
9630 THREADED_TEST(AccessControlFlatten) {
9631 named_access_count = 0;
9632 indexed_access_count = 0;
9634 v8::Isolate* isolate = CcTest::isolate();
9635 v8::HandleScope handle_scope(isolate);
9637 // Create an environment.
9638 v8::Local<Context> context0 = Context::New(isolate);
9641 // Create an object that requires access-check functions to be
9642 // called for cross-domain access.
9643 v8::Handle<v8::ObjectTemplate> object_template =
9644 v8::ObjectTemplate::New(isolate);
9645 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9646 IndexedAccessFlatten);
9647 Local<v8::Object> object = object_template->NewInstance();
9649 v8::HandleScope scope1(isolate);
9651 // Create another environment.
9652 v8::Local<Context> context1 = Context::New(isolate);
9655 // Make easy access to the object from the other environment.
9656 v8::Handle<v8::Object> global1 = context1->Global();
9657 global1->Set(v8_str("obj"), object);
9659 v8::Handle<Value> value;
9661 value = v8_compile("var p = 'as' + 'df';")->Run();
9662 value = v8_compile("obj[p];")->Run();
9669 static void AccessControlNamedGetter(
9671 const v8::PropertyCallbackInfo<v8::Value>& info) {
9672 info.GetReturnValue().Set(42);
9676 static void AccessControlNamedSetter(
9679 const v8::PropertyCallbackInfo<v8::Value>& info) {
9680 info.GetReturnValue().Set(value);
9684 static void AccessControlIndexedGetter(
9686 const v8::PropertyCallbackInfo<v8::Value>& info) {
9687 info.GetReturnValue().Set(v8_num(42));
9691 static void AccessControlIndexedSetter(
9694 const v8::PropertyCallbackInfo<v8::Value>& info) {
9695 info.GetReturnValue().Set(value);
9699 THREADED_TEST(AccessControlInterceptorIC) {
9700 named_access_count = 0;
9701 indexed_access_count = 0;
9703 v8::Isolate* isolate = CcTest::isolate();
9704 v8::HandleScope handle_scope(isolate);
9706 // Create an environment.
9707 v8::Local<Context> context0 = Context::New(isolate);
9710 // Create an object that requires access-check functions to be
9711 // called for cross-domain access. The object also has interceptors
9713 v8::Handle<v8::ObjectTemplate> object_template =
9714 v8::ObjectTemplate::New(isolate);
9715 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9716 IndexedAccessCounter);
9717 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9718 AccessControlNamedSetter);
9719 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9720 AccessControlIndexedSetter);
9721 Local<v8::Object> object = object_template->NewInstance();
9723 v8::HandleScope scope1(isolate);
9725 // Create another environment.
9726 v8::Local<Context> context1 = Context::New(isolate);
9729 // Make easy access to the object from the other environment.
9730 v8::Handle<v8::Object> global1 = context1->Global();
9731 global1->Set(v8_str("obj"), object);
9733 v8::Handle<Value> value;
9735 // Check that the named access-control function is called every time
9736 // eventhough there is an interceptor on the object.
9737 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9738 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9740 CHECK(value->IsNumber());
9741 CHECK_EQ(42, value->Int32Value());
9742 CHECK_EQ(21, named_access_count);
9744 value = v8_compile("var p = 'x';")->Run();
9745 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9746 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9748 CHECK(value->IsNumber());
9749 CHECK_EQ(42, value->Int32Value());
9750 CHECK_EQ(42, named_access_count);
9752 // Check that the indexed access-control function is called every
9753 // time eventhough there is an interceptor on the object.
9754 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9755 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9757 CHECK(value->IsNumber());
9758 CHECK_EQ(42, value->Int32Value());
9759 CHECK_EQ(21, indexed_access_count);
9766 THREADED_TEST(Version) {
9767 v8::V8::GetVersion();
9771 static void InstanceFunctionCallback(
9772 const v8::FunctionCallbackInfo<v8::Value>& args) {
9773 ApiTestFuzzer::Fuzz();
9774 args.GetReturnValue().Set(v8_num(12));
9778 THREADED_TEST(InstanceProperties) {
9779 LocalContext context;
9780 v8::Isolate* isolate = context->GetIsolate();
9781 v8::HandleScope handle_scope(isolate);
9783 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9784 Local<ObjectTemplate> instance = t->InstanceTemplate();
9786 instance->Set(v8_str("x"), v8_num(42));
9787 instance->Set(v8_str("f"),
9788 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9790 Local<Value> o = t->GetFunction()->NewInstance();
9792 context->Global()->Set(v8_str("i"), o);
9793 Local<Value> value = CompileRun("i.x");
9794 CHECK_EQ(42, value->Int32Value());
9796 value = CompileRun("i.f()");
9797 CHECK_EQ(12, value->Int32Value());
9801 static void GlobalObjectInstancePropertiesGet(
9803 const v8::PropertyCallbackInfo<v8::Value>&) {
9804 ApiTestFuzzer::Fuzz();
9808 THREADED_TEST(GlobalObjectInstanceProperties) {
9809 v8::Isolate* isolate = CcTest::isolate();
9810 v8::HandleScope handle_scope(isolate);
9812 Local<Value> global_object;
9814 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9815 t->InstanceTemplate()->SetNamedPropertyHandler(
9816 GlobalObjectInstancePropertiesGet);
9817 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9818 instance_template->Set(v8_str("x"), v8_num(42));
9819 instance_template->Set(v8_str("f"),
9820 v8::FunctionTemplate::New(isolate,
9821 InstanceFunctionCallback));
9823 // The script to check how Crankshaft compiles missing global function
9824 // invocations. function g is not defined and should throw on call.
9825 const char* script =
9826 "function wrapper(call) {"
9827 " var x = 0, y = 1;"
9828 " for (var i = 0; i < 1000; i++) {"
9834 "for (var i = 0; i < 17; i++) wrapper(false);"
9836 "try { wrapper(true); } catch (e) { thrown = 1; };"
9840 LocalContext env(NULL, instance_template);
9841 // Hold on to the global object so it can be used again in another
9842 // environment initialization.
9843 global_object = env->Global();
9845 Local<Value> value = CompileRun("x");
9846 CHECK_EQ(42, value->Int32Value());
9847 value = CompileRun("f()");
9848 CHECK_EQ(12, value->Int32Value());
9849 value = CompileRun(script);
9850 CHECK_EQ(1, value->Int32Value());
9854 // Create new environment reusing the global object.
9855 LocalContext env(NULL, instance_template, global_object);
9856 Local<Value> value = CompileRun("x");
9857 CHECK_EQ(42, value->Int32Value());
9858 value = CompileRun("f()");
9859 CHECK_EQ(12, value->Int32Value());
9860 value = CompileRun(script);
9861 CHECK_EQ(1, value->Int32Value());
9866 THREADED_TEST(CallKnownGlobalReceiver) {
9867 v8::Isolate* isolate = CcTest::isolate();
9868 v8::HandleScope handle_scope(isolate);
9870 Local<Value> global_object;
9872 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9873 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9875 // The script to check that we leave global object not
9876 // global object proxy on stack when we deoptimize from inside
9877 // arguments evaluation.
9878 // To provoke error we need to both force deoptimization
9879 // from arguments evaluation and to force CallIC to take
9880 // CallIC_Miss code path that can't cope with global proxy.
9881 const char* script =
9882 "function bar(x, y) { try { } finally { } }"
9883 "function baz(x) { try { } finally { } }"
9884 "function bom(x) { try { } finally { } }"
9885 "function foo(x) { bar([x], bom(2)); }"
9886 "for (var i = 0; i < 10000; i++) foo(1);"
9891 LocalContext env(NULL, instance_template);
9892 // Hold on to the global object so it can be used again in another
9893 // environment initialization.
9894 global_object = env->Global();
9895 foo = CompileRun(script);
9899 // Create new environment reusing the global object.
9900 LocalContext env(NULL, instance_template, global_object);
9901 env->Global()->Set(v8_str("foo"), foo);
9902 CompileRun("foo()");
9907 static void ShadowFunctionCallback(
9908 const v8::FunctionCallbackInfo<v8::Value>& args) {
9909 ApiTestFuzzer::Fuzz();
9910 args.GetReturnValue().Set(v8_num(42));
9914 static int shadow_y;
9915 static int shadow_y_setter_call_count;
9916 static int shadow_y_getter_call_count;
9919 static void ShadowYSetter(Local<String>,
9921 const v8::PropertyCallbackInfo<void>&) {
9922 shadow_y_setter_call_count++;
9927 static void ShadowYGetter(Local<String> name,
9928 const v8::PropertyCallbackInfo<v8::Value>& info) {
9929 ApiTestFuzzer::Fuzz();
9930 shadow_y_getter_call_count++;
9931 info.GetReturnValue().Set(v8_num(shadow_y));
9935 static void ShadowIndexedGet(uint32_t index,
9936 const v8::PropertyCallbackInfo<v8::Value>&) {
9940 static void ShadowNamedGet(Local<String> key,
9941 const v8::PropertyCallbackInfo<v8::Value>&) {
9945 THREADED_TEST(ShadowObject) {
9946 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9947 v8::Isolate* isolate = CcTest::isolate();
9948 v8::HandleScope handle_scope(isolate);
9950 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9951 LocalContext context(NULL, global_template);
9953 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9954 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9955 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9956 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9957 Local<ObjectTemplate> instance = t->InstanceTemplate();
9959 proto->Set(v8_str("f"),
9960 v8::FunctionTemplate::New(isolate,
9961 ShadowFunctionCallback,
9963 proto->Set(v8_str("x"), v8_num(12));
9965 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9967 Local<Value> o = t->GetFunction()->NewInstance();
9968 context->Global()->Set(v8_str("__proto__"), o);
9970 Local<Value> value =
9971 CompileRun("this.propertyIsEnumerable(0)");
9972 CHECK(value->IsBoolean());
9973 CHECK(!value->BooleanValue());
9975 value = CompileRun("x");
9976 CHECK_EQ(12, value->Int32Value());
9978 value = CompileRun("f()");
9979 CHECK_EQ(42, value->Int32Value());
9981 CompileRun("y = 43");
9982 CHECK_EQ(1, shadow_y_setter_call_count);
9983 value = CompileRun("y");
9984 CHECK_EQ(1, shadow_y_getter_call_count);
9985 CHECK_EQ(42, value->Int32Value());
9989 THREADED_TEST(HiddenPrototype) {
9990 LocalContext context;
9991 v8::Isolate* isolate = context->GetIsolate();
9992 v8::HandleScope handle_scope(isolate);
9994 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9995 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9996 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9997 t1->SetHiddenPrototype(true);
9998 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9999 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10000 t2->SetHiddenPrototype(true);
10001 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10002 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10003 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10005 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10006 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10007 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10008 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10010 // Setting the prototype on an object skips hidden prototypes.
10011 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10012 o0->Set(v8_str("__proto__"), o1);
10013 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10014 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10015 o0->Set(v8_str("__proto__"), o2);
10016 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10017 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10018 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10019 o0->Set(v8_str("__proto__"), o3);
10020 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10021 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10022 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10023 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10025 // Getting the prototype of o0 should get the first visible one
10026 // which is o3. Therefore, z should not be defined on the prototype
10028 Local<Value> proto = o0->Get(v8_str("__proto__"));
10029 CHECK(proto->IsObject());
10030 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10034 THREADED_TEST(HiddenPrototypeSet) {
10035 LocalContext context;
10036 v8::Isolate* isolate = context->GetIsolate();
10037 v8::HandleScope handle_scope(isolate);
10039 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10040 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10041 ht->SetHiddenPrototype(true);
10042 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10043 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10045 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10046 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10047 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10048 o->Set(v8_str("__proto__"), h);
10049 h->Set(v8_str("__proto__"), p);
10051 // Setting a property that exists on the hidden prototype goes there.
10052 o->Set(v8_str("x"), v8_num(7));
10053 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10054 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10055 CHECK(p->Get(v8_str("x"))->IsUndefined());
10057 // Setting a new property should not be forwarded to the hidden prototype.
10058 o->Set(v8_str("y"), v8_num(6));
10059 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10060 CHECK(h->Get(v8_str("y"))->IsUndefined());
10061 CHECK(p->Get(v8_str("y"))->IsUndefined());
10063 // Setting a property that only exists on a prototype of the hidden prototype
10064 // is treated normally again.
10065 p->Set(v8_str("z"), v8_num(8));
10066 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10067 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10068 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10069 o->Set(v8_str("z"), v8_num(9));
10070 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10071 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10072 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10076 // Regression test for issue 2457.
10077 THREADED_TEST(HiddenPrototypeIdentityHash) {
10078 LocalContext context;
10079 v8::HandleScope handle_scope(context->GetIsolate());
10081 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10082 t->SetHiddenPrototype(true);
10083 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10084 Handle<Object> p = t->GetFunction()->NewInstance();
10085 Handle<Object> o = Object::New(context->GetIsolate());
10086 o->SetPrototype(p);
10088 int hash = o->GetIdentityHash();
10090 o->Set(v8_str("foo"), v8_num(42));
10091 ASSERT_EQ(hash, o->GetIdentityHash());
10095 THREADED_TEST(SetPrototype) {
10096 LocalContext context;
10097 v8::Isolate* isolate = context->GetIsolate();
10098 v8::HandleScope handle_scope(isolate);
10100 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10101 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10102 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10103 t1->SetHiddenPrototype(true);
10104 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10105 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10106 t2->SetHiddenPrototype(true);
10107 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10108 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10109 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10111 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10112 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10113 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10114 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10116 // Setting the prototype on an object does not skip hidden prototypes.
10117 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10118 CHECK(o0->SetPrototype(o1));
10119 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10120 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10121 CHECK(o1->SetPrototype(o2));
10122 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10123 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10124 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10125 CHECK(o2->SetPrototype(o3));
10126 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10127 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10128 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10129 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10131 // Getting the prototype of o0 should get the first visible one
10132 // which is o3. Therefore, z should not be defined on the prototype
10134 Local<Value> proto = o0->Get(v8_str("__proto__"));
10135 CHECK(proto->IsObject());
10136 CHECK_EQ(proto.As<v8::Object>(), o3);
10138 // However, Object::GetPrototype ignores hidden prototype.
10139 Local<Value> proto0 = o0->GetPrototype();
10140 CHECK(proto0->IsObject());
10141 CHECK_EQ(proto0.As<v8::Object>(), o1);
10143 Local<Value> proto1 = o1->GetPrototype();
10144 CHECK(proto1->IsObject());
10145 CHECK_EQ(proto1.As<v8::Object>(), o2);
10147 Local<Value> proto2 = o2->GetPrototype();
10148 CHECK(proto2->IsObject());
10149 CHECK_EQ(proto2.As<v8::Object>(), o3);
10153 // Getting property names of an object with a prototype chain that
10154 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10155 // crash the runtime.
10156 THREADED_TEST(Regress91517) {
10157 i::FLAG_allow_natives_syntax = true;
10158 LocalContext context;
10159 v8::Isolate* isolate = context->GetIsolate();
10160 v8::HandleScope handle_scope(isolate);
10162 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10163 t1->SetHiddenPrototype(true);
10164 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10165 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10166 t2->SetHiddenPrototype(true);
10167 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10168 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10169 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10170 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10171 t3->SetHiddenPrototype(true);
10172 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10173 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10174 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10176 // Force dictionary-based properties.
10177 i::ScopedVector<char> name_buf(1024);
10178 for (int i = 1; i <= 1000; i++) {
10179 i::OS::SNPrintF(name_buf, "sdf%d", i);
10180 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10183 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10184 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10185 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10186 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10188 // Create prototype chain of hidden prototypes.
10189 CHECK(o4->SetPrototype(o3));
10190 CHECK(o3->SetPrototype(o2));
10191 CHECK(o2->SetPrototype(o1));
10193 // Call the runtime version of GetLocalPropertyNames() on the natively
10194 // created object through JavaScript.
10195 context->Global()->Set(v8_str("obj"), o4);
10196 // PROPERTY_ATTRIBUTES_NONE = 0
10197 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10199 ExpectInt32("names.length", 1006);
10200 ExpectTrue("names.indexOf(\"baz\") >= 0");
10201 ExpectTrue("names.indexOf(\"boo\") >= 0");
10202 ExpectTrue("names.indexOf(\"foo\") >= 0");
10203 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10204 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10205 ExpectFalse("names[1005] == undefined");
10209 // Getting property names of an object with a hidden and inherited
10210 // prototype should not duplicate the accessor properties inherited.
10211 THREADED_TEST(Regress269562) {
10212 i::FLAG_allow_natives_syntax = true;
10213 LocalContext context;
10214 v8::HandleScope handle_scope(context->GetIsolate());
10216 Local<v8::FunctionTemplate> t1 =
10217 v8::FunctionTemplate::New(context->GetIsolate());
10218 t1->SetHiddenPrototype(true);
10220 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10221 i1->SetAccessor(v8_str("foo"),
10222 SimpleAccessorGetter, SimpleAccessorSetter);
10223 i1->SetAccessor(v8_str("bar"),
10224 SimpleAccessorGetter, SimpleAccessorSetter);
10225 i1->SetAccessor(v8_str("baz"),
10226 SimpleAccessorGetter, SimpleAccessorSetter);
10227 i1->Set(v8_str("n1"), v8_num(1));
10228 i1->Set(v8_str("n2"), v8_num(2));
10230 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10231 Local<v8::FunctionTemplate> t2 =
10232 v8::FunctionTemplate::New(context->GetIsolate());
10233 t2->SetHiddenPrototype(true);
10235 // Inherit from t1 and mark prototype as hidden.
10237 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10239 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10240 CHECK(o2->SetPrototype(o1));
10242 v8::Local<v8::Symbol> sym =
10243 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10244 o1->Set(sym, v8_num(3));
10245 o1->SetHiddenValue(
10246 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10248 // Call the runtime version of GetLocalPropertyNames() on
10249 // the natively created object through JavaScript.
10250 context->Global()->Set(v8_str("obj"), o2);
10251 context->Global()->Set(v8_str("sym"), sym);
10252 // PROPERTY_ATTRIBUTES_NONE = 0
10253 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10255 ExpectInt32("names.length", 7);
10256 ExpectTrue("names.indexOf(\"foo\") >= 0");
10257 ExpectTrue("names.indexOf(\"bar\") >= 0");
10258 ExpectTrue("names.indexOf(\"baz\") >= 0");
10259 ExpectTrue("names.indexOf(\"n1\") >= 0");
10260 ExpectTrue("names.indexOf(\"n2\") >= 0");
10261 ExpectTrue("names.indexOf(sym) >= 0");
10262 ExpectTrue("names.indexOf(\"mine\") >= 0");
10266 THREADED_TEST(FunctionReadOnlyPrototype) {
10267 LocalContext context;
10268 v8::Isolate* isolate = context->GetIsolate();
10269 v8::HandleScope handle_scope(isolate);
10271 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10272 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10273 t1->ReadOnlyPrototype();
10274 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10275 // Configured value of ReadOnly flag.
10278 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10279 " return (descriptor['writable'] == false);"
10280 "})()")->BooleanValue());
10281 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10283 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10285 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10286 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10287 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10288 // Default value of ReadOnly flag.
10291 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10292 " return (descriptor['writable'] == true);"
10293 "})()")->BooleanValue());
10294 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10298 THREADED_TEST(SetPrototypeThrows) {
10299 LocalContext context;
10300 v8::Isolate* isolate = context->GetIsolate();
10301 v8::HandleScope handle_scope(isolate);
10303 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10305 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10306 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10308 CHECK(o0->SetPrototype(o1));
10309 // If setting the prototype leads to the cycle, SetPrototype should
10310 // return false and keep VM in sane state.
10311 v8::TryCatch try_catch;
10312 CHECK(!o1->SetPrototype(o0));
10313 CHECK(!try_catch.HasCaught());
10314 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10316 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10320 THREADED_TEST(FunctionRemovePrototype) {
10321 LocalContext context;
10322 v8::Isolate* isolate = context->GetIsolate();
10323 v8::HandleScope handle_scope(isolate);
10325 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10326 t1->RemovePrototype();
10327 Local<v8::Function> fun = t1->GetFunction();
10328 context->Global()->Set(v8_str("fun"), fun);
10329 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10331 v8::TryCatch try_catch;
10332 CompileRun("new fun()");
10333 CHECK(try_catch.HasCaught());
10336 fun->NewInstance();
10337 CHECK(try_catch.HasCaught());
10341 THREADED_TEST(GetterSetterExceptions) {
10342 LocalContext context;
10343 v8::Isolate* isolate = context->GetIsolate();
10344 v8::HandleScope handle_scope(isolate);
10346 "function Foo() { };"
10347 "function Throw() { throw 5; };"
10349 "x.__defineSetter__('set', Throw);"
10350 "x.__defineGetter__('get', Throw);");
10351 Local<v8::Object> x =
10352 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10353 v8::TryCatch try_catch;
10354 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10355 x->Get(v8_str("get"));
10356 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10357 x->Get(v8_str("get"));
10358 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10359 x->Get(v8_str("get"));
10360 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10361 x->Get(v8_str("get"));
10365 THREADED_TEST(Constructor) {
10366 LocalContext context;
10367 v8::Isolate* isolate = context->GetIsolate();
10368 v8::HandleScope handle_scope(isolate);
10369 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10370 templ->SetClassName(v8_str("Fun"));
10371 Local<Function> cons = templ->GetFunction();
10372 context->Global()->Set(v8_str("Fun"), cons);
10373 Local<v8::Object> inst = cons->NewInstance();
10374 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10375 CHECK(obj->IsJSObject());
10376 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10377 CHECK(value->BooleanValue());
10381 static void ConstructorCallback(
10382 const v8::FunctionCallbackInfo<v8::Value>& args) {
10383 ApiTestFuzzer::Fuzz();
10384 Local<Object> This;
10386 if (args.IsConstructCall()) {
10387 Local<Object> Holder = args.Holder();
10388 This = Object::New(args.GetIsolate());
10389 Local<Value> proto = Holder->GetPrototype();
10390 if (proto->IsObject()) {
10391 This->SetPrototype(proto);
10394 This = args.This();
10397 This->Set(v8_str("a"), args[0]);
10398 args.GetReturnValue().Set(This);
10402 static void FakeConstructorCallback(
10403 const v8::FunctionCallbackInfo<v8::Value>& args) {
10404 ApiTestFuzzer::Fuzz();
10405 args.GetReturnValue().Set(args[0]);
10409 THREADED_TEST(ConstructorForObject) {
10410 LocalContext context;
10411 v8::Isolate* isolate = context->GetIsolate();
10412 v8::HandleScope handle_scope(isolate);
10414 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10415 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10416 Local<Object> instance = instance_template->NewInstance();
10417 context->Global()->Set(v8_str("obj"), instance);
10418 v8::TryCatch try_catch;
10419 Local<Value> value;
10420 CHECK(!try_catch.HasCaught());
10422 // Call the Object's constructor with a 32-bit signed integer.
10423 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10424 CHECK(!try_catch.HasCaught());
10425 CHECK(value->IsInt32());
10426 CHECK_EQ(28, value->Int32Value());
10428 Local<Value> args1[] = { v8_num(28) };
10429 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10430 CHECK(value_obj1->IsObject());
10431 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10432 value = object1->Get(v8_str("a"));
10433 CHECK(value->IsInt32());
10434 CHECK(!try_catch.HasCaught());
10435 CHECK_EQ(28, value->Int32Value());
10437 // Call the Object's constructor with a String.
10438 value = CompileRun(
10439 "(function() { var o = new obj('tipli'); return o.a; })()");
10440 CHECK(!try_catch.HasCaught());
10441 CHECK(value->IsString());
10442 String::Utf8Value string_value1(value->ToString());
10443 CHECK_EQ("tipli", *string_value1);
10445 Local<Value> args2[] = { v8_str("tipli") };
10446 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10447 CHECK(value_obj2->IsObject());
10448 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10449 value = object2->Get(v8_str("a"));
10450 CHECK(!try_catch.HasCaught());
10451 CHECK(value->IsString());
10452 String::Utf8Value string_value2(value->ToString());
10453 CHECK_EQ("tipli", *string_value2);
10455 // Call the Object's constructor with a Boolean.
10456 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10457 CHECK(!try_catch.HasCaught());
10458 CHECK(value->IsBoolean());
10459 CHECK_EQ(true, value->BooleanValue());
10461 Handle<Value> args3[] = { v8::True(isolate) };
10462 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10463 CHECK(value_obj3->IsObject());
10464 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10465 value = object3->Get(v8_str("a"));
10466 CHECK(!try_catch.HasCaught());
10467 CHECK(value->IsBoolean());
10468 CHECK_EQ(true, value->BooleanValue());
10470 // Call the Object's constructor with undefined.
10471 Handle<Value> args4[] = { v8::Undefined(isolate) };
10472 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10473 CHECK(value_obj4->IsObject());
10474 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10475 value = object4->Get(v8_str("a"));
10476 CHECK(!try_catch.HasCaught());
10477 CHECK(value->IsUndefined());
10479 // Call the Object's constructor with null.
10480 Handle<Value> args5[] = { v8::Null(isolate) };
10481 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10482 CHECK(value_obj5->IsObject());
10483 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10484 value = object5->Get(v8_str("a"));
10485 CHECK(!try_catch.HasCaught());
10486 CHECK(value->IsNull());
10489 // Check exception handling when there is no constructor set for the Object.
10490 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10491 Local<Object> instance = instance_template->NewInstance();
10492 context->Global()->Set(v8_str("obj2"), instance);
10493 v8::TryCatch try_catch;
10494 Local<Value> value;
10495 CHECK(!try_catch.HasCaught());
10497 value = CompileRun("new obj2(28)");
10498 CHECK(try_catch.HasCaught());
10499 String::Utf8Value exception_value1(try_catch.Exception());
10500 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10503 Local<Value> args[] = { v8_num(29) };
10504 value = instance->CallAsConstructor(1, args);
10505 CHECK(try_catch.HasCaught());
10506 String::Utf8Value exception_value2(try_catch.Exception());
10507 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10511 // Check the case when constructor throws exception.
10512 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10513 instance_template->SetCallAsFunctionHandler(ThrowValue);
10514 Local<Object> instance = instance_template->NewInstance();
10515 context->Global()->Set(v8_str("obj3"), instance);
10516 v8::TryCatch try_catch;
10517 Local<Value> value;
10518 CHECK(!try_catch.HasCaught());
10520 value = CompileRun("new obj3(22)");
10521 CHECK(try_catch.HasCaught());
10522 String::Utf8Value exception_value1(try_catch.Exception());
10523 CHECK_EQ("22", *exception_value1);
10526 Local<Value> args[] = { v8_num(23) };
10527 value = instance->CallAsConstructor(1, args);
10528 CHECK(try_catch.HasCaught());
10529 String::Utf8Value exception_value2(try_catch.Exception());
10530 CHECK_EQ("23", *exception_value2);
10534 // Check whether constructor returns with an object or non-object.
10535 { Local<FunctionTemplate> function_template =
10536 FunctionTemplate::New(isolate, FakeConstructorCallback);
10537 Local<Function> function = function_template->GetFunction();
10538 Local<Object> instance1 = function;
10539 context->Global()->Set(v8_str("obj4"), instance1);
10540 v8::TryCatch try_catch;
10541 Local<Value> value;
10542 CHECK(!try_catch.HasCaught());
10544 CHECK(instance1->IsObject());
10545 CHECK(instance1->IsFunction());
10547 value = CompileRun("new obj4(28)");
10548 CHECK(!try_catch.HasCaught());
10549 CHECK(value->IsObject());
10551 Local<Value> args1[] = { v8_num(28) };
10552 value = instance1->CallAsConstructor(1, args1);
10553 CHECK(!try_catch.HasCaught());
10554 CHECK(value->IsObject());
10556 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10557 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10558 Local<Object> instance2 = instance_template->NewInstance();
10559 context->Global()->Set(v8_str("obj5"), instance2);
10560 CHECK(!try_catch.HasCaught());
10562 CHECK(instance2->IsObject());
10563 CHECK(!instance2->IsFunction());
10565 value = CompileRun("new obj5(28)");
10566 CHECK(!try_catch.HasCaught());
10567 CHECK(!value->IsObject());
10569 Local<Value> args2[] = { v8_num(28) };
10570 value = instance2->CallAsConstructor(1, args2);
10571 CHECK(!try_catch.HasCaught());
10572 CHECK(!value->IsObject());
10577 THREADED_TEST(FunctionDescriptorException) {
10578 LocalContext context;
10579 v8::Isolate* isolate = context->GetIsolate();
10580 v8::HandleScope handle_scope(isolate);
10581 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10582 templ->SetClassName(v8_str("Fun"));
10583 Local<Function> cons = templ->GetFunction();
10584 context->Global()->Set(v8_str("Fun"), cons);
10585 Local<Value> value = CompileRun(
10586 "function test() {"
10588 " (new Fun()).blah()"
10590 " var str = String(e);"
10591 // " if (str.indexOf('TypeError') == -1) return 1;"
10592 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10593 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10599 CHECK_EQ(0, value->Int32Value());
10603 THREADED_TEST(EvalAliasedDynamic) {
10604 LocalContext current;
10605 v8::HandleScope scope(current->GetIsolate());
10607 // Tests where aliased eval can only be resolved dynamically.
10608 Local<Script> script = v8_compile(
10611 " with (x) { return eval('foo'); }"
10614 "result1 = f(new Object());"
10615 "result2 = f(this);"
10616 "var x = new Object();"
10617 "x.eval = function(x) { return 1; };"
10618 "result3 = f(x);");
10620 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10621 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10622 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10624 v8::TryCatch try_catch;
10625 script = v8_compile(
10628 " with (x) { return eval('bar'); }"
10630 "result4 = f(this)");
10632 CHECK(!try_catch.HasCaught());
10633 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10639 THREADED_TEST(CrossEval) {
10640 v8::HandleScope scope(CcTest::isolate());
10641 LocalContext other;
10642 LocalContext current;
10644 Local<String> token = v8_str("<security token>");
10645 other->SetSecurityToken(token);
10646 current->SetSecurityToken(token);
10648 // Set up reference from current to other.
10649 current->Global()->Set(v8_str("other"), other->Global());
10651 // Check that new variables are introduced in other context.
10652 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10654 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10655 CHECK_EQ(1234, foo->Int32Value());
10656 CHECK(!current->Global()->Has(v8_str("foo")));
10658 // Check that writing to non-existing properties introduces them in
10659 // the other context.
10660 script = v8_compile("other.eval('na = 1234')");
10662 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10663 CHECK(!current->Global()->Has(v8_str("na")));
10665 // Check that global variables in current context are not visible in other
10667 v8::TryCatch try_catch;
10668 script = v8_compile("var bar = 42; other.eval('bar');");
10669 Local<Value> result = script->Run();
10670 CHECK(try_catch.HasCaught());
10673 // Check that local variables in current context are not visible in other
10675 script = v8_compile(
10678 " return other.eval('baz');"
10680 result = script->Run();
10681 CHECK(try_catch.HasCaught());
10684 // Check that global variables in the other environment are visible
10685 // when evaluting code.
10686 other->Global()->Set(v8_str("bis"), v8_num(1234));
10687 script = v8_compile("other.eval('bis')");
10688 CHECK_EQ(1234, script->Run()->Int32Value());
10689 CHECK(!try_catch.HasCaught());
10691 // Check that the 'this' pointer points to the global object evaluating
10693 other->Global()->Set(v8_str("t"), other->Global());
10694 script = v8_compile("other.eval('this == t')");
10695 result = script->Run();
10696 CHECK(result->IsTrue());
10697 CHECK(!try_catch.HasCaught());
10699 // Check that variables introduced in with-statement are not visible in
10701 script = v8_compile("with({x:2}){other.eval('x')}");
10702 result = script->Run();
10703 CHECK(try_catch.HasCaught());
10706 // Check that you cannot use 'eval.call' with another object than the
10707 // current global object.
10708 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10709 result = script->Run();
10710 CHECK(try_catch.HasCaught());
10714 // Test that calling eval in a context which has been detached from
10715 // its global throws an exception. This behavior is consistent with
10716 // other JavaScript implementations.
10717 THREADED_TEST(EvalInDetachedGlobal) {
10718 v8::Isolate* isolate = CcTest::isolate();
10719 v8::HandleScope scope(isolate);
10721 v8::Local<Context> context0 = Context::New(isolate);
10722 v8::Local<Context> context1 = Context::New(isolate);
10724 // Set up function in context0 that uses eval from context0.
10726 v8::Handle<v8::Value> fun =
10727 CompileRun("var x = 42;"
10730 " return function(s) { return e(s); }"
10734 // Put the function into context1 and call it before and after
10735 // detaching the global. Before detaching, the call succeeds and
10736 // after detaching and exception is thrown.
10738 context1->Global()->Set(v8_str("fun"), fun);
10739 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10740 CHECK_EQ(42, x_value->Int32Value());
10741 context0->DetachGlobal();
10742 v8::TryCatch catcher;
10743 x_value = CompileRun("fun('x')");
10744 CHECK(x_value.IsEmpty());
10745 CHECK(catcher.HasCaught());
10750 THREADED_TEST(CrossLazyLoad) {
10751 v8::HandleScope scope(CcTest::isolate());
10752 LocalContext other;
10753 LocalContext current;
10755 Local<String> token = v8_str("<security token>");
10756 other->SetSecurityToken(token);
10757 current->SetSecurityToken(token);
10759 // Set up reference from current to other.
10760 current->Global()->Set(v8_str("other"), other->Global());
10762 // Trigger lazy loading in other context.
10763 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10764 Local<Value> value = script->Run();
10765 CHECK_EQ(42.0, value->NumberValue());
10769 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10770 ApiTestFuzzer::Fuzz();
10771 if (args.IsConstructCall()) {
10772 if (args[0]->IsInt32()) {
10773 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10778 args.GetReturnValue().Set(args[0]);
10782 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10783 args.GetReturnValue().Set(args.This());
10787 // Test that a call handler can be set for objects which will allow
10788 // non-function objects created through the API to be called as
10790 THREADED_TEST(CallAsFunction) {
10791 LocalContext context;
10792 v8::Isolate* isolate = context->GetIsolate();
10793 v8::HandleScope scope(isolate);
10795 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10796 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10797 instance_template->SetCallAsFunctionHandler(call_as_function);
10798 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10799 context->Global()->Set(v8_str("obj"), instance);
10800 v8::TryCatch try_catch;
10801 Local<Value> value;
10802 CHECK(!try_catch.HasCaught());
10804 value = CompileRun("obj(42)");
10805 CHECK(!try_catch.HasCaught());
10806 CHECK_EQ(42, value->Int32Value());
10808 value = CompileRun("(function(o){return o(49)})(obj)");
10809 CHECK(!try_catch.HasCaught());
10810 CHECK_EQ(49, value->Int32Value());
10812 // test special case of call as function
10813 value = CompileRun("[obj]['0'](45)");
10814 CHECK(!try_catch.HasCaught());
10815 CHECK_EQ(45, value->Int32Value());
10817 value = CompileRun("obj.call = Function.prototype.call;"
10818 "obj.call(null, 87)");
10819 CHECK(!try_catch.HasCaught());
10820 CHECK_EQ(87, value->Int32Value());
10822 // Regression tests for bug #1116356: Calling call through call/apply
10823 // must work for non-function receivers.
10824 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10825 value = CompileRun(apply_99);
10826 CHECK(!try_catch.HasCaught());
10827 CHECK_EQ(99, value->Int32Value());
10829 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10830 value = CompileRun(call_17);
10831 CHECK(!try_catch.HasCaught());
10832 CHECK_EQ(17, value->Int32Value());
10834 // Check that the call-as-function handler can be called through
10836 value = CompileRun("new obj(43)");
10837 CHECK(!try_catch.HasCaught());
10838 CHECK_EQ(-43, value->Int32Value());
10840 // Check that the call-as-function handler can be called through
10842 v8::Handle<Value> args[] = { v8_num(28) };
10843 value = instance->CallAsFunction(instance, 1, args);
10844 CHECK(!try_catch.HasCaught());
10845 CHECK_EQ(28, value->Int32Value());
10848 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10849 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10850 USE(instance_template);
10851 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10852 context->Global()->Set(v8_str("obj2"), instance);
10853 v8::TryCatch try_catch;
10854 Local<Value> value;
10855 CHECK(!try_catch.HasCaught());
10857 // Call an object without call-as-function handler through the JS
10858 value = CompileRun("obj2(28)");
10859 CHECK(value.IsEmpty());
10860 CHECK(try_catch.HasCaught());
10861 String::Utf8Value exception_value1(try_catch.Exception());
10862 // TODO(verwaest): Better message
10863 CHECK_EQ("TypeError: object is not a function",
10864 *exception_value1);
10867 // Call an object without call-as-function handler through the API
10868 value = CompileRun("obj2(28)");
10869 v8::Handle<Value> args[] = { v8_num(28) };
10870 value = instance->CallAsFunction(instance, 1, args);
10871 CHECK(value.IsEmpty());
10872 CHECK(try_catch.HasCaught());
10873 String::Utf8Value exception_value2(try_catch.Exception());
10874 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10878 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10879 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10880 instance_template->SetCallAsFunctionHandler(ThrowValue);
10881 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10882 context->Global()->Set(v8_str("obj3"), instance);
10883 v8::TryCatch try_catch;
10884 Local<Value> value;
10885 CHECK(!try_catch.HasCaught());
10887 // Catch the exception which is thrown by call-as-function handler
10888 value = CompileRun("obj3(22)");
10889 CHECK(try_catch.HasCaught());
10890 String::Utf8Value exception_value1(try_catch.Exception());
10891 CHECK_EQ("22", *exception_value1);
10894 v8::Handle<Value> args[] = { v8_num(23) };
10895 value = instance->CallAsFunction(instance, 1, args);
10896 CHECK(try_catch.HasCaught());
10897 String::Utf8Value exception_value2(try_catch.Exception());
10898 CHECK_EQ("23", *exception_value2);
10902 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10903 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10904 instance_template->SetCallAsFunctionHandler(ReturnThis);
10905 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10907 Local<v8::Value> a1 =
10908 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10909 CHECK(a1->StrictEquals(instance));
10910 Local<v8::Value> a2 =
10911 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10912 CHECK(a2->StrictEquals(instance));
10913 Local<v8::Value> a3 =
10914 instance->CallAsFunction(v8_num(42), 0, NULL);
10915 CHECK(a3->StrictEquals(instance));
10916 Local<v8::Value> a4 =
10917 instance->CallAsFunction(v8_str("hello"), 0, NULL);
10918 CHECK(a4->StrictEquals(instance));
10919 Local<v8::Value> a5 =
10920 instance->CallAsFunction(v8::True(isolate), 0, NULL);
10921 CHECK(a5->StrictEquals(instance));
10925 "function ReturnThisSloppy() {"
10928 "function ReturnThisStrict() {"
10932 Local<Function> ReturnThisSloppy =
10933 Local<Function>::Cast(
10934 context->Global()->Get(v8_str("ReturnThisSloppy")));
10935 Local<Function> ReturnThisStrict =
10936 Local<Function>::Cast(
10937 context->Global()->Get(v8_str("ReturnThisStrict")));
10939 Local<v8::Value> a1 =
10940 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10941 CHECK(a1->StrictEquals(context->Global()));
10942 Local<v8::Value> a2 =
10943 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10944 CHECK(a2->StrictEquals(context->Global()));
10945 Local<v8::Value> a3 =
10946 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10947 CHECK(a3->IsNumberObject());
10948 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10949 Local<v8::Value> a4 =
10950 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10951 CHECK(a4->IsStringObject());
10952 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10953 Local<v8::Value> a5 =
10954 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10955 CHECK(a5->IsBooleanObject());
10956 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10958 Local<v8::Value> a6 =
10959 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10960 CHECK(a6->IsUndefined());
10961 Local<v8::Value> a7 =
10962 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10963 CHECK(a7->IsNull());
10964 Local<v8::Value> a8 =
10965 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10966 CHECK(a8->StrictEquals(v8_num(42)));
10967 Local<v8::Value> a9 =
10968 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10969 CHECK(a9->StrictEquals(v8_str("hello")));
10970 Local<v8::Value> a10 =
10971 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10972 CHECK(a10->StrictEquals(v8::True(isolate)));
10977 // Check whether a non-function object is callable.
10978 THREADED_TEST(CallableObject) {
10979 LocalContext context;
10980 v8::Isolate* isolate = context->GetIsolate();
10981 v8::HandleScope scope(isolate);
10983 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10984 instance_template->SetCallAsFunctionHandler(call_as_function);
10985 Local<Object> instance = instance_template->NewInstance();
10986 v8::TryCatch try_catch;
10988 CHECK(instance->IsCallable());
10989 CHECK(!try_catch.HasCaught());
10992 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10993 Local<Object> instance = instance_template->NewInstance();
10994 v8::TryCatch try_catch;
10996 CHECK(!instance->IsCallable());
10997 CHECK(!try_catch.HasCaught());
11000 { Local<FunctionTemplate> function_template =
11001 FunctionTemplate::New(isolate, call_as_function);
11002 Local<Function> function = function_template->GetFunction();
11003 Local<Object> instance = function;
11004 v8::TryCatch try_catch;
11006 CHECK(instance->IsCallable());
11007 CHECK(!try_catch.HasCaught());
11010 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11011 Local<Function> function = function_template->GetFunction();
11012 Local<Object> instance = function;
11013 v8::TryCatch try_catch;
11015 CHECK(instance->IsCallable());
11016 CHECK(!try_catch.HasCaught());
11021 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11022 v8::HandleScope scope(isolate);
11023 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11024 for (int i = 0; i < iterations; i++) {
11025 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11027 return Recurse(isolate, depth - 1, iterations);
11031 THREADED_TEST(HandleIteration) {
11032 static const int kIterations = 500;
11033 static const int kNesting = 200;
11034 LocalContext context;
11035 v8::Isolate* isolate = context->GetIsolate();
11036 v8::HandleScope scope0(isolate);
11037 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11039 v8::HandleScope scope1(isolate);
11040 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11041 for (int i = 0; i < kIterations; i++) {
11042 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11043 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11046 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11048 v8::HandleScope scope2(CcTest::isolate());
11049 for (int j = 0; j < kIterations; j++) {
11050 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11051 CHECK_EQ(j + 1 + kIterations,
11052 v8::HandleScope::NumberOfHandles(isolate));
11055 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11057 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11058 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11062 static void InterceptorHasOwnPropertyGetter(
11063 Local<String> name,
11064 const v8::PropertyCallbackInfo<v8::Value>& info) {
11065 ApiTestFuzzer::Fuzz();
11069 THREADED_TEST(InterceptorHasOwnProperty) {
11070 LocalContext context;
11071 v8::Isolate* isolate = context->GetIsolate();
11072 v8::HandleScope scope(isolate);
11073 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11074 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11075 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11076 Local<Function> function = fun_templ->GetFunction();
11077 context->Global()->Set(v8_str("constructor"), function);
11078 v8::Handle<Value> value = CompileRun(
11079 "var o = new constructor();"
11080 "o.hasOwnProperty('ostehaps');");
11081 CHECK_EQ(false, value->BooleanValue());
11082 value = CompileRun(
11084 "o.hasOwnProperty('ostehaps');");
11085 CHECK_EQ(true, value->BooleanValue());
11086 value = CompileRun(
11087 "var p = new constructor();"
11088 "p.hasOwnProperty('ostehaps');");
11089 CHECK_EQ(false, value->BooleanValue());
11093 static void InterceptorHasOwnPropertyGetterGC(
11094 Local<String> name,
11095 const v8::PropertyCallbackInfo<v8::Value>& info) {
11096 ApiTestFuzzer::Fuzz();
11097 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11101 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11102 LocalContext context;
11103 v8::Isolate* isolate = context->GetIsolate();
11104 v8::HandleScope scope(isolate);
11105 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11106 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11107 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11108 Local<Function> function = fun_templ->GetFunction();
11109 context->Global()->Set(v8_str("constructor"), function);
11110 // Let's first make some stuff so we can be sure to get a good GC.
11112 "function makestr(size) {"
11114 " case 1: return 'f';"
11115 " case 2: return 'fo';"
11116 " case 3: return 'foo';"
11118 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11120 "var x = makestr(12345);"
11121 "x = makestr(31415);"
11122 "x = makestr(23456);");
11123 v8::Handle<Value> value = CompileRun(
11124 "var o = new constructor();"
11125 "o.__proto__ = new String(x);"
11126 "o.hasOwnProperty('ostehaps');");
11127 CHECK_EQ(false, value->BooleanValue());
11131 typedef void (*NamedPropertyGetter)(
11132 Local<String> property,
11133 const v8::PropertyCallbackInfo<v8::Value>& info);
11136 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11137 const char* source,
11139 v8::Isolate* isolate = CcTest::isolate();
11140 v8::HandleScope scope(isolate);
11141 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11142 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11143 LocalContext context;
11144 context->Global()->Set(v8_str("o"), templ->NewInstance());
11145 v8::Handle<Value> value = CompileRun(source);
11146 CHECK_EQ(expected, value->Int32Value());
11150 static void InterceptorLoadICGetter(
11151 Local<String> name,
11152 const v8::PropertyCallbackInfo<v8::Value>& info) {
11153 ApiTestFuzzer::Fuzz();
11154 v8::Isolate* isolate = CcTest::isolate();
11155 CHECK_EQ(isolate, info.GetIsolate());
11156 CHECK_EQ(v8_str("data"), info.Data());
11157 CHECK_EQ(v8_str("x"), name);
11158 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11162 // This test should hit the load IC for the interceptor case.
11163 THREADED_TEST(InterceptorLoadIC) {
11164 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11166 "for (var i = 0; i < 1000; i++) {"
11173 // Below go several tests which verify that JITing for various
11174 // configurations of interceptor and explicit fields works fine
11175 // (those cases are special cased to get better performance).
11177 static void InterceptorLoadXICGetter(
11178 Local<String> name,
11179 const v8::PropertyCallbackInfo<v8::Value>& info) {
11180 ApiTestFuzzer::Fuzz();
11181 info.GetReturnValue().Set(
11182 v8_str("x")->Equals(name) ?
11183 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11184 v8::Handle<v8::Value>());
11188 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11189 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11192 "for (var i = 0; i < 1000; i++) {"
11199 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11200 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11202 "o.__proto__ = { 'y': 239 };"
11203 "for (var i = 0; i < 1000; i++) {"
11204 " result = o.y + o.x;"
11210 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11211 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11213 "o.__proto__.y = 239;"
11214 "for (var i = 0; i < 1000; i++) {"
11215 " result = o.y + o.x;"
11221 THREADED_TEST(InterceptorLoadICUndefined) {
11222 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11224 "for (var i = 0; i < 1000; i++) {"
11225 " result = (o.y == undefined) ? 239 : 42;"
11231 THREADED_TEST(InterceptorLoadICWithOverride) {
11232 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11233 "fst = new Object(); fst.__proto__ = o;"
11234 "snd = new Object(); snd.__proto__ = fst;"
11236 "for (var i = 0; i < 1000; i++) {"
11237 " result1 = snd.x;"
11241 "for (var i = 0; i < 1000; i++) {"
11244 "result + result1",
11249 // Test the case when we stored field into
11250 // a stub, but interceptor produced value on its own.
11251 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11252 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11253 "proto = new Object();"
11254 "o.__proto__ = proto;"
11256 "for (var i = 0; i < 1000; i++) {"
11258 // Now it should be ICed and keep a reference to x defined on proto
11261 "for (var i = 0; i < 1000; i++) {"
11269 // Test the case when we stored field into
11270 // a stub, but it got invalidated later on.
11271 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11272 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11273 "proto1 = new Object();"
11274 "proto2 = new Object();"
11275 "o.__proto__ = proto1;"
11276 "proto1.__proto__ = proto2;"
11278 "for (var i = 0; i < 1000; i++) {"
11280 // Now it should be ICed and keep a reference to y defined on proto2
11284 "for (var i = 0; i < 1000; i++) {"
11292 static int interceptor_load_not_handled_calls = 0;
11293 static void InterceptorLoadNotHandled(
11294 Local<String> name,
11295 const v8::PropertyCallbackInfo<v8::Value>& info) {
11296 ++interceptor_load_not_handled_calls;
11300 // Test how post-interceptor lookups are done in the non-cacheable
11301 // case: the interceptor should not be invoked during this lookup.
11302 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11303 interceptor_load_not_handled_calls = 0;
11304 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11305 "receiver = new Object();"
11306 "receiver.__proto__ = o;"
11307 "proto = new Object();"
11308 "/* Make proto a slow-case object. */"
11309 "for (var i = 0; i < 1000; i++) {"
11310 " proto[\"xxxxxxxx\" + i] = [];"
11313 "o.__proto__ = proto;"
11315 "for (var i = 0; i < 1000; i++) {"
11316 " result += receiver.x;"
11320 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11324 // Test the case when we stored field into
11325 // a stub, but it got invalidated later on due to override on
11326 // global object which is between interceptor and fields' holders.
11327 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11328 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11329 "o.__proto__ = this;" // set a global to be a proto of o.
11330 "this.__proto__.y = 239;"
11331 "for (var i = 0; i < 10; i++) {"
11332 " if (o.y != 239) throw 'oops: ' + o.y;"
11333 // Now it should be ICed and keep a reference to y defined on field_holder.
11335 "this.y = 42;" // Assign on a global.
11337 "for (var i = 0; i < 10; i++) {"
11345 static void SetOnThis(Local<String> name,
11346 Local<Value> value,
11347 const v8::PropertyCallbackInfo<void>& info) {
11348 info.This()->ForceSet(name, value);
11352 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11353 v8::Isolate* isolate = CcTest::isolate();
11354 v8::HandleScope scope(isolate);
11355 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11356 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11357 templ->SetAccessor(v8_str("y"), Return239Callback);
11358 LocalContext context;
11359 context->Global()->Set(v8_str("o"), templ->NewInstance());
11361 // Check the case when receiver and interceptor's holder
11362 // are the same objects.
11363 v8::Handle<Value> value = CompileRun(
11365 "for (var i = 0; i < 7; i++) {"
11368 CHECK_EQ(239, value->Int32Value());
11370 // Check the case when interceptor's holder is in proto chain
11372 value = CompileRun(
11373 "r = { __proto__: o };"
11375 "for (var i = 0; i < 7; i++) {"
11378 CHECK_EQ(239, value->Int32Value());
11382 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11383 v8::Isolate* isolate = CcTest::isolate();
11384 v8::HandleScope scope(isolate);
11385 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11386 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11387 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11388 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11390 LocalContext context;
11391 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11392 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11394 // Check the case when receiver and interceptor's holder
11395 // are the same objects.
11396 v8::Handle<Value> value = CompileRun(
11399 "for (var i = 0; i < 7; i++) {"
11400 " result = o.x + o.y;"
11402 CHECK_EQ(239 + 42, value->Int32Value());
11404 // Check the case when interceptor's holder is in proto chain
11406 value = CompileRun(
11407 "r = { __proto__: o };"
11409 "for (var i = 0; i < 7; i++) {"
11410 " result = r.x + r.y;"
11412 CHECK_EQ(239 + 42, value->Int32Value());
11416 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11417 v8::Isolate* isolate = CcTest::isolate();
11418 v8::HandleScope scope(isolate);
11419 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11420 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11421 templ->SetAccessor(v8_str("y"), Return239Callback);
11423 LocalContext context;
11424 context->Global()->Set(v8_str("o"), templ->NewInstance());
11426 v8::Handle<Value> value = CompileRun(
11427 "fst = new Object(); fst.__proto__ = o;"
11428 "snd = new Object(); snd.__proto__ = fst;"
11430 "for (var i = 0; i < 7; i++) {"
11431 " result1 = snd.x;"
11435 "for (var i = 0; i < 7; i++) {"
11438 "result + result1");
11439 CHECK_EQ(239 + 42, value->Int32Value());
11443 // Test the case when we stored callback into
11444 // a stub, but interceptor produced value on its own.
11445 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11446 v8::Isolate* isolate = CcTest::isolate();
11447 v8::HandleScope scope(isolate);
11448 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11449 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11450 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11451 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11453 LocalContext context;
11454 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11455 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11457 v8::Handle<Value> value = CompileRun(
11459 "for (var i = 0; i < 7; i++) {"
11461 // Now it should be ICed and keep a reference to x defined on p
11464 "for (var i = 0; i < 7; i++) {"
11468 CHECK_EQ(42 * 7, value->Int32Value());
11472 // Test the case when we stored callback into
11473 // a stub, but it got invalidated later on.
11474 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11475 v8::Isolate* isolate = CcTest::isolate();
11476 v8::HandleScope scope(isolate);
11477 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11478 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11479 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11480 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11482 LocalContext context;
11483 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11484 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11486 v8::Handle<Value> value = CompileRun(
11487 "inbetween = new Object();"
11488 "o.__proto__ = inbetween;"
11489 "inbetween.__proto__ = p;"
11490 "for (var i = 0; i < 10; i++) {"
11492 // Now it should be ICed and keep a reference to y defined on p
11494 "inbetween.y = 42;"
11496 "for (var i = 0; i < 10; i++) {"
11500 CHECK_EQ(42 * 10, value->Int32Value());
11504 // Test the case when we stored callback into
11505 // a stub, but it got invalidated later on due to override on
11506 // global object which is between interceptor and callbacks' holders.
11507 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11508 v8::Isolate* isolate = CcTest::isolate();
11509 v8::HandleScope scope(isolate);
11510 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11511 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11512 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11513 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11515 LocalContext context;
11516 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11517 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11519 v8::Handle<Value> value = CompileRun(
11520 "o.__proto__ = this;"
11521 "this.__proto__ = p;"
11522 "for (var i = 0; i < 10; i++) {"
11523 " if (o.y != 239) throw 'oops: ' + o.y;"
11524 // Now it should be ICed and keep a reference to y defined on p
11528 "for (var i = 0; i < 10; i++) {"
11532 CHECK_EQ(42 * 10, value->Int32Value());
11536 static void InterceptorLoadICGetter0(
11537 Local<String> name,
11538 const v8::PropertyCallbackInfo<v8::Value>& info) {
11539 ApiTestFuzzer::Fuzz();
11540 CHECK(v8_str("x")->Equals(name));
11541 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11545 THREADED_TEST(InterceptorReturningZero) {
11546 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11547 "o.x == undefined ? 1 : 0",
11552 static void InterceptorStoreICSetter(
11554 Local<Value> value,
11555 const v8::PropertyCallbackInfo<v8::Value>& info) {
11556 CHECK(v8_str("x")->Equals(key));
11557 CHECK_EQ(42, value->Int32Value());
11558 info.GetReturnValue().Set(value);
11562 // This test should hit the store IC for the interceptor case.
11563 THREADED_TEST(InterceptorStoreIC) {
11564 v8::Isolate* isolate = CcTest::isolate();
11565 v8::HandleScope scope(isolate);
11566 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11567 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11568 InterceptorStoreICSetter,
11569 0, 0, 0, v8_str("data"));
11570 LocalContext context;
11571 context->Global()->Set(v8_str("o"), templ->NewInstance());
11573 "for (var i = 0; i < 1000; i++) {"
11579 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11580 v8::Isolate* isolate = CcTest::isolate();
11581 v8::HandleScope scope(isolate);
11582 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11583 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11584 LocalContext context;
11585 context->Global()->Set(v8_str("o"), templ->NewInstance());
11586 v8::Handle<Value> value = CompileRun(
11587 "for (var i = 0; i < 1000; i++) {"
11591 CHECK_EQ(239 + 42, value->Int32Value());
11597 v8::Handle<Value> call_ic_function;
11598 v8::Handle<Value> call_ic_function2;
11599 v8::Handle<Value> call_ic_function3;
11601 static void InterceptorCallICGetter(
11602 Local<String> name,
11603 const v8::PropertyCallbackInfo<v8::Value>& info) {
11604 ApiTestFuzzer::Fuzz();
11605 CHECK(v8_str("x")->Equals(name));
11606 info.GetReturnValue().Set(call_ic_function);
11610 // This test should hit the call IC for the interceptor case.
11611 THREADED_TEST(InterceptorCallIC) {
11612 v8::Isolate* isolate = CcTest::isolate();
11613 v8::HandleScope scope(isolate);
11614 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11615 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11616 LocalContext context;
11617 context->Global()->Set(v8_str("o"), templ->NewInstance());
11619 v8_compile("function f(x) { return x + 1; }; f")->Run();
11620 v8::Handle<Value> value = CompileRun(
11622 "for (var i = 0; i < 1000; i++) {"
11623 " result = o.x(41);"
11625 CHECK_EQ(42, value->Int32Value());
11629 // This test checks that if interceptor doesn't provide
11630 // a value, we can fetch regular value.
11631 THREADED_TEST(InterceptorCallICSeesOthers) {
11632 v8::Isolate* isolate = CcTest::isolate();
11633 v8::HandleScope scope(isolate);
11634 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11635 templ->SetNamedPropertyHandler(NoBlockGetterX);
11636 LocalContext context;
11637 context->Global()->Set(v8_str("o"), templ->NewInstance());
11638 v8::Handle<Value> value = CompileRun(
11639 "o.x = function f(x) { return x + 1; };"
11641 "for (var i = 0; i < 7; i++) {"
11642 " result = o.x(41);"
11644 CHECK_EQ(42, value->Int32Value());
11648 static v8::Handle<Value> call_ic_function4;
11649 static void InterceptorCallICGetter4(
11650 Local<String> name,
11651 const v8::PropertyCallbackInfo<v8::Value>& info) {
11652 ApiTestFuzzer::Fuzz();
11653 CHECK(v8_str("x")->Equals(name));
11654 info.GetReturnValue().Set(call_ic_function4);
11658 // This test checks that if interceptor provides a function,
11659 // even if we cached shadowed variant, interceptor's function
11661 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11662 v8::Isolate* isolate = CcTest::isolate();
11663 v8::HandleScope scope(isolate);
11664 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11665 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11666 LocalContext context;
11667 context->Global()->Set(v8_str("o"), templ->NewInstance());
11668 call_ic_function4 =
11669 v8_compile("function f(x) { return x - 1; }; f")->Run();
11670 v8::Handle<Value> value = CompileRun(
11671 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11673 "for (var i = 0; i < 1000; i++) {"
11674 " result = o.x(42);"
11676 CHECK_EQ(41, value->Int32Value());
11680 // Test the case when we stored cacheable lookup into
11681 // a stub, but it got invalidated later on
11682 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11683 v8::Isolate* isolate = CcTest::isolate();
11684 v8::HandleScope scope(isolate);
11685 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11686 templ->SetNamedPropertyHandler(NoBlockGetterX);
11687 LocalContext context;
11688 context->Global()->Set(v8_str("o"), templ->NewInstance());
11689 v8::Handle<Value> value = CompileRun(
11690 "proto1 = new Object();"
11691 "proto2 = new Object();"
11692 "o.__proto__ = proto1;"
11693 "proto1.__proto__ = proto2;"
11694 "proto2.y = function(x) { return x + 1; };"
11695 // Invoke it many times to compile a stub
11696 "for (var i = 0; i < 7; i++) {"
11699 "proto1.y = function(x) { return x - 1; };"
11701 "for (var i = 0; i < 7; i++) {"
11702 " result += o.y(42);"
11704 CHECK_EQ(41 * 7, value->Int32Value());
11708 // This test checks that if interceptor doesn't provide a function,
11709 // cached constant function is used
11710 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11711 v8::Isolate* isolate = CcTest::isolate();
11712 v8::HandleScope scope(isolate);
11713 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11714 templ->SetNamedPropertyHandler(NoBlockGetterX);
11715 LocalContext context;
11716 context->Global()->Set(v8_str("o"), templ->NewInstance());
11717 v8::Handle<Value> value = CompileRun(
11718 "function inc(x) { return x + 1; };"
11722 "for (var i = 0; i < 1000; i++) {"
11723 " result = o.x(42);"
11725 CHECK_EQ(43, value->Int32Value());
11729 static v8::Handle<Value> call_ic_function5;
11730 static void InterceptorCallICGetter5(
11731 Local<String> name,
11732 const v8::PropertyCallbackInfo<v8::Value>& info) {
11733 ApiTestFuzzer::Fuzz();
11734 if (v8_str("x")->Equals(name))
11735 info.GetReturnValue().Set(call_ic_function5);
11739 // This test checks that if interceptor provides a function,
11740 // even if we cached constant function, interceptor's function
11742 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11743 v8::Isolate* isolate = CcTest::isolate();
11744 v8::HandleScope scope(isolate);
11745 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11746 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11747 LocalContext context;
11748 context->Global()->Set(v8_str("o"), templ->NewInstance());
11749 call_ic_function5 =
11750 v8_compile("function f(x) { return x - 1; }; f")->Run();
11751 v8::Handle<Value> value = CompileRun(
11752 "function inc(x) { return x + 1; };"
11756 "for (var i = 0; i < 1000; i++) {"
11757 " result = o.x(42);"
11759 CHECK_EQ(41, value->Int32Value());
11763 static v8::Handle<Value> call_ic_function6;
11764 static void InterceptorCallICGetter6(
11765 Local<String> name,
11766 const v8::PropertyCallbackInfo<v8::Value>& info) {
11767 ApiTestFuzzer::Fuzz();
11768 if (v8_str("x")->Equals(name))
11769 info.GetReturnValue().Set(call_ic_function6);
11773 // Same test as above, except the code is wrapped in a function
11774 // to test the optimized compiler.
11775 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11776 i::FLAG_allow_natives_syntax = true;
11777 v8::Isolate* isolate = CcTest::isolate();
11778 v8::HandleScope scope(isolate);
11779 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11780 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11781 LocalContext context;
11782 context->Global()->Set(v8_str("o"), templ->NewInstance());
11783 call_ic_function6 =
11784 v8_compile("function f(x) { return x - 1; }; f")->Run();
11785 v8::Handle<Value> value = CompileRun(
11786 "function inc(x) { return x + 1; };"
11789 "function test() {"
11791 " for (var i = 0; i < 1000; i++) {"
11792 " result = o.x(42);"
11799 "%OptimizeFunctionOnNextCall(test);"
11801 CHECK_EQ(41, value->Int32Value());
11805 // Test the case when we stored constant function into
11806 // a stub, but it got invalidated later on
11807 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11808 v8::Isolate* isolate = CcTest::isolate();
11809 v8::HandleScope scope(isolate);
11810 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11811 templ->SetNamedPropertyHandler(NoBlockGetterX);
11812 LocalContext context;
11813 context->Global()->Set(v8_str("o"), templ->NewInstance());
11814 v8::Handle<Value> value = CompileRun(
11815 "function inc(x) { return x + 1; };"
11817 "proto1 = new Object();"
11818 "proto2 = new Object();"
11819 "o.__proto__ = proto1;"
11820 "proto1.__proto__ = proto2;"
11822 // Invoke it many times to compile a stub
11823 "for (var i = 0; i < 7; i++) {"
11826 "proto1.y = function(x) { return x - 1; };"
11828 "for (var i = 0; i < 7; i++) {"
11829 " result += o.y(42);"
11831 CHECK_EQ(41 * 7, value->Int32Value());
11835 // Test the case when we stored constant function into
11836 // a stub, but it got invalidated later on due to override on
11837 // global object which is between interceptor and constant function' holders.
11838 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11839 v8::Isolate* isolate = CcTest::isolate();
11840 v8::HandleScope scope(isolate);
11841 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11842 templ->SetNamedPropertyHandler(NoBlockGetterX);
11843 LocalContext context;
11844 context->Global()->Set(v8_str("o"), templ->NewInstance());
11845 v8::Handle<Value> value = CompileRun(
11846 "function inc(x) { return x + 1; };"
11848 "o.__proto__ = this;"
11849 "this.__proto__.y = inc;"
11850 // Invoke it many times to compile a stub
11851 "for (var i = 0; i < 7; i++) {"
11852 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11854 "this.y = function(x) { return x - 1; };"
11856 "for (var i = 0; i < 7; i++) {"
11857 " result += o.y(42);"
11859 CHECK_EQ(41 * 7, value->Int32Value());
11863 // Test the case when actual function to call sits on global object.
11864 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11865 v8::Isolate* isolate = CcTest::isolate();
11866 v8::HandleScope scope(isolate);
11867 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11868 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11870 LocalContext context;
11871 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11873 v8::Handle<Value> value = CompileRun(
11875 " o.__proto__ = this;"
11876 " for (var i = 0; i < 10; i++) {"
11877 " var v = o.parseFloat('239');"
11878 " if (v != 239) throw v;"
11879 // Now it should be ICed and keep a reference to parseFloat.
11882 " for (var i = 0; i < 10; i++) {"
11883 " result += o.parseFloat('239');"
11889 CHECK_EQ(239 * 10, value->Int32Value());
11892 static void InterceptorCallICFastApi(
11893 Local<String> name,
11894 const v8::PropertyCallbackInfo<v8::Value>& info) {
11895 ApiTestFuzzer::Fuzz();
11896 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11898 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11900 if ((*call_count) % 20 == 0) {
11901 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11905 static void FastApiCallback_TrivialSignature(
11906 const v8::FunctionCallbackInfo<v8::Value>& args) {
11907 ApiTestFuzzer::Fuzz();
11908 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11909 v8::Isolate* isolate = CcTest::isolate();
11910 CHECK_EQ(isolate, args.GetIsolate());
11911 CHECK_EQ(args.This(), args.Holder());
11912 CHECK(args.Data()->Equals(v8_str("method_data")));
11913 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11916 static void FastApiCallback_SimpleSignature(
11917 const v8::FunctionCallbackInfo<v8::Value>& args) {
11918 ApiTestFuzzer::Fuzz();
11919 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11920 v8::Isolate* isolate = CcTest::isolate();
11921 CHECK_EQ(isolate, args.GetIsolate());
11922 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11923 CHECK(args.Data()->Equals(v8_str("method_data")));
11924 // Note, we're using HasRealNamedProperty instead of Has to avoid
11925 // invoking the interceptor again.
11926 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11927 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11931 // Helper to maximize the odds of object moving.
11932 static void GenerateSomeGarbage() {
11935 "for (var i = 0; i < 1000; i++) {"
11936 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11938 "garbage = undefined;");
11942 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11943 static int count = 0;
11944 if (count++ % 3 == 0) {
11945 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11946 // This should move the stub
11947 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
11952 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11953 LocalContext context;
11954 v8::Isolate* isolate = context->GetIsolate();
11955 v8::HandleScope scope(isolate);
11956 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11957 v8::ObjectTemplate::New(isolate);
11958 nativeobject_templ->Set(isolate, "callback",
11959 v8::FunctionTemplate::New(isolate,
11960 DirectApiCallback));
11961 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11962 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11963 // call the api function multiple times to ensure direct call stub creation.
11966 " for (var i = 1; i <= 30; i++) {"
11967 " nativeobject.callback();"
11974 void ThrowingDirectApiCallback(
11975 const v8::FunctionCallbackInfo<v8::Value>& args) {
11976 args.GetIsolate()->ThrowException(v8_str("g"));
11980 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11981 LocalContext context;
11982 v8::Isolate* isolate = context->GetIsolate();
11983 v8::HandleScope scope(isolate);
11984 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11985 v8::ObjectTemplate::New(isolate);
11986 nativeobject_templ->Set(isolate, "callback",
11987 v8::FunctionTemplate::New(isolate,
11988 ThrowingDirectApiCallback));
11989 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11990 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11991 // call the api function multiple times to ensure direct call stub creation.
11992 v8::Handle<Value> result = CompileRun(
11995 " for (var i = 1; i <= 5; i++) {"
11996 " try { nativeobject.callback(); } catch (e) { result += e; }"
12000 CHECK_EQ(v8_str("ggggg"), result);
12004 static Handle<Value> DoDirectGetter() {
12005 if (++p_getter_count % 3 == 0) {
12006 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12007 GenerateSomeGarbage();
12009 return v8_str("Direct Getter Result");
12012 static void DirectGetterCallback(
12013 Local<String> name,
12014 const v8::PropertyCallbackInfo<v8::Value>& info) {
12015 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12016 info.GetReturnValue().Set(DoDirectGetter());
12020 template<typename Accessor>
12021 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12022 LocalContext context;
12023 v8::Isolate* isolate = context->GetIsolate();
12024 v8::HandleScope scope(isolate);
12025 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12026 obj->SetAccessor(v8_str("p1"), accessor);
12027 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12028 p_getter_count = 0;
12029 v8::Handle<v8::Value> result = CompileRun(
12031 " for (var i = 0; i < 30; i++) o1.p1;"
12035 CHECK_EQ(v8_str("Direct Getter Result"), result);
12036 CHECK_EQ(31, p_getter_count);
12040 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12041 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12045 void ThrowingDirectGetterCallback(
12046 Local<String> name,
12047 const v8::PropertyCallbackInfo<v8::Value>& info) {
12048 info.GetIsolate()->ThrowException(v8_str("g"));
12052 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12053 LocalContext context;
12054 v8::Isolate* isolate = context->GetIsolate();
12055 v8::HandleScope scope(isolate);
12056 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12057 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12058 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12059 v8::Handle<Value> result = CompileRun(
12061 "for (var i = 0; i < 5; i++) {"
12062 " try { o1.p1; } catch (e) { result += e; }"
12065 CHECK_EQ(v8_str("ggggg"), result);
12069 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12070 int interceptor_call_count = 0;
12071 v8::Isolate* isolate = CcTest::isolate();
12072 v8::HandleScope scope(isolate);
12073 v8::Handle<v8::FunctionTemplate> fun_templ =
12074 v8::FunctionTemplate::New(isolate);
12075 v8::Handle<v8::FunctionTemplate> method_templ =
12076 v8::FunctionTemplate::New(isolate,
12077 FastApiCallback_TrivialSignature,
12078 v8_str("method_data"),
12079 v8::Handle<v8::Signature>());
12080 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12081 proto_templ->Set(v8_str("method"), method_templ);
12082 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12083 templ->SetNamedPropertyHandler(
12084 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12085 v8::External::New(isolate, &interceptor_call_count));
12086 LocalContext context;
12087 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12088 GenerateSomeGarbage();
12089 context->Global()->Set(v8_str("o"), fun->NewInstance());
12092 "for (var i = 0; i < 100; i++) {"
12093 " result = o.method(41);"
12095 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12096 CHECK_EQ(100, interceptor_call_count);
12100 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12101 int interceptor_call_count = 0;
12102 v8::Isolate* isolate = CcTest::isolate();
12103 v8::HandleScope scope(isolate);
12104 v8::Handle<v8::FunctionTemplate> fun_templ =
12105 v8::FunctionTemplate::New(isolate);
12106 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12107 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12108 v8::Signature::New(isolate, fun_templ));
12109 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12110 proto_templ->Set(v8_str("method"), method_templ);
12111 fun_templ->SetHiddenPrototype(true);
12112 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12113 templ->SetNamedPropertyHandler(
12114 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12115 v8::External::New(isolate, &interceptor_call_count));
12116 LocalContext context;
12117 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12118 GenerateSomeGarbage();
12119 context->Global()->Set(v8_str("o"), fun->NewInstance());
12122 "var receiver = {};"
12123 "receiver.__proto__ = o;"
12125 "for (var i = 0; i < 100; i++) {"
12126 " result = receiver.method(41);"
12128 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12129 CHECK_EQ(100, interceptor_call_count);
12133 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12134 int interceptor_call_count = 0;
12135 v8::Isolate* isolate = CcTest::isolate();
12136 v8::HandleScope scope(isolate);
12137 v8::Handle<v8::FunctionTemplate> fun_templ =
12138 v8::FunctionTemplate::New(isolate);
12139 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12140 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12141 v8::Signature::New(isolate, fun_templ));
12142 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12143 proto_templ->Set(v8_str("method"), method_templ);
12144 fun_templ->SetHiddenPrototype(true);
12145 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12146 templ->SetNamedPropertyHandler(
12147 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12148 v8::External::New(isolate, &interceptor_call_count));
12149 LocalContext context;
12150 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12151 GenerateSomeGarbage();
12152 context->Global()->Set(v8_str("o"), fun->NewInstance());
12155 "var receiver = {};"
12156 "receiver.__proto__ = o;"
12158 "var saved_result = 0;"
12159 "for (var i = 0; i < 100; i++) {"
12160 " result = receiver.method(41);"
12162 " saved_result = result;"
12163 " receiver = {method: function(x) { return x - 1 }};"
12166 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12167 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12168 CHECK_GE(interceptor_call_count, 50);
12172 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12173 int interceptor_call_count = 0;
12174 v8::Isolate* isolate = CcTest::isolate();
12175 v8::HandleScope scope(isolate);
12176 v8::Handle<v8::FunctionTemplate> fun_templ =
12177 v8::FunctionTemplate::New(isolate);
12178 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12179 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12180 v8::Signature::New(isolate, fun_templ));
12181 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12182 proto_templ->Set(v8_str("method"), method_templ);
12183 fun_templ->SetHiddenPrototype(true);
12184 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12185 templ->SetNamedPropertyHandler(
12186 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12187 v8::External::New(isolate, &interceptor_call_count));
12188 LocalContext context;
12189 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12190 GenerateSomeGarbage();
12191 context->Global()->Set(v8_str("o"), fun->NewInstance());
12194 "var receiver = {};"
12195 "receiver.__proto__ = o;"
12197 "var saved_result = 0;"
12198 "for (var i = 0; i < 100; i++) {"
12199 " result = receiver.method(41);"
12201 " saved_result = result;"
12202 " o.method = function(x) { return x - 1 };"
12205 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12206 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12207 CHECK_GE(interceptor_call_count, 50);
12211 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12212 int interceptor_call_count = 0;
12213 v8::Isolate* isolate = CcTest::isolate();
12214 v8::HandleScope scope(isolate);
12215 v8::Handle<v8::FunctionTemplate> fun_templ =
12216 v8::FunctionTemplate::New(isolate);
12217 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12218 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12219 v8::Signature::New(isolate, fun_templ));
12220 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12221 proto_templ->Set(v8_str("method"), method_templ);
12222 fun_templ->SetHiddenPrototype(true);
12223 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12224 templ->SetNamedPropertyHandler(
12225 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12226 v8::External::New(isolate, &interceptor_call_count));
12227 LocalContext context;
12228 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12229 GenerateSomeGarbage();
12230 context->Global()->Set(v8_str("o"), fun->NewInstance());
12231 v8::TryCatch try_catch;
12234 "var receiver = {};"
12235 "receiver.__proto__ = o;"
12237 "var saved_result = 0;"
12238 "for (var i = 0; i < 100; i++) {"
12239 " result = receiver.method(41);"
12241 " saved_result = result;"
12245 CHECK(try_catch.HasCaught());
12246 // TODO(verwaest): Adjust message.
12247 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12248 try_catch.Exception()->ToString());
12249 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12250 CHECK_GE(interceptor_call_count, 50);
12254 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12255 int interceptor_call_count = 0;
12256 v8::Isolate* isolate = CcTest::isolate();
12257 v8::HandleScope scope(isolate);
12258 v8::Handle<v8::FunctionTemplate> fun_templ =
12259 v8::FunctionTemplate::New(isolate);
12260 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12261 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12262 v8::Signature::New(isolate, fun_templ));
12263 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12264 proto_templ->Set(v8_str("method"), method_templ);
12265 fun_templ->SetHiddenPrototype(true);
12266 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12267 templ->SetNamedPropertyHandler(
12268 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12269 v8::External::New(isolate, &interceptor_call_count));
12270 LocalContext context;
12271 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12272 GenerateSomeGarbage();
12273 context->Global()->Set(v8_str("o"), fun->NewInstance());
12274 v8::TryCatch try_catch;
12277 "var receiver = {};"
12278 "receiver.__proto__ = o;"
12280 "var saved_result = 0;"
12281 "for (var i = 0; i < 100; i++) {"
12282 " result = receiver.method(41);"
12284 " saved_result = result;"
12285 " receiver = {method: receiver.method};"
12288 CHECK(try_catch.HasCaught());
12289 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12290 try_catch.Exception()->ToString());
12291 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12292 CHECK_GE(interceptor_call_count, 50);
12296 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12297 v8::Isolate* isolate = CcTest::isolate();
12298 v8::HandleScope scope(isolate);
12299 v8::Handle<v8::FunctionTemplate> fun_templ =
12300 v8::FunctionTemplate::New(isolate);
12301 v8::Handle<v8::FunctionTemplate> method_templ =
12302 v8::FunctionTemplate::New(isolate,
12303 FastApiCallback_TrivialSignature,
12304 v8_str("method_data"),
12305 v8::Handle<v8::Signature>());
12306 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12307 proto_templ->Set(v8_str("method"), method_templ);
12308 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12310 LocalContext context;
12311 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12312 GenerateSomeGarbage();
12313 context->Global()->Set(v8_str("o"), fun->NewInstance());
12316 "for (var i = 0; i < 100; i++) {"
12317 " result = o.method(41);"
12320 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12324 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
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 CHECK(!templ.IsEmpty());
12337 LocalContext context;
12338 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12339 GenerateSomeGarbage();
12340 context->Global()->Set(v8_str("o"), fun->NewInstance());
12343 "var receiver = {};"
12344 "receiver.__proto__ = o;"
12346 "for (var i = 0; i < 100; i++) {"
12347 " result = receiver.method(41);"
12350 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12354 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12355 v8::Isolate* isolate = CcTest::isolate();
12356 v8::HandleScope scope(isolate);
12357 v8::Handle<v8::FunctionTemplate> fun_templ =
12358 v8::FunctionTemplate::New(isolate);
12359 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12360 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12361 v8::Signature::New(isolate, fun_templ));
12362 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12363 proto_templ->Set(v8_str("method"), method_templ);
12364 fun_templ->SetHiddenPrototype(true);
12365 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12366 CHECK(!templ.IsEmpty());
12367 LocalContext context;
12368 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12369 GenerateSomeGarbage();
12370 context->Global()->Set(v8_str("o"), fun->NewInstance());
12373 "var receiver = {};"
12374 "receiver.__proto__ = o;"
12376 "var saved_result = 0;"
12377 "for (var i = 0; i < 100; i++) {"
12378 " result = receiver.method(41);"
12380 " saved_result = result;"
12381 " receiver = {method: function(x) { return x - 1 }};"
12384 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12385 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12389 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12390 v8::Isolate* isolate = CcTest::isolate();
12391 v8::HandleScope scope(isolate);
12392 v8::Handle<v8::FunctionTemplate> fun_templ =
12393 v8::FunctionTemplate::New(isolate);
12394 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12395 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12396 v8::Signature::New(isolate, fun_templ));
12397 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12398 proto_templ->Set(v8_str("method"), method_templ);
12399 fun_templ->SetHiddenPrototype(true);
12400 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12401 CHECK(!templ.IsEmpty());
12402 LocalContext context;
12403 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12404 GenerateSomeGarbage();
12405 context->Global()->Set(v8_str("o"), fun->NewInstance());
12406 v8::TryCatch try_catch;
12409 "var receiver = {};"
12410 "receiver.__proto__ = o;"
12412 "var saved_result = 0;"
12413 "for (var i = 0; i < 100; i++) {"
12414 " result = receiver.method(41);"
12416 " saved_result = result;"
12420 CHECK(try_catch.HasCaught());
12421 // TODO(verwaest): Adjust message.
12422 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12423 try_catch.Exception()->ToString());
12424 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12428 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12429 v8::Isolate* isolate = CcTest::isolate();
12430 v8::HandleScope scope(isolate);
12431 v8::Handle<v8::FunctionTemplate> fun_templ =
12432 v8::FunctionTemplate::New(isolate);
12433 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12434 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12435 v8::Signature::New(isolate, fun_templ));
12436 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12437 proto_templ->Set(v8_str("method"), method_templ);
12438 fun_templ->SetHiddenPrototype(true);
12439 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12440 CHECK(!templ.IsEmpty());
12441 LocalContext context;
12442 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12443 GenerateSomeGarbage();
12444 context->Global()->Set(v8_str("o"), fun->NewInstance());
12445 v8::TryCatch try_catch;
12448 "var receiver = {};"
12449 "receiver.__proto__ = o;"
12451 "var saved_result = 0;"
12452 "for (var i = 0; i < 100; i++) {"
12453 " result = receiver.method(41);"
12455 " saved_result = result;"
12456 " receiver = Object.create(receiver);"
12459 CHECK(try_catch.HasCaught());
12460 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12461 try_catch.Exception()->ToString());
12462 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12466 v8::Handle<Value> keyed_call_ic_function;
12468 static void InterceptorKeyedCallICGetter(
12469 Local<String> name,
12470 const v8::PropertyCallbackInfo<v8::Value>& info) {
12471 ApiTestFuzzer::Fuzz();
12472 if (v8_str("x")->Equals(name)) {
12473 info.GetReturnValue().Set(keyed_call_ic_function);
12478 // Test the case when we stored cacheable lookup into
12479 // a stub, but the function name changed (to another cacheable function).
12480 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12481 v8::Isolate* isolate = CcTest::isolate();
12482 v8::HandleScope scope(isolate);
12483 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12484 templ->SetNamedPropertyHandler(NoBlockGetterX);
12485 LocalContext context;
12486 context->Global()->Set(v8_str("o"), templ->NewInstance());
12488 "proto = new Object();"
12489 "proto.y = function(x) { return x + 1; };"
12490 "proto.z = function(x) { return x - 1; };"
12491 "o.__proto__ = proto;"
12493 "var method = 'y';"
12494 "for (var i = 0; i < 10; i++) {"
12495 " if (i == 5) { method = 'z'; };"
12496 " result += o[method](41);"
12498 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12502 // Test the case when we stored cacheable lookup into
12503 // a stub, but the function name changed (and the new function is present
12504 // both before and after the interceptor in the prototype chain).
12505 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12506 v8::Isolate* isolate = CcTest::isolate();
12507 v8::HandleScope scope(isolate);
12508 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12509 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12510 LocalContext context;
12511 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12512 keyed_call_ic_function =
12513 v8_compile("function f(x) { return x - 1; }; f")->Run();
12515 "o = new Object();"
12516 "proto2 = new Object();"
12517 "o.y = function(x) { return x + 1; };"
12518 "proto2.y = function(x) { return x + 2; };"
12519 "o.__proto__ = proto1;"
12520 "proto1.__proto__ = proto2;"
12522 "var method = 'x';"
12523 "for (var i = 0; i < 10; i++) {"
12524 " if (i == 5) { method = 'y'; };"
12525 " result += o[method](41);"
12527 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12531 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12532 // on the global object.
12533 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12534 v8::Isolate* isolate = CcTest::isolate();
12535 v8::HandleScope scope(isolate);
12536 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12537 templ->SetNamedPropertyHandler(NoBlockGetterX);
12538 LocalContext context;
12539 context->Global()->Set(v8_str("o"), templ->NewInstance());
12541 "function inc(x) { return x + 1; };"
12543 "function dec(x) { return x - 1; };"
12545 "o.__proto__ = this;"
12546 "this.__proto__.x = inc;"
12547 "this.__proto__.y = dec;"
12549 "var method = 'x';"
12550 "for (var i = 0; i < 10; i++) {"
12551 " if (i == 5) { method = 'y'; };"
12552 " result += o[method](41);"
12554 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12558 // Test the case when actual function to call sits on global object.
12559 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12560 v8::Isolate* isolate = CcTest::isolate();
12561 v8::HandleScope scope(isolate);
12562 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12563 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12564 LocalContext context;
12565 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12568 "function len(x) { return x.length; };"
12569 "o.__proto__ = this;"
12570 "var m = 'parseFloat';"
12572 "for (var i = 0; i < 10; i++) {"
12575 " saved_result = result;"
12577 " result = o[m]('239');"
12579 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12580 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12584 // Test the map transition before the interceptor.
12585 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12586 v8::Isolate* isolate = CcTest::isolate();
12587 v8::HandleScope scope(isolate);
12588 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12589 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12590 LocalContext context;
12591 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12594 "var o = new Object();"
12595 "o.__proto__ = proto;"
12596 "o.method = function(x) { return x + 1; };"
12597 "var m = 'method';"
12599 "for (var i = 0; i < 10; i++) {"
12600 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12601 " result += o[m](41);"
12603 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12607 // Test the map transition after the interceptor.
12608 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12609 v8::Isolate* isolate = CcTest::isolate();
12610 v8::HandleScope scope(isolate);
12611 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12612 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12613 LocalContext context;
12614 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12617 "var proto = new Object();"
12618 "o.__proto__ = proto;"
12619 "proto.method = function(x) { return x + 1; };"
12620 "var m = 'method';"
12622 "for (var i = 0; i < 10; i++) {"
12623 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12624 " result += o[m](41);"
12626 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12630 static int interceptor_call_count = 0;
12632 static void InterceptorICRefErrorGetter(
12633 Local<String> name,
12634 const v8::PropertyCallbackInfo<v8::Value>& info) {
12635 ApiTestFuzzer::Fuzz();
12636 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12637 info.GetReturnValue().Set(call_ic_function2);
12642 // This test should hit load and call ICs for the interceptor case.
12643 // Once in a while, the interceptor will reply that a property was not
12644 // found in which case we should get a reference error.
12645 THREADED_TEST(InterceptorICReferenceErrors) {
12646 v8::Isolate* isolate = CcTest::isolate();
12647 v8::HandleScope scope(isolate);
12648 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12649 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12650 LocalContext context(0, templ, v8::Handle<Value>());
12651 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12652 v8::Handle<Value> value = CompileRun(
12654 " for (var i = 0; i < 1000; i++) {"
12655 " try { x; } catch(e) { return true; }"
12660 CHECK_EQ(true, value->BooleanValue());
12661 interceptor_call_count = 0;
12662 value = CompileRun(
12664 " for (var i = 0; i < 1000; i++) {"
12665 " try { x(42); } catch(e) { return true; }"
12670 CHECK_EQ(true, value->BooleanValue());
12674 static int interceptor_ic_exception_get_count = 0;
12676 static void InterceptorICExceptionGetter(
12677 Local<String> name,
12678 const v8::PropertyCallbackInfo<v8::Value>& info) {
12679 ApiTestFuzzer::Fuzz();
12680 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12681 info.GetReturnValue().Set(call_ic_function3);
12683 if (interceptor_ic_exception_get_count == 20) {
12684 info.GetIsolate()->ThrowException(v8_num(42));
12690 // Test interceptor load/call IC where the interceptor throws an
12691 // exception once in a while.
12692 THREADED_TEST(InterceptorICGetterExceptions) {
12693 interceptor_ic_exception_get_count = 0;
12694 v8::Isolate* isolate = CcTest::isolate();
12695 v8::HandleScope scope(isolate);
12696 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12697 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12698 LocalContext context(0, templ, v8::Handle<Value>());
12699 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12700 v8::Handle<Value> value = CompileRun(
12702 " for (var i = 0; i < 100; i++) {"
12703 " try { x; } catch(e) { return true; }"
12708 CHECK_EQ(true, value->BooleanValue());
12709 interceptor_ic_exception_get_count = 0;
12710 value = CompileRun(
12712 " for (var i = 0; i < 100; i++) {"
12713 " try { x(42); } catch(e) { return true; }"
12718 CHECK_EQ(true, value->BooleanValue());
12722 static int interceptor_ic_exception_set_count = 0;
12724 static void InterceptorICExceptionSetter(
12726 Local<Value> value,
12727 const v8::PropertyCallbackInfo<v8::Value>& info) {
12728 ApiTestFuzzer::Fuzz();
12729 if (++interceptor_ic_exception_set_count > 20) {
12730 info.GetIsolate()->ThrowException(v8_num(42));
12735 // Test interceptor store IC where the interceptor throws an exception
12736 // once in a while.
12737 THREADED_TEST(InterceptorICSetterExceptions) {
12738 interceptor_ic_exception_set_count = 0;
12739 v8::Isolate* isolate = CcTest::isolate();
12740 v8::HandleScope scope(isolate);
12741 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12742 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12743 LocalContext context(0, templ, v8::Handle<Value>());
12744 v8::Handle<Value> value = CompileRun(
12746 " for (var i = 0; i < 100; i++) {"
12747 " try { x = 42; } catch(e) { return true; }"
12752 CHECK_EQ(true, value->BooleanValue());
12756 // Test that we ignore null interceptors.
12757 THREADED_TEST(NullNamedInterceptor) {
12758 v8::Isolate* isolate = CcTest::isolate();
12759 v8::HandleScope scope(isolate);
12760 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761 templ->SetNamedPropertyHandler(
12762 static_cast<v8::NamedPropertyGetterCallback>(0));
12763 LocalContext context;
12764 templ->Set(CcTest::isolate(), "x", v8_num(42));
12765 v8::Handle<v8::Object> obj = templ->NewInstance();
12766 context->Global()->Set(v8_str("obj"), obj);
12767 v8::Handle<Value> value = CompileRun("obj.x");
12768 CHECK(value->IsInt32());
12769 CHECK_EQ(42, value->Int32Value());
12773 // Test that we ignore null interceptors.
12774 THREADED_TEST(NullIndexedInterceptor) {
12775 v8::Isolate* isolate = CcTest::isolate();
12776 v8::HandleScope scope(isolate);
12777 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12778 templ->SetIndexedPropertyHandler(
12779 static_cast<v8::IndexedPropertyGetterCallback>(0));
12780 LocalContext context;
12781 templ->Set(CcTest::isolate(), "42", v8_num(42));
12782 v8::Handle<v8::Object> obj = templ->NewInstance();
12783 context->Global()->Set(v8_str("obj"), obj);
12784 v8::Handle<Value> value = CompileRun("obj[42]");
12785 CHECK(value->IsInt32());
12786 CHECK_EQ(42, value->Int32Value());
12790 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12791 v8::Isolate* isolate = CcTest::isolate();
12792 v8::HandleScope scope(isolate);
12793 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12794 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12796 env->Global()->Set(v8_str("obj"),
12797 templ->GetFunction()->NewInstance());
12798 ExpectTrue("obj.x === 42");
12799 ExpectTrue("!obj.propertyIsEnumerable('x')");
12803 static void ThrowingGetter(Local<String> name,
12804 const v8::PropertyCallbackInfo<v8::Value>& info) {
12805 ApiTestFuzzer::Fuzz();
12806 info.GetIsolate()->ThrowException(Handle<Value>());
12807 info.GetReturnValue().SetUndefined();
12811 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12812 LocalContext context;
12813 HandleScope scope(context->GetIsolate());
12815 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12816 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12817 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12819 Local<Object> instance = templ->GetFunction()->NewInstance();
12821 Local<Object> another = Object::New(context->GetIsolate());
12822 another->SetPrototype(instance);
12824 Local<Object> with_js_getter = CompileRun(
12826 "o.__defineGetter__('f', function() { throw undefined; });\n"
12827 "o\n").As<Object>();
12828 CHECK(!with_js_getter.IsEmpty());
12830 TryCatch try_catch;
12832 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12833 CHECK(try_catch.HasCaught());
12835 CHECK(result.IsEmpty());
12837 result = another->GetRealNamedProperty(v8_str("f"));
12838 CHECK(try_catch.HasCaught());
12840 CHECK(result.IsEmpty());
12842 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12843 CHECK(try_catch.HasCaught());
12845 CHECK(result.IsEmpty());
12847 result = another->Get(v8_str("f"));
12848 CHECK(try_catch.HasCaught());
12850 CHECK(result.IsEmpty());
12852 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12853 CHECK(try_catch.HasCaught());
12855 CHECK(result.IsEmpty());
12857 result = with_js_getter->Get(v8_str("f"));
12858 CHECK(try_catch.HasCaught());
12860 CHECK(result.IsEmpty());
12864 static void ThrowingCallbackWithTryCatch(
12865 const v8::FunctionCallbackInfo<v8::Value>& args) {
12866 TryCatch try_catch;
12867 // Verboseness is important: it triggers message delivery which can call into
12869 try_catch.SetVerbose(true);
12870 CompileRun("throw 'from JS';");
12871 CHECK(try_catch.HasCaught());
12872 CHECK(!CcTest::i_isolate()->has_pending_exception());
12873 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12877 static int call_depth;
12880 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12881 TryCatch try_catch;
12885 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12886 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12890 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12891 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12895 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12896 Handle<String> errorMessageString = message->Get();
12897 CHECK(!errorMessageString.IsEmpty());
12898 message->GetStackTrace();
12899 message->GetScriptResourceName();
12903 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12904 LocalContext context;
12905 v8::Isolate* isolate = context->GetIsolate();
12906 HandleScope scope(isolate);
12908 Local<Function> func =
12909 FunctionTemplate::New(isolate,
12910 ThrowingCallbackWithTryCatch)->GetFunction();
12911 context->Global()->Set(v8_str("func"), func);
12913 MessageCallback callbacks[] =
12914 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12915 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12916 MessageCallback callback = callbacks[i];
12917 if (callback != NULL) {
12918 V8::AddMessageListener(callback);
12920 // Some small number to control number of times message handler should
12921 // throw an exception.
12924 "var thrown = false;\n"
12925 "try { func(); } catch(e) { thrown = true; }\n"
12927 if (callback != NULL) {
12928 V8::RemoveMessageListeners(callback);
12934 static void ParentGetter(Local<String> name,
12935 const v8::PropertyCallbackInfo<v8::Value>& info) {
12936 ApiTestFuzzer::Fuzz();
12937 info.GetReturnValue().Set(v8_num(1));
12941 static void ChildGetter(Local<String> name,
12942 const v8::PropertyCallbackInfo<v8::Value>& info) {
12943 ApiTestFuzzer::Fuzz();
12944 info.GetReturnValue().Set(v8_num(42));
12948 THREADED_TEST(Overriding) {
12949 LocalContext context;
12950 v8::Isolate* isolate = context->GetIsolate();
12951 v8::HandleScope scope(isolate);
12953 // Parent template.
12954 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12955 Local<ObjectTemplate> parent_instance_templ =
12956 parent_templ->InstanceTemplate();
12957 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12959 // Template that inherits from the parent template.
12960 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12961 Local<ObjectTemplate> child_instance_templ =
12962 child_templ->InstanceTemplate();
12963 child_templ->Inherit(parent_templ);
12964 // Override 'f'. The child version of 'f' should get called for child
12966 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12967 // Add 'g' twice. The 'g' added last should get called for instances.
12968 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12969 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12971 // Add 'h' as an accessor to the proto template with ReadOnly attributes
12972 // so 'h' can be shadowed on the instance object.
12973 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12974 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12975 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12977 // Add 'i' as an accessor to the instance template with ReadOnly attributes
12978 // but the attribute does not have effect because it is duplicated with
12980 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12981 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12985 // Instantiate the child template.
12986 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12988 // Check that the child function overrides the parent one.
12989 context->Global()->Set(v8_str("o"), instance);
12990 Local<Value> value = v8_compile("o.f")->Run();
12991 // Check that the 'g' that was added last is hit.
12992 CHECK_EQ(42, value->Int32Value());
12993 value = v8_compile("o.g")->Run();
12994 CHECK_EQ(42, value->Int32Value());
12996 // Check that 'h' cannot be shadowed.
12997 value = v8_compile("o.h = 3; o.h")->Run();
12998 CHECK_EQ(1, value->Int32Value());
13000 // Check that 'i' cannot be shadowed or changed.
13001 value = v8_compile("o.i = 3; o.i")->Run();
13002 CHECK_EQ(42, value->Int32Value());
13006 static void IsConstructHandler(
13007 const v8::FunctionCallbackInfo<v8::Value>& args) {
13008 ApiTestFuzzer::Fuzz();
13009 args.GetReturnValue().Set(args.IsConstructCall());
13013 THREADED_TEST(IsConstructCall) {
13014 v8::Isolate* isolate = CcTest::isolate();
13015 v8::HandleScope scope(isolate);
13017 // Function template with call handler.
13018 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13019 templ->SetCallHandler(IsConstructHandler);
13021 LocalContext context;
13023 context->Global()->Set(v8_str("f"), templ->GetFunction());
13024 Local<Value> value = v8_compile("f()")->Run();
13025 CHECK(!value->BooleanValue());
13026 value = v8_compile("new f()")->Run();
13027 CHECK(value->BooleanValue());
13031 THREADED_TEST(ObjectProtoToString) {
13032 v8::Isolate* isolate = CcTest::isolate();
13033 v8::HandleScope scope(isolate);
13034 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13035 templ->SetClassName(v8_str("MyClass"));
13037 LocalContext context;
13039 Local<String> customized_tostring = v8_str("customized toString");
13041 // Replace Object.prototype.toString
13042 v8_compile("Object.prototype.toString = function() {"
13043 " return 'customized toString';"
13046 // Normal ToString call should call replaced Object.prototype.toString
13047 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13048 Local<String> value = instance->ToString();
13049 CHECK(value->IsString() && value->Equals(customized_tostring));
13051 // ObjectProtoToString should not call replace toString function.
13052 value = instance->ObjectProtoToString();
13053 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13056 value = context->Global()->ObjectProtoToString();
13057 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13059 // Check ordinary object
13060 Local<Value> object = v8_compile("new Object()")->Run();
13061 value = object.As<v8::Object>()->ObjectProtoToString();
13062 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13066 THREADED_TEST(ObjectGetConstructorName) {
13067 LocalContext context;
13068 v8::HandleScope scope(context->GetIsolate());
13069 v8_compile("function Parent() {};"
13070 "function Child() {};"
13071 "Child.prototype = new Parent();"
13072 "var outer = { inner: function() { } };"
13073 "var p = new Parent();"
13074 "var c = new Child();"
13075 "var x = new outer.inner();")->Run();
13077 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13078 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13079 v8_str("Parent")));
13081 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13082 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13085 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13086 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13087 v8_str("outer.inner")));
13091 bool ApiTestFuzzer::fuzzing_ = false;
13092 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13093 int ApiTestFuzzer::active_tests_;
13094 int ApiTestFuzzer::tests_being_run_;
13095 int ApiTestFuzzer::current_;
13098 // We are in a callback and want to switch to another thread (if we
13099 // are currently running the thread fuzzing test).
13100 void ApiTestFuzzer::Fuzz() {
13101 if (!fuzzing_) return;
13102 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13103 test->ContextSwitch();
13107 // Let the next thread go. Since it is also waiting on the V8 lock it may
13108 // not start immediately.
13109 bool ApiTestFuzzer::NextThread() {
13110 int test_position = GetNextTestNumber();
13111 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13112 if (test_position == current_) {
13114 printf("Stay with %s\n", test_name);
13117 if (kLogThreading) {
13118 printf("Switch from %s to %s\n",
13120 RegisterThreadedTest::nth(test_position)->name());
13122 current_ = test_position;
13123 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13128 void ApiTestFuzzer::Run() {
13129 // When it is our turn...
13132 // ... get the V8 lock and start running the test.
13133 v8::Locker locker(CcTest::isolate());
13136 // This test finished.
13139 // If it was the last then signal that fact.
13140 if (active_tests_ == 0) {
13141 all_tests_done_.Signal();
13143 // Otherwise select a new test and start that.
13149 static unsigned linear_congruential_generator;
13152 void ApiTestFuzzer::SetUp(PartOfTest part) {
13153 linear_congruential_generator = i::FLAG_testing_prng_seed;
13155 int count = RegisterThreadedTest::count();
13156 int start = count * part / (LAST_PART + 1);
13157 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13158 active_tests_ = tests_being_run_ = end - start + 1;
13159 for (int i = 0; i < tests_being_run_; i++) {
13160 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13162 for (int i = 0; i < active_tests_; i++) {
13163 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13168 static void CallTestNumber(int test_number) {
13169 (RegisterThreadedTest::nth(test_number)->callback())();
13173 void ApiTestFuzzer::RunAllTests() {
13174 // Set off the first test.
13177 // Wait till they are all done.
13178 all_tests_done_.Wait();
13182 int ApiTestFuzzer::GetNextTestNumber() {
13185 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13186 linear_congruential_generator *= 1664525u;
13187 linear_congruential_generator += 1013904223u;
13188 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13193 void ApiTestFuzzer::ContextSwitch() {
13194 // If the new thread is the same as the current thread there is nothing to do.
13195 if (NextThread()) {
13196 // Now it can start.
13197 v8::Unlocker unlocker(CcTest::isolate());
13198 // Wait till someone starts us again.
13205 void ApiTestFuzzer::TearDown() {
13207 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13208 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13209 if (fuzzer != NULL) fuzzer->Join();
13214 // Lets not be needlessly self-referential.
13216 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13217 ApiTestFuzzer::RunAllTests();
13218 ApiTestFuzzer::TearDown();
13223 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13224 ApiTestFuzzer::RunAllTests();
13225 ApiTestFuzzer::TearDown();
13230 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13231 ApiTestFuzzer::RunAllTests();
13232 ApiTestFuzzer::TearDown();
13237 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13238 ApiTestFuzzer::RunAllTests();
13239 ApiTestFuzzer::TearDown();
13243 void ApiTestFuzzer::CallTest() {
13244 v8::Isolate::Scope scope(CcTest::isolate());
13246 printf("Start test %d\n", test_number_);
13247 CallTestNumber(test_number_);
13249 printf("End test %d\n", test_number_);
13253 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13254 v8::Isolate* isolate = args.GetIsolate();
13255 CHECK(v8::Locker::IsLocked(isolate));
13256 ApiTestFuzzer::Fuzz();
13257 v8::Unlocker unlocker(isolate);
13258 const char* code = "throw 7;";
13260 v8::Locker nested_locker(isolate);
13261 v8::HandleScope scope(isolate);
13262 v8::Handle<Value> exception;
13263 { v8::TryCatch try_catch;
13264 v8::Handle<Value> value = CompileRun(code);
13265 CHECK(value.IsEmpty());
13266 CHECK(try_catch.HasCaught());
13267 // Make sure to wrap the exception in a new handle because
13268 // the handle returned from the TryCatch is destroyed
13269 // when the TryCatch is destroyed.
13270 exception = Local<Value>::New(isolate, try_catch.Exception());
13272 args.GetIsolate()->ThrowException(exception);
13277 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13278 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13279 ApiTestFuzzer::Fuzz();
13280 v8::Unlocker unlocker(CcTest::isolate());
13281 const char* code = "throw 7;";
13283 v8::Locker nested_locker(CcTest::isolate());
13284 v8::HandleScope scope(args.GetIsolate());
13285 v8::Handle<Value> value = CompileRun(code);
13286 CHECK(value.IsEmpty());
13287 args.GetReturnValue().Set(v8_str("foo"));
13292 // These are locking tests that don't need to be run again
13293 // as part of the locking aggregation tests.
13294 TEST(NestedLockers) {
13295 v8::Isolate* isolate = CcTest::isolate();
13296 v8::Locker locker(isolate);
13297 CHECK(v8::Locker::IsLocked(isolate));
13299 v8::HandleScope scope(env->GetIsolate());
13300 Local<v8::FunctionTemplate> fun_templ =
13301 v8::FunctionTemplate::New(isolate, ThrowInJS);
13302 Local<Function> fun = fun_templ->GetFunction();
13303 env->Global()->Set(v8_str("throw_in_js"), fun);
13304 Local<Script> script = v8_compile("(function () {"
13312 CHECK_EQ(91, script->Run()->Int32Value());
13316 // These are locking tests that don't need to be run again
13317 // as part of the locking aggregation tests.
13318 TEST(NestedLockersNoTryCatch) {
13319 v8::Locker locker(CcTest::isolate());
13321 v8::HandleScope scope(env->GetIsolate());
13322 Local<v8::FunctionTemplate> fun_templ =
13323 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13324 Local<Function> fun = fun_templ->GetFunction();
13325 env->Global()->Set(v8_str("throw_in_js"), fun);
13326 Local<Script> script = v8_compile("(function () {"
13334 CHECK_EQ(91, script->Run()->Int32Value());
13338 THREADED_TEST(RecursiveLocking) {
13339 v8::Locker locker(CcTest::isolate());
13341 v8::Locker locker2(CcTest::isolate());
13342 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13347 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13348 ApiTestFuzzer::Fuzz();
13349 v8::Unlocker unlocker(CcTest::isolate());
13353 THREADED_TEST(LockUnlockLock) {
13355 v8::Locker locker(CcTest::isolate());
13356 v8::HandleScope scope(CcTest::isolate());
13358 Local<v8::FunctionTemplate> fun_templ =
13359 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13360 Local<Function> fun = fun_templ->GetFunction();
13361 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13362 Local<Script> script = v8_compile("(function () {"
13363 " unlock_for_a_moment();"
13366 CHECK_EQ(42, script->Run()->Int32Value());
13369 v8::Locker locker(CcTest::isolate());
13370 v8::HandleScope scope(CcTest::isolate());
13372 Local<v8::FunctionTemplate> fun_templ =
13373 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13374 Local<Function> fun = fun_templ->GetFunction();
13375 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13376 Local<Script> script = v8_compile("(function () {"
13377 " unlock_for_a_moment();"
13380 CHECK_EQ(42, script->Run()->Int32Value());
13385 static int GetGlobalObjectsCount() {
13386 CcTest::heap()->EnsureHeapIsIterable();
13388 i::HeapIterator it(CcTest::heap());
13389 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13390 if (object->IsJSGlobalObject()) count++;
13395 static void CheckSurvivingGlobalObjectsCount(int expected) {
13396 // We need to collect all garbage twice to be sure that everything
13397 // has been collected. This is because inline caches are cleared in
13398 // the first garbage collection but some of the maps have already
13399 // been marked at that point. Therefore some of the maps are not
13400 // collected until the second garbage collection.
13401 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13402 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13403 int count = GetGlobalObjectsCount();
13405 if (count != expected) CcTest::heap()->TracePathToGlobal();
13407 CHECK_EQ(expected, count);
13411 TEST(DontLeakGlobalObjects) {
13412 // Regression test for issues 1139850 and 1174891.
13414 i::FLAG_expose_gc = true;
13415 v8::V8::Initialize();
13417 for (int i = 0; i < 5; i++) {
13418 { v8::HandleScope scope(CcTest::isolate());
13419 LocalContext context;
13421 v8::V8::ContextDisposedNotification();
13422 CheckSurvivingGlobalObjectsCount(0);
13424 { v8::HandleScope scope(CcTest::isolate());
13425 LocalContext context;
13426 v8_compile("Date")->Run();
13428 v8::V8::ContextDisposedNotification();
13429 CheckSurvivingGlobalObjectsCount(0);
13431 { v8::HandleScope scope(CcTest::isolate());
13432 LocalContext context;
13433 v8_compile("/aaa/")->Run();
13435 v8::V8::ContextDisposedNotification();
13436 CheckSurvivingGlobalObjectsCount(0);
13438 { v8::HandleScope scope(CcTest::isolate());
13439 const char* extension_list[] = { "v8/gc" };
13440 v8::ExtensionConfiguration extensions(1, extension_list);
13441 LocalContext context(&extensions);
13442 v8_compile("gc();")->Run();
13444 v8::V8::ContextDisposedNotification();
13445 CheckSurvivingGlobalObjectsCount(0);
13450 TEST(CopyablePersistent) {
13451 LocalContext context;
13452 v8::Isolate* isolate = context->GetIsolate();
13453 i::GlobalHandles* globals =
13454 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13455 int initial_handles = globals->global_handles_count();
13456 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13459 CopyableObject handle1;
13461 v8::HandleScope scope(isolate);
13462 handle1.Reset(isolate, v8::Object::New(isolate));
13464 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13465 CopyableObject handle2;
13467 CHECK(handle1 == handle2);
13468 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13469 CopyableObject handle3(handle2);
13470 CHECK(handle1 == handle3);
13471 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13473 // Verify autodispose
13474 CHECK_EQ(initial_handles, globals->global_handles_count());
13478 static void WeakApiCallback(
13479 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13480 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13481 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13482 data.GetParameter()->Reset();
13483 delete data.GetParameter();
13487 TEST(WeakCallbackApi) {
13488 LocalContext context;
13489 v8::Isolate* isolate = context->GetIsolate();
13490 i::GlobalHandles* globals =
13491 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13492 int initial_handles = globals->global_handles_count();
13494 v8::HandleScope scope(isolate);
13495 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13496 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13497 v8::Persistent<v8::Object>* handle =
13498 new v8::Persistent<v8::Object>(isolate, obj);
13499 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13502 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13503 CollectAllGarbage(i::Heap::kNoGCFlags);
13504 // Verify disposed.
13505 CHECK_EQ(initial_handles, globals->global_handles_count());
13509 v8::Persistent<v8::Object> some_object;
13510 v8::Persistent<v8::Object> bad_handle;
13512 void NewPersistentHandleCallback(
13513 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13514 v8::HandleScope scope(data.GetIsolate());
13515 bad_handle.Reset(data.GetIsolate(), some_object);
13516 data.GetParameter()->Reset();
13520 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13521 LocalContext context;
13522 v8::Isolate* isolate = context->GetIsolate();
13524 v8::Persistent<v8::Object> handle1, handle2;
13526 v8::HandleScope scope(isolate);
13527 some_object.Reset(isolate, v8::Object::New(isolate));
13528 handle1.Reset(isolate, v8::Object::New(isolate));
13529 handle2.Reset(isolate, v8::Object::New(isolate));
13531 // Note: order is implementation dependent alas: currently
13532 // global handle nodes are processed by PostGarbageCollectionProcessing
13533 // in reverse allocation order, so if second allocated handle is deleted,
13534 // weak callback of the first handle would be able to 'reallocate' it.
13535 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13537 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13541 v8::Persistent<v8::Object> to_be_disposed;
13543 void DisposeAndForceGcCallback(
13544 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13545 to_be_disposed.Reset();
13546 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13547 data.GetParameter()->Reset();
13551 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13552 LocalContext context;
13553 v8::Isolate* isolate = context->GetIsolate();
13555 v8::Persistent<v8::Object> handle1, handle2;
13557 v8::HandleScope scope(isolate);
13558 handle1.Reset(isolate, v8::Object::New(isolate));
13559 handle2.Reset(isolate, v8::Object::New(isolate));
13561 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13562 to_be_disposed.Reset(isolate, handle2);
13563 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13566 void DisposingCallback(
13567 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13568 data.GetParameter()->Reset();
13571 void HandleCreatingCallback(
13572 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13573 v8::HandleScope scope(data.GetIsolate());
13574 v8::Persistent<v8::Object>(data.GetIsolate(),
13575 v8::Object::New(data.GetIsolate()));
13576 data.GetParameter()->Reset();
13580 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13581 LocalContext context;
13582 v8::Isolate* isolate = context->GetIsolate();
13584 v8::Persistent<v8::Object> handle1, handle2, handle3;
13586 v8::HandleScope scope(isolate);
13587 handle3.Reset(isolate, v8::Object::New(isolate));
13588 handle2.Reset(isolate, v8::Object::New(isolate));
13589 handle1.Reset(isolate, v8::Object::New(isolate));
13591 handle2.SetWeak(&handle2, DisposingCallback);
13592 handle3.SetWeak(&handle3, HandleCreatingCallback);
13593 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13597 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13598 v8::V8::Initialize();
13601 const char* sources[nof] = {
13602 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13606 for (int i = 0; i < nof; i++) {
13607 const char* source = sources[i];
13608 { v8::HandleScope scope(CcTest::isolate());
13609 LocalContext context;
13610 CompileRun(source);
13612 { v8::HandleScope scope(CcTest::isolate());
13613 LocalContext context;
13614 CompileRun(source);
13620 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13621 v8::EscapableHandleScope inner(env->GetIsolate());
13623 v8::Local<Value> three = v8_num(3);
13624 v8::Local<Value> value = inner.Escape(three);
13630 THREADED_TEST(NestedHandleScopeAndContexts) {
13631 v8::Isolate* isolate = CcTest::isolate();
13632 v8::HandleScope outer(isolate);
13633 v8::Local<Context> env = Context::New(isolate);
13635 v8::Handle<Value> value = NestedScope(env);
13636 v8::Handle<String> str(value->ToString());
13637 CHECK(!str.IsEmpty());
13642 static bool MatchPointers(void* key1, void* key2) {
13643 return key1 == key2;
13647 struct SymbolInfo {
13654 class SetFunctionEntryHookTest {
13656 SetFunctionEntryHookTest() {
13657 CHECK(instance_ == NULL);
13660 ~SetFunctionEntryHookTest() {
13661 CHECK(instance_ == this);
13666 symbol_locations_.clear();
13667 invocations_.clear();
13670 void OnJitEvent(const v8::JitCodeEvent* event);
13671 static void JitEvent(const v8::JitCodeEvent* event) {
13672 CHECK(instance_ != NULL);
13673 instance_->OnJitEvent(event);
13676 void OnEntryHook(uintptr_t function,
13677 uintptr_t return_addr_location);
13678 static void EntryHook(uintptr_t function,
13679 uintptr_t return_addr_location) {
13680 CHECK(instance_ != NULL);
13681 instance_->OnEntryHook(function, return_addr_location);
13684 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13685 CHECK(instance_ != NULL);
13686 args.GetReturnValue().Set(v8_num(42));
13688 void RunLoopInNewEnv(v8::Isolate* isolate);
13690 // Records addr as location of symbol.
13691 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13693 // Finds the symbol containing addr
13694 SymbolInfo* FindSymbolForAddr(i::Address addr);
13695 // Returns the number of invocations where the caller name contains
13696 // \p caller_name and the function name contains \p function_name.
13697 int CountInvocations(const char* caller_name,
13698 const char* function_name);
13700 i::Handle<i::JSFunction> foo_func_;
13701 i::Handle<i::JSFunction> bar_func_;
13703 typedef std::map<size_t, SymbolInfo> SymbolMap;
13704 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13705 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13706 SymbolMap symbols_;
13707 SymbolLocationMap symbol_locations_;
13708 InvocationMap invocations_;
13710 static SetFunctionEntryHookTest* instance_;
13712 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13715 // Returns true if addr is in the range [start, start+len).
13716 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13717 if (start <= addr && start + len > addr)
13723 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13724 SymbolInfo* symbol) {
13725 // Insert the symbol at the new location.
13726 SymbolLocationMap::iterator it =
13727 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13728 // Now erase symbols to the left and right that overlap this one.
13729 while (it != symbol_locations_.begin()) {
13730 SymbolLocationMap::iterator left = it;
13732 if (!Overlaps(left->first, left->second->size, addr))
13734 symbol_locations_.erase(left);
13737 // Now erase symbols to the left and right that overlap this one.
13739 SymbolLocationMap::iterator right = it;
13741 if (right == symbol_locations_.end())
13743 if (!Overlaps(addr, symbol->size, right->first))
13745 symbol_locations_.erase(right);
13750 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13751 switch (event->type) {
13752 case v8::JitCodeEvent::CODE_ADDED: {
13753 CHECK(event->code_start != NULL);
13754 CHECK_NE(0, static_cast<int>(event->code_len));
13755 CHECK(event->name.str != NULL);
13756 size_t symbol_id = symbols_.size();
13758 // Record the new symbol.
13759 SymbolInfo& info = symbols_[symbol_id];
13760 info.id = symbol_id;
13761 info.size = event->code_len;
13762 info.name.assign(event->name.str, event->name.str + event->name.len);
13764 // And record it's location.
13765 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13769 case v8::JitCodeEvent::CODE_MOVED: {
13770 // We would like to never see code move that we haven't seen before,
13771 // but the code creation event does not happen until the line endings
13772 // have been calculated (this is so that we can report the line in the
13773 // script at which the function source is found, see
13774 // Compiler::RecordFunctionCompilation) and the line endings
13775 // calculations can cause a GC, which can move the newly created code
13776 // before its existence can be logged.
13777 SymbolLocationMap::iterator it(
13778 symbol_locations_.find(
13779 reinterpret_cast<i::Address>(event->code_start)));
13780 if (it != symbol_locations_.end()) {
13781 // Found a symbol at this location, move it.
13782 SymbolInfo* info = it->second;
13783 symbol_locations_.erase(it);
13784 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13793 void SetFunctionEntryHookTest::OnEntryHook(
13794 uintptr_t function, uintptr_t return_addr_location) {
13795 // Get the function's code object.
13796 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13797 reinterpret_cast<i::Address>(function));
13798 CHECK(function_code != NULL);
13800 // Then try and look up the caller's code object.
13801 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13803 // Count the invocation.
13804 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13805 SymbolInfo* function_symbol =
13806 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13807 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13809 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13810 // Check that we have a symbol for the "bar" function at the right location.
13811 SymbolLocationMap::iterator it(
13812 symbol_locations_.find(function_code->instruction_start()));
13813 CHECK(it != symbol_locations_.end());
13816 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13817 // Check that we have a symbol for "foo" at the right location.
13818 SymbolLocationMap::iterator it(
13819 symbol_locations_.find(function_code->instruction_start()));
13820 CHECK(it != symbol_locations_.end());
13825 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13826 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13827 // Do we have a direct hit on a symbol?
13828 if (it != symbol_locations_.end()) {
13829 if (it->first == addr)
13833 // If not a direct hit, it'll have to be the previous symbol.
13834 if (it == symbol_locations_.begin())
13838 size_t offs = addr - it->first;
13839 if (offs < it->second->size)
13846 int SetFunctionEntryHookTest::CountInvocations(
13847 const char* caller_name, const char* function_name) {
13848 InvocationMap::iterator it(invocations_.begin());
13849 int invocations = 0;
13850 for (; it != invocations_.end(); ++it) {
13851 SymbolInfo* caller = it->first.first;
13852 SymbolInfo* function = it->first.second;
13854 // Filter out non-matching functions.
13855 if (function_name != NULL) {
13856 if (function->name.find(function_name) == std::string::npos)
13860 // Filter out non-matching callers.
13861 if (caller_name != NULL) {
13862 if (caller == NULL)
13864 if (caller->name.find(caller_name) == std::string::npos)
13868 // It matches add the invocation count to the tally.
13869 invocations += it->second;
13872 return invocations;
13876 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13877 v8::HandleScope outer(isolate);
13878 v8::Local<Context> env = Context::New(isolate);
13881 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13882 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13883 env->Global()->Set(v8_str("obj"), t->NewInstance());
13885 const char* script =
13886 "function bar() {\n"
13888 " for (i = 0; i < 100; ++i)\n"
13892 "function foo(i) { return i * i; }\n"
13893 "// Invoke on the runtime function.\n"
13895 CompileRun(script);
13896 bar_func_ = i::Handle<i::JSFunction>::cast(
13897 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13898 ASSERT(!bar_func_.is_null());
13901 i::Handle<i::JSFunction>::cast(
13902 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13903 ASSERT(!foo_func_.is_null());
13905 v8::Handle<v8::Value> value = CompileRun("bar();");
13906 CHECK(value->IsNumber());
13907 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13909 // Test the optimized codegen path.
13910 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13912 CHECK(value->IsNumber());
13913 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13919 void SetFunctionEntryHookTest::RunTest() {
13920 // Work in a new isolate throughout.
13921 v8::Isolate* isolate = v8::Isolate::New();
13923 // Test setting the entry hook on the new isolate.
13924 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13926 // Replacing the hook, once set should fail.
13927 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13930 v8::Isolate::Scope scope(isolate);
13932 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13934 RunLoopInNewEnv(isolate);
13936 // Check the exepected invocation counts.
13937 CHECK_EQ(2, CountInvocations(NULL, "bar"));
13938 CHECK_EQ(200, CountInvocations("bar", "foo"));
13939 CHECK_EQ(200, CountInvocations(NULL, "foo"));
13941 // Verify that we have an entry hook on some specific stubs.
13942 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13943 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13944 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13946 isolate->Dispose();
13950 // Make sure a second isolate is unaffected by the previous entry hook.
13951 isolate = v8::Isolate::New();
13953 v8::Isolate::Scope scope(isolate);
13955 // Reset the entry count to zero and set the entry hook.
13956 RunLoopInNewEnv(isolate);
13958 // We should record no invocations in this isolate.
13959 CHECK_EQ(0, static_cast<int>(invocations_.size()));
13961 // Since the isolate has been used, we shouldn't be able to set an entry
13963 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13965 isolate->Dispose();
13969 TEST(SetFunctionEntryHook) {
13970 // FunctionEntryHook does not work well with experimental natives.
13971 // Experimental natives are compiled during snapshot deserialization.
13972 // This test breaks because InstallGetter (function from snapshot that
13973 // only gets called from experimental natives) is compiled with entry hooks.
13974 i::FLAG_allow_natives_syntax = true;
13975 i::FLAG_use_inlining = false;
13977 SetFunctionEntryHookTest test;
13982 static i::HashMap* code_map = NULL;
13983 static i::HashMap* jitcode_line_info = NULL;
13984 static int saw_bar = 0;
13985 static int move_events = 0;
13988 static bool FunctionNameIs(const char* expected,
13989 const v8::JitCodeEvent* event) {
13990 // Log lines for functions are of the general form:
13991 // "LazyCompile:<type><function_name>", where the type is one of
13993 static const char kPreamble[] = "LazyCompile:";
13994 static size_t kPreambleLen = sizeof(kPreamble) - 1;
13996 if (event->name.len < sizeof(kPreamble) - 1 ||
13997 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14001 const char* tail = event->name.str + kPreambleLen;
14002 size_t tail_len = event->name.len - kPreambleLen;
14003 size_t expected_len = strlen(expected);
14004 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14009 // Check for tails like 'bar :1'.
14010 if (tail_len > expected_len + 2 &&
14011 tail[expected_len] == ' ' &&
14012 tail[expected_len + 1] == ':' &&
14013 tail[expected_len + 2] &&
14014 !strncmp(tail, expected, expected_len)) {
14018 if (tail_len != expected_len)
14021 return strncmp(tail, expected, expected_len) == 0;
14025 static void event_handler(const v8::JitCodeEvent* event) {
14026 CHECK(event != NULL);
14027 CHECK(code_map != NULL);
14028 CHECK(jitcode_line_info != NULL);
14030 class DummyJitCodeLineInfo {
14033 switch (event->type) {
14034 case v8::JitCodeEvent::CODE_ADDED: {
14035 CHECK(event->code_start != NULL);
14036 CHECK_NE(0, static_cast<int>(event->code_len));
14037 CHECK(event->name.str != NULL);
14038 i::HashMap::Entry* entry =
14039 code_map->Lookup(event->code_start,
14040 i::ComputePointerHash(event->code_start),
14042 entry->value = reinterpret_cast<void*>(event->code_len);
14044 if (FunctionNameIs("bar", event)) {
14050 case v8::JitCodeEvent::CODE_MOVED: {
14051 uint32_t hash = i::ComputePointerHash(event->code_start);
14052 // We would like to never see code move that we haven't seen before,
14053 // but the code creation event does not happen until the line endings
14054 // have been calculated (this is so that we can report the line in the
14055 // script at which the function source is found, see
14056 // Compiler::RecordFunctionCompilation) and the line endings
14057 // calculations can cause a GC, which can move the newly created code
14058 // before its existence can be logged.
14059 i::HashMap::Entry* entry =
14060 code_map->Lookup(event->code_start, hash, false);
14061 if (entry != NULL) {
14064 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14065 code_map->Remove(event->code_start, hash);
14067 entry = code_map->Lookup(event->new_code_start,
14068 i::ComputePointerHash(event->new_code_start),
14070 CHECK(entry != NULL);
14071 entry->value = reinterpret_cast<void*>(event->code_len);
14076 case v8::JitCodeEvent::CODE_REMOVED:
14077 // Object/code removal events are currently not dispatched from the GC.
14081 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14082 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14083 // record it in jitcode_line_info.
14084 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14085 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14086 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14087 temp_event->user_data = line_info;
14088 i::HashMap::Entry* entry =
14089 jitcode_line_info->Lookup(line_info,
14090 i::ComputePointerHash(line_info),
14092 entry->value = reinterpret_cast<void*>(line_info);
14095 // For these two events, we will check whether the event->user_data
14096 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14097 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14098 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14099 CHECK(event->user_data != NULL);
14100 uint32_t hash = i::ComputePointerHash(event->user_data);
14101 i::HashMap::Entry* entry =
14102 jitcode_line_info->Lookup(event->user_data, hash, false);
14103 CHECK(entry != NULL);
14104 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14108 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14109 CHECK(event->user_data != NULL);
14110 uint32_t hash = i::ComputePointerHash(event->user_data);
14111 i::HashMap::Entry* entry =
14112 jitcode_line_info->Lookup(event->user_data, hash, false);
14113 CHECK(entry != NULL);
14118 // Impossible event.
14125 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14126 i::FLAG_stress_compaction = true;
14127 i::FLAG_incremental_marking = false;
14128 const char* script =
14131 " for (i = 0; i < 100; ++i)"
14135 "function foo(i) { return i * i; };"
14138 // Run this test in a new isolate to make sure we don't
14139 // have remnants of state from other code.
14140 v8::Isolate* isolate = v8::Isolate::New();
14142 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14143 i::Heap* heap = i_isolate->heap();
14146 v8::HandleScope scope(isolate);
14147 i::HashMap code(MatchPointers);
14150 i::HashMap lineinfo(MatchPointers);
14151 jitcode_line_info = &lineinfo;
14156 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14158 // Generate new code objects sparsely distributed across several
14159 // different fragmented code-space pages.
14160 const int kIterations = 10;
14161 for (int i = 0; i < kIterations; ++i) {
14162 LocalContext env(isolate);
14163 i::AlwaysAllocateScope always_allocate(i_isolate);
14164 SimulateFullSpace(heap->code_space());
14165 CompileRun(script);
14167 // Keep a strong reference to the code object in the handle scope.
14168 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14169 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14170 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14171 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14173 // Clear the compilation cache to get more wastage.
14174 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14177 // Force code movement.
14178 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14180 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14182 CHECK_LE(kIterations, saw_bar);
14183 CHECK_LT(0, move_events);
14186 jitcode_line_info = NULL;
14190 isolate->Dispose();
14192 // Do this in a new isolate.
14193 isolate = v8::Isolate::New();
14196 // Verify that we get callbacks for existing code objects when we
14197 // request enumeration of existing code.
14199 v8::HandleScope scope(isolate);
14200 LocalContext env(isolate);
14201 CompileRun(script);
14203 // Now get code through initial iteration.
14204 i::HashMap code(MatchPointers);
14207 i::HashMap lineinfo(MatchPointers);
14208 jitcode_line_info = &lineinfo;
14210 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14211 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14213 jitcode_line_info = NULL;
14214 // We expect that we got some events. Note that if we could get code removal
14215 // notifications, we could compare two collections, one created by listening
14216 // from the time of creation of an isolate, and the other by subscribing
14217 // with EnumExisting.
14218 CHECK_LT(0, code.occupancy());
14224 isolate->Dispose();
14228 THREADED_TEST(ExternalAllocatedMemory) {
14229 v8::Isolate* isolate = CcTest::isolate();
14230 v8::HandleScope outer(isolate);
14231 v8::Local<Context> env(Context::New(isolate));
14232 CHECK(!env.IsEmpty());
14233 const int64_t kSize = 1024*1024;
14234 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14235 CHECK_EQ(baseline + kSize,
14236 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14238 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14242 // Regression test for issue 54, object templates with internal fields
14243 // but no accessors or interceptors did not get their internal field
14244 // count set on instances.
14245 THREADED_TEST(Regress54) {
14246 LocalContext context;
14247 v8::Isolate* isolate = context->GetIsolate();
14248 v8::HandleScope outer(isolate);
14249 static v8::Persistent<v8::ObjectTemplate> templ;
14250 if (templ.IsEmpty()) {
14251 v8::EscapableHandleScope inner(isolate);
14252 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14253 local->SetInternalFieldCount(1);
14254 templ.Reset(isolate, inner.Escape(local));
14256 v8::Handle<v8::Object> result =
14257 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14258 CHECK_EQ(1, result->InternalFieldCount());
14262 // If part of the threaded tests, this test makes ThreadingTest fail
14264 TEST(CatchStackOverflow) {
14265 LocalContext context;
14266 v8::HandleScope scope(context->GetIsolate());
14267 v8::TryCatch try_catch;
14268 v8::Handle<v8::Value> result = CompileRun(
14274 CHECK(result.IsEmpty());
14278 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14279 const char* resource_name,
14281 v8::HandleScope scope(CcTest::isolate());
14282 v8::TryCatch try_catch;
14283 v8::Handle<v8::Value> result = script->Run();
14284 CHECK(result.IsEmpty());
14285 CHECK(try_catch.HasCaught());
14286 v8::Handle<v8::Message> message = try_catch.Message();
14287 CHECK(!message.IsEmpty());
14288 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14289 CHECK_EQ(91, message->GetStartPosition());
14290 CHECK_EQ(92, message->GetEndPosition());
14291 CHECK_EQ(2, message->GetStartColumn());
14292 CHECK_EQ(3, message->GetEndColumn());
14293 v8::String::Utf8Value line(message->GetSourceLine());
14294 CHECK_EQ(" throw 'nirk';", *line);
14295 v8::String::Utf8Value name(message->GetScriptResourceName());
14296 CHECK_EQ(resource_name, *name);
14300 THREADED_TEST(TryCatchSourceInfo) {
14301 LocalContext context;
14302 v8::HandleScope scope(context->GetIsolate());
14303 v8::Local<v8::String> source = v8_str(
14304 "function Foo() {\n"
14308 "function Bar() {\n"
14312 "function Baz() {\n"
14318 const char* resource_name;
14319 v8::Handle<v8::Script> script;
14320 resource_name = "test.js";
14321 script = CompileWithOrigin(source, resource_name);
14322 CheckTryCatchSourceInfo(script, resource_name, 0);
14324 resource_name = "test1.js";
14325 v8::ScriptOrigin origin1(
14326 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14327 script = v8::Script::Compile(source, &origin1);
14328 CheckTryCatchSourceInfo(script, resource_name, 0);
14330 resource_name = "test2.js";
14331 v8::ScriptOrigin origin2(
14332 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14333 v8::Integer::New(context->GetIsolate(), 7));
14334 script = v8::Script::Compile(source, &origin2);
14335 CheckTryCatchSourceInfo(script, resource_name, 7);
14339 THREADED_TEST(CompilationCache) {
14340 LocalContext context;
14341 v8::HandleScope scope(context->GetIsolate());
14342 v8::Handle<v8::String> source0 =
14343 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14344 v8::Handle<v8::String> source1 =
14345 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14346 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14347 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14348 v8::Handle<v8::Script> script2 =
14349 v8::Script::Compile(source0); // different origin
14350 CHECK_EQ(1234, script0->Run()->Int32Value());
14351 CHECK_EQ(1234, script1->Run()->Int32Value());
14352 CHECK_EQ(1234, script2->Run()->Int32Value());
14356 static void FunctionNameCallback(
14357 const v8::FunctionCallbackInfo<v8::Value>& args) {
14358 ApiTestFuzzer::Fuzz();
14359 args.GetReturnValue().Set(v8_num(42));
14363 THREADED_TEST(CallbackFunctionName) {
14364 LocalContext context;
14365 v8::Isolate* isolate = context->GetIsolate();
14366 v8::HandleScope scope(isolate);
14367 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14368 t->Set(v8_str("asdf"),
14369 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14370 context->Global()->Set(v8_str("obj"), t->NewInstance());
14371 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14372 CHECK(value->IsString());
14373 v8::String::Utf8Value name(value);
14374 CHECK_EQ("asdf", *name);
14378 THREADED_TEST(DateAccess) {
14379 LocalContext context;
14380 v8::HandleScope scope(context->GetIsolate());
14381 v8::Handle<v8::Value> date =
14382 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14383 CHECK(date->IsDate());
14384 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14388 void CheckProperties(v8::Isolate* isolate,
14389 v8::Handle<v8::Value> val,
14391 const char* elmv[]) {
14392 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14393 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14394 CHECK_EQ(elmc, props->Length());
14395 for (int i = 0; i < elmc; i++) {
14396 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14397 CHECK_EQ(elmv[i], *elm);
14402 void CheckOwnProperties(v8::Isolate* isolate,
14403 v8::Handle<v8::Value> val,
14405 const char* elmv[]) {
14406 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14407 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14408 CHECK_EQ(elmc, props->Length());
14409 for (int i = 0; i < elmc; i++) {
14410 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14411 CHECK_EQ(elmv[i], *elm);
14416 THREADED_TEST(PropertyEnumeration) {
14417 LocalContext context;
14418 v8::Isolate* isolate = context->GetIsolate();
14419 v8::HandleScope scope(isolate);
14420 v8::Handle<v8::Value> obj = CompileRun(
14423 "result[1] = {a: 1, b: 2};"
14424 "result[2] = [1, 2, 3];"
14425 "var proto = {x: 1, y: 2, z: 3};"
14426 "var x = { __proto__: proto, w: 0, z: 1 };"
14429 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14430 CHECK_EQ(4, elms->Length());
14432 const char** elmv0 = NULL;
14434 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14435 CheckOwnProperties(
14436 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14438 const char* elmv1[] = {"a", "b"};
14440 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14441 CheckOwnProperties(
14442 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14444 const char* elmv2[] = {"0", "1", "2"};
14446 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14447 CheckOwnProperties(
14448 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14450 const char* elmv3[] = {"w", "z", "x", "y"};
14452 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14454 const char* elmv4[] = {"w", "z"};
14455 CheckOwnProperties(
14456 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14460 THREADED_TEST(PropertyEnumeration2) {
14461 LocalContext context;
14462 v8::Isolate* isolate = context->GetIsolate();
14463 v8::HandleScope scope(isolate);
14464 v8::Handle<v8::Value> obj = CompileRun(
14467 "result[1] = {a: 1, b: 2};"
14468 "result[2] = [1, 2, 3];"
14469 "var proto = {x: 1, y: 2, z: 3};"
14470 "var x = { __proto__: proto, w: 0, z: 1 };"
14473 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14474 CHECK_EQ(4, elms->Length());
14476 const char** elmv0 = NULL;
14477 CheckProperties(isolate,
14478 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14480 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14481 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14482 CHECK_EQ(0, props->Length());
14483 for (uint32_t i = 0; i < props->Length(); i++) {
14484 printf("p[%d]\n", i);
14488 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14490 v8::AccessType type,
14491 Local<Value> data) {
14492 return type != v8::ACCESS_SET;
14496 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14498 v8::AccessType type,
14499 Local<Value> data) {
14500 return type != v8::ACCESS_SET;
14504 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14505 LocalContext context;
14506 v8::Isolate* isolate = context->GetIsolate();
14507 v8::HandleScope scope(isolate);
14508 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14509 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14510 IndexedSetAccessBlocker);
14511 templ->Set(v8_str("x"), v8::True(isolate));
14512 Local<v8::Object> instance = templ->NewInstance();
14513 context->Global()->Set(v8_str("obj"), instance);
14514 Local<Value> value = CompileRun("obj.x");
14515 CHECK(value->BooleanValue());
14519 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14521 v8::AccessType type,
14522 Local<Value> data) {
14527 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14529 v8::AccessType type,
14530 Local<Value> data) {
14536 THREADED_TEST(AccessChecksReenabledCorrectly) {
14537 LocalContext context;
14538 v8::Isolate* isolate = context->GetIsolate();
14539 v8::HandleScope scope(isolate);
14540 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14541 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14542 IndexedGetAccessBlocker);
14543 templ->Set(v8_str("a"), v8_str("a"));
14544 // Add more than 8 (see kMaxFastProperties) properties
14545 // so that the constructor will force copying map.
14546 // Cannot sprintf, gcc complains unsafety.
14548 for (char i = '0'; i <= '9' ; i++) {
14550 for (char j = '0'; j <= '9'; j++) {
14552 for (char k = '0'; k <= '9'; k++) {
14555 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14560 Local<v8::Object> instance_1 = templ->NewInstance();
14561 context->Global()->Set(v8_str("obj_1"), instance_1);
14563 Local<Value> value_1 = CompileRun("obj_1.a");
14564 CHECK(value_1->IsUndefined());
14566 Local<v8::Object> instance_2 = templ->NewInstance();
14567 context->Global()->Set(v8_str("obj_2"), instance_2);
14569 Local<Value> value_2 = CompileRun("obj_2.a");
14570 CHECK(value_2->IsUndefined());
14574 // This tests that access check information remains on the global
14575 // object template when creating contexts.
14576 THREADED_TEST(AccessControlRepeatedContextCreation) {
14577 v8::Isolate* isolate = CcTest::isolate();
14578 v8::HandleScope handle_scope(isolate);
14579 v8::Handle<v8::ObjectTemplate> global_template =
14580 v8::ObjectTemplate::New(isolate);
14581 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14582 IndexedSetAccessBlocker);
14583 i::Handle<i::ObjectTemplateInfo> internal_template =
14584 v8::Utils::OpenHandle(*global_template);
14585 CHECK(!internal_template->constructor()->IsUndefined());
14586 i::Handle<i::FunctionTemplateInfo> constructor(
14587 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14588 CHECK(!constructor->access_check_info()->IsUndefined());
14589 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14590 CHECK(!context0.IsEmpty());
14591 CHECK(!constructor->access_check_info()->IsUndefined());
14595 THREADED_TEST(TurnOnAccessCheck) {
14596 v8::Isolate* isolate = CcTest::isolate();
14597 v8::HandleScope handle_scope(isolate);
14599 // Create an environment with access check to the global object disabled by
14601 v8::Handle<v8::ObjectTemplate> global_template =
14602 v8::ObjectTemplate::New(isolate);
14603 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14604 IndexedGetAccessBlocker,
14605 v8::Handle<v8::Value>(),
14607 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14608 Context::Scope context_scope(context);
14610 // Set up a property and a number of functions.
14611 context->Global()->Set(v8_str("a"), v8_num(1));
14612 CompileRun("function f1() {return a;}"
14613 "function f2() {return a;}"
14614 "function g1() {return h();}"
14615 "function g2() {return h();}"
14616 "function h() {return 1;}");
14617 Local<Function> f1 =
14618 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14619 Local<Function> f2 =
14620 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14621 Local<Function> g1 =
14622 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14623 Local<Function> g2 =
14624 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14625 Local<Function> h =
14626 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14628 // Get the global object.
14629 v8::Handle<v8::Object> global = context->Global();
14631 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14632 // uses the runtime system to retreive property a whereas f2 uses global load
14634 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14635 for (int i = 0; i < 4; i++) {
14636 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14639 // Same for g1 and g2.
14640 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14641 for (int i = 0; i < 4; i++) {
14642 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14645 // Detach the global and turn on access check.
14646 Local<Object> hidden_global = Local<Object>::Cast(
14647 context->Global()->GetPrototype());
14648 context->DetachGlobal();
14649 hidden_global->TurnOnAccessCheck();
14651 // Failing access check to property get results in undefined.
14652 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14653 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14655 // Failing access check to function call results in exception.
14656 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14657 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14659 // No failing access check when just returning a constant.
14660 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14664 static const char* kPropertyA = "a";
14665 static const char* kPropertyH = "h";
14667 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14669 v8::AccessType type,
14670 Local<Value> data) {
14671 if (!name->IsString()) return false;
14672 i::Handle<i::String> name_handle =
14673 v8::Utils::OpenHandle(String::Cast(*name));
14674 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14675 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14679 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14680 v8::Isolate* isolate = CcTest::isolate();
14681 v8::HandleScope handle_scope(isolate);
14683 // Create an environment with access check to the global object disabled by
14684 // default. When the registered access checker will block access to properties
14686 v8::Handle<v8::ObjectTemplate> global_template =
14687 v8::ObjectTemplate::New(isolate);
14688 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14689 IndexedGetAccessBlocker,
14690 v8::Handle<v8::Value>(),
14692 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14693 Context::Scope context_scope(context);
14695 // Set up a property and a number of functions.
14696 context->Global()->Set(v8_str("a"), v8_num(1));
14697 static const char* source = "function f1() {return a;}"
14698 "function f2() {return a;}"
14699 "function g1() {return h();}"
14700 "function g2() {return h();}"
14701 "function h() {return 1;}";
14703 CompileRun(source);
14704 Local<Function> f1;
14705 Local<Function> f2;
14706 Local<Function> g1;
14707 Local<Function> g2;
14709 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14710 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14711 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14712 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14713 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14715 // Get the global object.
14716 v8::Handle<v8::Object> global = context->Global();
14718 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14719 // uses the runtime system to retreive property a whereas f2 uses global load
14721 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14722 for (int i = 0; i < 4; i++) {
14723 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14726 // Same for g1 and g2.
14727 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14728 for (int i = 0; i < 4; i++) {
14729 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14732 // Detach the global and turn on access check now blocking access to property
14733 // a and function h.
14734 Local<Object> hidden_global = Local<Object>::Cast(
14735 context->Global()->GetPrototype());
14736 context->DetachGlobal();
14737 hidden_global->TurnOnAccessCheck();
14739 // Failing access check to property get results in undefined.
14740 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14741 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14743 // Failing access check to function call results in exception.
14744 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14745 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14747 // No failing access check when just returning a constant.
14748 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14750 // Now compile the source again. And get the newly compiled functions, except
14751 // for h for which access is blocked.
14752 CompileRun(source);
14753 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14754 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14755 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14756 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14757 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14759 // Failing access check to property get results in undefined.
14760 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14761 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14763 // Failing access check to function call results in exception.
14764 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14765 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14769 // This test verifies that pre-compilation (aka preparsing) can be called
14770 // without initializing the whole VM. Thus we cannot run this test in a
14771 // multi-threaded setup.
14773 // TODO(155): This test would break without the initialization of V8. This is
14774 // a workaround for now to make this test not fail.
14775 v8::V8::Initialize();
14776 v8::Isolate* isolate = CcTest::isolate();
14777 HandleScope handle_scope(isolate);
14778 const char* script = "function foo(a) { return a+1; }";
14779 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14780 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14781 CHECK_NE(sd->Length(), 0);
14782 CHECK_NE(sd->Data(), NULL);
14783 CHECK(!sd->HasError());
14788 TEST(PreCompileWithError) {
14789 v8::V8::Initialize();
14790 v8::Isolate* isolate = CcTest::isolate();
14791 HandleScope handle_scope(isolate);
14792 const char* script = "function foo(a) { return 1 * * 2; }";
14793 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14794 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14795 CHECK(sd->HasError());
14800 TEST(Regress31661) {
14801 v8::V8::Initialize();
14802 v8::Isolate* isolate = CcTest::isolate();
14803 HandleScope handle_scope(isolate);
14804 const char* script = " The Definintive Guide";
14805 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14806 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14807 CHECK(sd->HasError());
14812 // Tests that ScriptData can be serialized and deserialized.
14813 TEST(PreCompileSerialization) {
14814 v8::V8::Initialize();
14815 v8::Isolate* isolate = CcTest::isolate();
14816 HandleScope handle_scope(isolate);
14817 const char* script = "function foo(a) { return a+1; }";
14818 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14819 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14822 int serialized_data_length = sd->Length();
14823 char* serialized_data = i::NewArray<char>(serialized_data_length);
14824 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14827 v8::ScriptData* deserialized_sd =
14828 v8::ScriptData::New(serialized_data, serialized_data_length);
14830 // Verify that the original is the same as the deserialized.
14831 CHECK_EQ(sd->Length(), deserialized_sd->Length());
14832 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14833 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14836 delete deserialized_sd;
14837 i::DeleteArray(serialized_data);
14841 // Attempts to deserialize bad data.
14842 TEST(PreCompileDeserializationError) {
14843 v8::V8::Initialize();
14844 const char* data = "DONT CARE";
14845 int invalid_size = 3;
14846 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14848 CHECK_EQ(0, sd->Length());
14854 // Attempts to deserialize bad data.
14855 TEST(PreCompileInvalidPreparseDataError) {
14856 v8::V8::Initialize();
14857 v8::Isolate* isolate = CcTest::isolate();
14858 LocalContext context;
14859 v8::HandleScope scope(context->GetIsolate());
14861 const char* script = "function foo(){ return 5;}\n"
14862 "function bar(){ return 6 + 7;} foo();";
14863 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14864 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14865 CHECK(!sd->HasError());
14866 // ScriptDataImpl private implementation details
14867 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14868 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14869 const int kFunctionEntryStartOffset = 0;
14870 const int kFunctionEntryEndOffset = 1;
14871 unsigned* sd_data =
14872 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14874 // Overwrite function bar's end position with 0.
14875 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14876 v8::TryCatch try_catch;
14878 v8::ScriptCompiler::Source script_source(
14879 String::NewFromUtf8(isolate, script),
14880 new v8::ScriptCompiler::CachedData(
14881 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14882 Local<v8::UnboundScript> compiled_script =
14883 v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
14885 CHECK(try_catch.HasCaught());
14886 String::Utf8Value exception_value(try_catch.Message()->Get());
14887 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14893 // Overwrite function bar's start position with 200. The function entry
14894 // will not be found when searching for it by position and we should fall
14895 // back on eager compilation.
14896 sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14897 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14898 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14899 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14901 v8::ScriptCompiler::Source script_source2(
14902 String::NewFromUtf8(isolate, script),
14903 new v8::ScriptCompiler::CachedData(
14904 reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14906 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2);
14907 CHECK(!try_catch.HasCaught());
14913 // This tests that we do not allow dictionary load/call inline caches
14914 // to use functions that have not yet been compiled. The potential
14915 // problem of loading a function that has not yet been compiled can
14916 // arise because we share code between contexts via the compilation
14918 THREADED_TEST(DictionaryICLoadedFunction) {
14919 v8::HandleScope scope(CcTest::isolate());
14921 for (int i = 0; i < 2; i++) {
14922 LocalContext context;
14923 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14924 context->Global()->Delete(v8_str("tmp"));
14925 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14928 for (int i = 0; i < 2; i++) {
14929 LocalContext context;
14930 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14931 context->Global()->Delete(v8_str("tmp"));
14932 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14937 // Test that cross-context new calls use the context of the callee to
14938 // create the new JavaScript object.
14939 THREADED_TEST(CrossContextNew) {
14940 v8::Isolate* isolate = CcTest::isolate();
14941 v8::HandleScope scope(isolate);
14942 v8::Local<Context> context0 = Context::New(isolate);
14943 v8::Local<Context> context1 = Context::New(isolate);
14945 // Allow cross-domain access.
14946 Local<String> token = v8_str("<security token>");
14947 context0->SetSecurityToken(token);
14948 context1->SetSecurityToken(token);
14950 // Set an 'x' property on the Object prototype and define a
14951 // constructor function in context0.
14953 CompileRun("Object.prototype.x = 42; function C() {};");
14956 // Call the constructor function from context0 and check that the
14957 // result has the 'x' property.
14959 context1->Global()->Set(v8_str("other"), context0->Global());
14960 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14961 CHECK(value->IsInt32());
14962 CHECK_EQ(42, value->Int32Value());
14967 // Verify that we can clone an object
14968 TEST(ObjectClone) {
14970 v8::Isolate* isolate = env->GetIsolate();
14971 v8::HandleScope scope(isolate);
14973 const char* sample =
14975 "rv.alpha = 'hello';" \
14979 // Create an object, verify basics.
14980 Local<Value> val = CompileRun(sample);
14981 CHECK(val->IsObject());
14982 Local<v8::Object> obj = val.As<v8::Object>();
14983 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14985 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14986 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14987 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14990 Local<v8::Object> clone = obj->Clone();
14991 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14992 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14993 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14995 // Set a property on the clone, verify each object.
14996 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
14997 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14998 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15002 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15004 explicit AsciiVectorResource(i::Vector<const char> vector)
15006 virtual ~AsciiVectorResource() {}
15007 virtual size_t length() const { return data_.length(); }
15008 virtual const char* data() const { return data_.start(); }
15010 i::Vector<const char> data_;
15014 class UC16VectorResource : public v8::String::ExternalStringResource {
15016 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15018 virtual ~UC16VectorResource() {}
15019 virtual size_t length() const { return data_.length(); }
15020 virtual const i::uc16* data() const { return data_.start(); }
15022 i::Vector<const i::uc16> data_;
15026 static void MorphAString(i::String* string,
15027 AsciiVectorResource* ascii_resource,
15028 UC16VectorResource* uc16_resource) {
15029 CHECK(i::StringShape(string).IsExternal());
15030 if (string->IsOneByteRepresentation()) {
15031 // Check old map is not internalized or long.
15032 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15033 // Morph external string to be TwoByte string.
15034 string->set_map(CcTest::heap()->external_string_map());
15035 i::ExternalTwoByteString* morphed =
15036 i::ExternalTwoByteString::cast(string);
15037 morphed->set_resource(uc16_resource);
15039 // Check old map is not internalized or long.
15040 CHECK(string->map() == CcTest::heap()->external_string_map());
15041 // Morph external string to be ASCII string.
15042 string->set_map(CcTest::heap()->external_ascii_string_map());
15043 i::ExternalAsciiString* morphed =
15044 i::ExternalAsciiString::cast(string);
15045 morphed->set_resource(ascii_resource);
15050 // Test that we can still flatten a string if the components it is built up
15051 // from have been turned into 16 bit strings in the mean time.
15052 THREADED_TEST(MorphCompositeStringTest) {
15053 char utf_buffer[129];
15054 const char* c_string = "Now is the time for all good men"
15055 " to come to the aid of the party";
15056 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15059 i::Factory* factory = CcTest::i_isolate()->factory();
15060 v8::HandleScope scope(env->GetIsolate());
15061 AsciiVectorResource ascii_resource(
15062 i::Vector<const char>(c_string, i::StrLength(c_string)));
15063 UC16VectorResource uc16_resource(
15064 i::Vector<const uint16_t>(two_byte_string,
15065 i::StrLength(c_string)));
15067 Local<String> lhs(v8::Utils::ToLocal(
15068 factory->NewExternalStringFromAscii(&ascii_resource)));
15069 Local<String> rhs(v8::Utils::ToLocal(
15070 factory->NewExternalStringFromAscii(&ascii_resource)));
15072 env->Global()->Set(v8_str("lhs"), lhs);
15073 env->Global()->Set(v8_str("rhs"), rhs);
15076 "var cons = lhs + rhs;"
15077 "var slice = lhs.substring(1, lhs.length - 1);"
15078 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15080 CHECK(lhs->IsOneByte());
15081 CHECK(rhs->IsOneByte());
15083 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15084 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15086 // This should UTF-8 without flattening, since everything is ASCII.
15087 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15088 CHECK_EQ(128, cons->Utf8Length());
15090 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15091 CHECK_EQ(128, nchars);
15092 CHECK_EQ(0, strcmp(
15094 "Now is the time for all good men to come to the aid of the party"
15095 "Now is the time for all good men to come to the aid of the party"));
15097 // Now do some stuff to make sure the strings are flattened, etc.
15099 "/[^a-z]/.test(cons);"
15100 "/[^a-z]/.test(slice);"
15101 "/[^a-z]/.test(slice_on_cons);");
15102 const char* expected_cons =
15103 "Now is the time for all good men to come to the aid of the party"
15104 "Now is the time for all good men to come to the aid of the party";
15105 const char* expected_slice =
15106 "ow is the time for all good men to come to the aid of the part";
15107 const char* expected_slice_on_cons =
15108 "ow is the time for all good men to come to the aid of the party"
15109 "Now is the time for all good men to come to the aid of the part";
15110 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15111 env->Global()->Get(v8_str("cons")));
15112 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15113 env->Global()->Get(v8_str("slice")));
15114 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15115 env->Global()->Get(v8_str("slice_on_cons")));
15117 i::DeleteArray(two_byte_string);
15121 TEST(CompileExternalTwoByteSource) {
15122 LocalContext context;
15123 v8::HandleScope scope(context->GetIsolate());
15125 // This is a very short list of sources, which currently is to check for a
15126 // regression caused by r2703.
15127 const char* ascii_sources[] = {
15129 "-0.5", // This mainly testes PushBack in the Scanner.
15130 "--0.5", // This mainly testes PushBack in the Scanner.
15134 // Compile the sources as external two byte strings.
15135 for (int i = 0; ascii_sources[i] != NULL; i++) {
15136 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15137 TestResource* uc16_resource = new TestResource(two_byte_string);
15138 v8::Local<v8::String> source =
15139 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15140 v8::Script::Compile(source);
15145 #ifndef V8_INTERPRETED_REGEXP
15147 struct RegExpInterruptionData {
15149 UC16VectorResource* string_resource;
15150 v8::Persistent<v8::String> string;
15151 } regexp_interruption_data;
15154 class RegExpInterruptionThread : public i::Thread {
15156 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15157 : Thread("TimeoutThread"), isolate_(isolate) {}
15159 virtual void Run() {
15160 for (regexp_interruption_data.loop_count = 0;
15161 regexp_interruption_data.loop_count < 7;
15162 regexp_interruption_data.loop_count++) {
15163 i::OS::Sleep(50); // Wait a bit before requesting GC.
15164 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15166 i::OS::Sleep(50); // Wait a bit before terminating.
15167 v8::V8::TerminateExecution(isolate_);
15171 v8::Isolate* isolate_;
15175 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15176 if (regexp_interruption_data.loop_count != 2) return;
15177 v8::HandleScope scope(CcTest::isolate());
15178 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15179 CcTest::isolate(), regexp_interruption_data.string);
15180 string->MakeExternal(regexp_interruption_data.string_resource);
15184 // Test that RegExp execution can be interrupted. Specifically, we test
15185 // * interrupting with GC
15186 // * turn the subject string from one-byte internal to two-byte external string
15187 // * force termination
15188 TEST(RegExpInterruption) {
15189 v8::HandleScope scope(CcTest::isolate());
15192 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15194 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15195 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15196 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15197 v8::Local<v8::String> string = v8_str(ascii_content);
15199 CcTest::global()->Set(v8_str("a"), string);
15200 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15201 regexp_interruption_data.string_resource = new UC16VectorResource(
15202 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15204 v8::TryCatch try_catch;
15205 timeout_thread.Start();
15207 CompileRun("/((a*)*)*b/.exec(a)");
15208 CHECK(try_catch.HasTerminated());
15210 timeout_thread.Join();
15212 regexp_interruption_data.string.Reset();
15213 i::DeleteArray(uc16_content);
15216 #endif // V8_INTERPRETED_REGEXP
15219 // Test that we cannot set a property on the global object if there
15220 // is a read-only property in the prototype chain.
15221 TEST(ReadOnlyPropertyInGlobalProto) {
15222 v8::Isolate* isolate = CcTest::isolate();
15223 v8::HandleScope scope(isolate);
15224 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15225 LocalContext context(0, templ);
15226 v8::Handle<v8::Object> global = context->Global();
15227 v8::Handle<v8::Object> global_proto =
15228 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15229 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15230 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15231 // Check without 'eval' or 'with'.
15232 v8::Handle<v8::Value> res =
15233 CompileRun("function f() { x = 42; return x; }; f()");
15234 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15235 // Check with 'eval'.
15236 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15237 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15238 // Check with 'with'.
15239 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15240 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15243 static int force_set_set_count = 0;
15244 static int force_set_get_count = 0;
15245 bool pass_on_get = false;
15247 static void ForceSetGetter(v8::Local<v8::String> name,
15248 const v8::PropertyCallbackInfo<v8::Value>& info) {
15249 force_set_get_count++;
15253 info.GetReturnValue().Set(3);
15256 static void ForceSetSetter(v8::Local<v8::String> name,
15257 v8::Local<v8::Value> value,
15258 const v8::PropertyCallbackInfo<void>& info) {
15259 force_set_set_count++;
15262 static void ForceSetInterceptSetter(
15263 v8::Local<v8::String> name,
15264 v8::Local<v8::Value> value,
15265 const v8::PropertyCallbackInfo<v8::Value>& info) {
15266 force_set_set_count++;
15267 info.GetReturnValue().SetUndefined();
15272 force_set_get_count = 0;
15273 force_set_set_count = 0;
15274 pass_on_get = false;
15276 v8::Isolate* isolate = CcTest::isolate();
15277 v8::HandleScope scope(isolate);
15278 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15279 v8::Handle<v8::String> access_property =
15280 v8::String::NewFromUtf8(isolate, "a");
15281 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15282 LocalContext context(NULL, templ);
15283 v8::Handle<v8::Object> global = context->Global();
15285 // Ordinary properties
15286 v8::Handle<v8::String> simple_property =
15287 v8::String::NewFromUtf8(isolate, "p");
15288 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15289 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15290 // This should fail because the property is read-only
15291 global->Set(simple_property, v8::Int32::New(isolate, 5));
15292 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15293 // This should succeed even though the property is read-only
15294 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15295 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15298 CHECK_EQ(0, force_set_set_count);
15299 CHECK_EQ(0, force_set_get_count);
15300 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15301 // CHECK_EQ the property shouldn't override it, just call the setter
15302 // which in this case does nothing.
15303 global->Set(access_property, v8::Int32::New(isolate, 7));
15304 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15305 CHECK_EQ(1, force_set_set_count);
15306 CHECK_EQ(2, force_set_get_count);
15307 // Forcing the property to be set should override the accessor without
15309 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15310 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15311 CHECK_EQ(1, force_set_set_count);
15312 CHECK_EQ(2, force_set_get_count);
15316 TEST(ForceSetWithInterceptor) {
15317 force_set_get_count = 0;
15318 force_set_set_count = 0;
15319 pass_on_get = false;
15321 v8::Isolate* isolate = CcTest::isolate();
15322 v8::HandleScope scope(isolate);
15323 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15324 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15325 LocalContext context(NULL, templ);
15326 v8::Handle<v8::Object> global = context->Global();
15328 v8::Handle<v8::String> some_property =
15329 v8::String::NewFromUtf8(isolate, "a");
15330 CHECK_EQ(0, force_set_set_count);
15331 CHECK_EQ(0, force_set_get_count);
15332 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15333 // Setting the property shouldn't override it, just call the setter
15334 // which in this case does nothing.
15335 global->Set(some_property, v8::Int32::New(isolate, 7));
15336 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15337 CHECK_EQ(1, force_set_set_count);
15338 CHECK_EQ(2, force_set_get_count);
15339 // Getting the property when the interceptor returns an empty handle
15340 // should yield undefined, since the property isn't present on the
15341 // object itself yet.
15342 pass_on_get = true;
15343 CHECK(global->Get(some_property)->IsUndefined());
15344 CHECK_EQ(1, force_set_set_count);
15345 CHECK_EQ(3, force_set_get_count);
15346 // Forcing the property to be set should cause the value to be
15347 // set locally without calling the interceptor.
15348 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15349 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15350 CHECK_EQ(1, force_set_set_count);
15351 CHECK_EQ(4, force_set_get_count);
15352 // Reenabling the interceptor should cause it to take precedence over
15354 pass_on_get = false;
15355 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15356 CHECK_EQ(1, force_set_set_count);
15357 CHECK_EQ(5, force_set_get_count);
15358 // The interceptor should also work for other properties
15359 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15361 CHECK_EQ(1, force_set_set_count);
15362 CHECK_EQ(6, force_set_get_count);
15366 THREADED_TEST(ForceDelete) {
15367 v8::Isolate* isolate = CcTest::isolate();
15368 v8::HandleScope scope(isolate);
15369 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15370 LocalContext context(NULL, templ);
15371 v8::Handle<v8::Object> global = context->Global();
15373 // Ordinary properties
15374 v8::Handle<v8::String> simple_property =
15375 v8::String::NewFromUtf8(isolate, "p");
15376 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15377 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15378 // This should fail because the property is dont-delete.
15379 CHECK(!global->Delete(simple_property));
15380 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15381 // This should succeed even though the property is dont-delete.
15382 CHECK(global->ForceDelete(simple_property));
15383 CHECK(global->Get(simple_property)->IsUndefined());
15387 static int force_delete_interceptor_count = 0;
15388 static bool pass_on_delete = false;
15391 static void ForceDeleteDeleter(
15392 v8::Local<v8::String> name,
15393 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15394 force_delete_interceptor_count++;
15395 if (pass_on_delete) return;
15396 info.GetReturnValue().Set(true);
15400 THREADED_TEST(ForceDeleteWithInterceptor) {
15401 force_delete_interceptor_count = 0;
15402 pass_on_delete = false;
15404 v8::Isolate* isolate = CcTest::isolate();
15405 v8::HandleScope scope(isolate);
15406 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15407 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15408 LocalContext context(NULL, templ);
15409 v8::Handle<v8::Object> global = context->Global();
15411 v8::Handle<v8::String> some_property =
15412 v8::String::NewFromUtf8(isolate, "a");
15413 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15415 // Deleting a property should get intercepted and nothing should
15417 CHECK_EQ(0, force_delete_interceptor_count);
15418 CHECK(global->Delete(some_property));
15419 CHECK_EQ(1, force_delete_interceptor_count);
15420 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15421 // Deleting the property when the interceptor returns an empty
15422 // handle should not delete the property since it is DontDelete.
15423 pass_on_delete = true;
15424 CHECK(!global->Delete(some_property));
15425 CHECK_EQ(2, force_delete_interceptor_count);
15426 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15427 // Forcing the property to be deleted should delete the value
15428 // without calling the interceptor.
15429 CHECK(global->ForceDelete(some_property));
15430 CHECK(global->Get(some_property)->IsUndefined());
15431 CHECK_EQ(2, force_delete_interceptor_count);
15435 // Make sure that forcing a delete invalidates any IC stubs, so we
15436 // don't read the hole value.
15437 THREADED_TEST(ForceDeleteIC) {
15438 LocalContext context;
15439 v8::HandleScope scope(context->GetIsolate());
15440 // Create a DontDelete variable on the global object.
15441 CompileRun("this.__proto__ = { foo: 'horse' };"
15442 "var foo = 'fish';"
15443 "function f() { return foo.length; }");
15444 // Initialize the IC for foo in f.
15445 CompileRun("for (var i = 0; i < 4; i++) f();");
15446 // Make sure the value of foo is correct before the deletion.
15447 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15448 // Force the deletion of foo.
15449 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15450 // Make sure the value for foo is read from the prototype, and that
15451 // we don't get in trouble with reading the deleted cell value
15453 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15457 TEST(InlinedFunctionAcrossContexts) {
15458 i::FLAG_allow_natives_syntax = true;
15459 v8::Isolate* isolate = CcTest::isolate();
15460 v8::HandleScope outer_scope(isolate);
15461 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15462 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15466 v8::HandleScope inner_scope(CcTest::isolate());
15467 CompileRun("var G = 42; function foo() { return G; }");
15468 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15470 ctx2->Global()->Set(v8_str("o"), foo);
15471 v8::Local<v8::Value> res = CompileRun(
15472 "function f() { return o(); }"
15473 "for (var i = 0; i < 10; ++i) f();"
15474 "%OptimizeFunctionOnNextCall(f);"
15476 CHECK_EQ(42, res->Int32Value());
15478 v8::Handle<v8::String> G_property =
15479 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15480 CHECK(ctx1->Global()->ForceDelete(G_property));
15487 " return e.toString();"
15490 "ReferenceError: G is not defined");
15497 static v8::Local<Context> calling_context0;
15498 static v8::Local<Context> calling_context1;
15499 static v8::Local<Context> calling_context2;
15502 // Check that the call to the callback is initiated in
15503 // calling_context2, the directly calling context is calling_context1
15504 // and the callback itself is in calling_context0.
15505 static void GetCallingContextCallback(
15506 const v8::FunctionCallbackInfo<v8::Value>& args) {
15507 ApiTestFuzzer::Fuzz();
15508 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15509 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15510 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15511 args.GetReturnValue().Set(42);
15515 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15516 i::Isolate* isolate = CcTest::i_isolate();
15517 CHECK(isolate != NULL);
15518 CHECK(isolate->context() == NULL);
15519 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15520 v8::HandleScope scope(v8_isolate);
15521 // The following should not crash, but return an empty handle.
15522 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15523 CHECK(current.IsEmpty());
15527 THREADED_TEST(GetCallingContext) {
15528 v8::Isolate* isolate = CcTest::isolate();
15529 v8::HandleScope scope(isolate);
15531 Local<Context> calling_context0(Context::New(isolate));
15532 Local<Context> calling_context1(Context::New(isolate));
15533 Local<Context> calling_context2(Context::New(isolate));
15534 ::calling_context0 = calling_context0;
15535 ::calling_context1 = calling_context1;
15536 ::calling_context2 = calling_context2;
15538 // Allow cross-domain access.
15539 Local<String> token = v8_str("<security token>");
15540 calling_context0->SetSecurityToken(token);
15541 calling_context1->SetSecurityToken(token);
15542 calling_context2->SetSecurityToken(token);
15544 // Create an object with a C++ callback in context0.
15545 calling_context0->Enter();
15546 Local<v8::FunctionTemplate> callback_templ =
15547 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15548 calling_context0->Global()->Set(v8_str("callback"),
15549 callback_templ->GetFunction());
15550 calling_context0->Exit();
15552 // Expose context0 in context1 and set up a function that calls the
15553 // callback function.
15554 calling_context1->Enter();
15555 calling_context1->Global()->Set(v8_str("context0"),
15556 calling_context0->Global());
15557 CompileRun("function f() { context0.callback() }");
15558 calling_context1->Exit();
15560 // Expose context1 in context2 and call the callback function in
15561 // context0 indirectly through f in context1.
15562 calling_context2->Enter();
15563 calling_context2->Global()->Set(v8_str("context1"),
15564 calling_context1->Global());
15565 CompileRun("context1.f()");
15566 calling_context2->Exit();
15567 ::calling_context0.Clear();
15568 ::calling_context1.Clear();
15569 ::calling_context2.Clear();
15573 // Check that a variable declaration with no explicit initialization
15574 // value does shadow an existing property in the prototype chain.
15575 THREADED_TEST(InitGlobalVarInProtoChain) {
15576 LocalContext context;
15577 v8::HandleScope scope(context->GetIsolate());
15578 // Introduce a variable in the prototype chain.
15579 CompileRun("__proto__.x = 42");
15580 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15581 CHECK(!result->IsUndefined());
15582 CHECK_EQ(43, result->Int32Value());
15586 // Regression test for issue 398.
15587 // If a function is added to an object, creating a constant function
15588 // field, and the result is cloned, replacing the constant function on the
15589 // original should not affect the clone.
15590 // See http://code.google.com/p/v8/issues/detail?id=398
15591 THREADED_TEST(ReplaceConstantFunction) {
15592 LocalContext context;
15593 v8::Isolate* isolate = context->GetIsolate();
15594 v8::HandleScope scope(isolate);
15595 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15596 v8::Handle<v8::FunctionTemplate> func_templ =
15597 v8::FunctionTemplate::New(isolate);
15598 v8::Handle<v8::String> foo_string =
15599 v8::String::NewFromUtf8(isolate, "foo");
15600 obj->Set(foo_string, func_templ->GetFunction());
15601 v8::Handle<v8::Object> obj_clone = obj->Clone();
15602 obj_clone->Set(foo_string,
15603 v8::String::NewFromUtf8(isolate, "Hello"));
15604 CHECK(!obj->Get(foo_string)->IsUndefined());
15608 static void CheckElementValue(i::Isolate* isolate,
15610 i::Handle<i::Object> obj,
15612 i::Object* element = *i::Object::GetElement(isolate, obj, offset);
15613 CHECK_EQ(expected, i::Smi::cast(element)->value());
15617 THREADED_TEST(PixelArray) {
15618 LocalContext context;
15619 i::Isolate* isolate = CcTest::i_isolate();
15620 i::Factory* factory = isolate->factory();
15621 v8::HandleScope scope(context->GetIsolate());
15622 const int kElementCount = 260;
15623 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15624 i::Handle<i::ExternalUint8ClampedArray> pixels =
15625 i::Handle<i::ExternalUint8ClampedArray>::cast(
15626 factory->NewExternalArray(kElementCount,
15627 v8::kExternalUint8ClampedArray,
15629 // Force GC to trigger verification.
15630 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15631 for (int i = 0; i < kElementCount; i++) {
15632 pixels->set(i, i % 256);
15634 // Force GC to trigger verification.
15635 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15636 for (int i = 0; i < kElementCount; i++) {
15637 CHECK_EQ(i % 256, pixels->get_scalar(i));
15638 CHECK_EQ(i % 256, pixel_data[i]);
15641 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15642 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15643 // Set the elements to be the pixels.
15644 // jsobj->set_elements(*pixels);
15645 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15646 CheckElementValue(isolate, 1, jsobj, 1);
15647 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15648 context->Global()->Set(v8_str("pixels"), obj);
15649 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15650 CHECK_EQ(1503, result->Int32Value());
15651 result = CompileRun("pixels[1]");
15652 CHECK_EQ(1, result->Int32Value());
15654 result = CompileRun("var sum = 0;"
15655 "for (var i = 0; i < 8; i++) {"
15656 " sum += pixels[i] = pixels[i] = -i;"
15659 CHECK_EQ(-28, result->Int32Value());
15661 result = CompileRun("var sum = 0;"
15662 "for (var i = 0; i < 8; i++) {"
15663 " sum += pixels[i] = pixels[i] = 0;"
15666 CHECK_EQ(0, result->Int32Value());
15668 result = CompileRun("var sum = 0;"
15669 "for (var i = 0; i < 8; i++) {"
15670 " sum += pixels[i] = pixels[i] = 255;"
15673 CHECK_EQ(8 * 255, result->Int32Value());
15675 result = CompileRun("var sum = 0;"
15676 "for (var i = 0; i < 8; i++) {"
15677 " sum += pixels[i] = pixels[i] = 256 + i;"
15680 CHECK_EQ(2076, result->Int32Value());
15682 result = CompileRun("var sum = 0;"
15683 "for (var i = 0; i < 8; i++) {"
15684 " sum += pixels[i] = pixels[i] = i;"
15687 CHECK_EQ(28, result->Int32Value());
15689 result = CompileRun("var sum = 0;"
15690 "for (var i = 0; i < 8; i++) {"
15691 " sum += pixels[i];"
15694 CHECK_EQ(28, result->Int32Value());
15696 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15697 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15698 i::Handle<i::Object> no_failure;
15699 no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15700 ASSERT(!no_failure.is_null());
15701 i::USE(no_failure);
15702 CheckElementValue(isolate, 2, jsobj, 1);
15703 *value.location() = i::Smi::FromInt(256);
15704 no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15705 ASSERT(!no_failure.is_null());
15706 i::USE(no_failure);
15707 CheckElementValue(isolate, 255, jsobj, 1);
15708 *value.location() = i::Smi::FromInt(-1);
15709 no_failure = i::JSObject::SetElement(jsobj, 1, value, NONE, i::SLOPPY);
15710 ASSERT(!no_failure.is_null());
15711 i::USE(no_failure);
15712 CheckElementValue(isolate, 0, jsobj, 1);
15714 result = CompileRun("for (var i = 0; i < 8; i++) {"
15715 " pixels[i] = (i * 65) - 109;"
15717 "pixels[1] + pixels[6];");
15718 CHECK_EQ(255, result->Int32Value());
15719 CheckElementValue(isolate, 0, jsobj, 0);
15720 CheckElementValue(isolate, 0, jsobj, 1);
15721 CheckElementValue(isolate, 21, jsobj, 2);
15722 CheckElementValue(isolate, 86, jsobj, 3);
15723 CheckElementValue(isolate, 151, jsobj, 4);
15724 CheckElementValue(isolate, 216, jsobj, 5);
15725 CheckElementValue(isolate, 255, jsobj, 6);
15726 CheckElementValue(isolate, 255, jsobj, 7);
15727 result = CompileRun("var sum = 0;"
15728 "for (var i = 0; i < 8; i++) {"
15729 " sum += pixels[i];"
15732 CHECK_EQ(984, result->Int32Value());
15734 result = CompileRun("for (var i = 0; i < 8; i++) {"
15735 " pixels[i] = (i * 1.1);"
15737 "pixels[1] + pixels[6];");
15738 CHECK_EQ(8, result->Int32Value());
15739 CheckElementValue(isolate, 0, jsobj, 0);
15740 CheckElementValue(isolate, 1, jsobj, 1);
15741 CheckElementValue(isolate, 2, jsobj, 2);
15742 CheckElementValue(isolate, 3, jsobj, 3);
15743 CheckElementValue(isolate, 4, jsobj, 4);
15744 CheckElementValue(isolate, 6, jsobj, 5);
15745 CheckElementValue(isolate, 7, jsobj, 6);
15746 CheckElementValue(isolate, 8, jsobj, 7);
15748 result = CompileRun("for (var i = 0; i < 8; i++) {"
15749 " pixels[7] = undefined;"
15752 CHECK_EQ(0, result->Int32Value());
15753 CheckElementValue(isolate, 0, jsobj, 7);
15755 result = CompileRun("for (var i = 0; i < 8; i++) {"
15756 " pixels[6] = '2.3';"
15759 CHECK_EQ(2, result->Int32Value());
15760 CheckElementValue(isolate, 2, jsobj, 6);
15762 result = CompileRun("for (var i = 0; i < 8; i++) {"
15763 " pixels[5] = NaN;"
15766 CHECK_EQ(0, result->Int32Value());
15767 CheckElementValue(isolate, 0, jsobj, 5);
15769 result = CompileRun("for (var i = 0; i < 8; i++) {"
15770 " pixels[8] = Infinity;"
15773 CHECK_EQ(255, result->Int32Value());
15774 CheckElementValue(isolate, 255, jsobj, 8);
15776 result = CompileRun("for (var i = 0; i < 8; i++) {"
15777 " pixels[9] = -Infinity;"
15780 CHECK_EQ(0, result->Int32Value());
15781 CheckElementValue(isolate, 0, jsobj, 9);
15783 result = CompileRun("pixels[3] = 33;"
15784 "delete pixels[3];"
15786 CHECK_EQ(33, result->Int32Value());
15788 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15789 "pixels[2] = 12; pixels[3] = 13;"
15790 "pixels.__defineGetter__('2',"
15791 "function() { return 120; });"
15793 CHECK_EQ(12, result->Int32Value());
15795 result = CompileRun("var js_array = new Array(40);"
15796 "js_array[0] = 77;"
15798 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15800 result = CompileRun("pixels[1] = 23;"
15801 "pixels.__proto__ = [];"
15802 "js_array.__proto__ = pixels;"
15803 "js_array.concat(pixels);");
15804 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15805 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15807 result = CompileRun("pixels[1] = 23;");
15808 CHECK_EQ(23, result->Int32Value());
15810 // Test for index greater than 255. Regression test for:
15811 // http://code.google.com/p/chromium/issues/detail?id=26337.
15812 result = CompileRun("pixels[256] = 255;");
15813 CHECK_EQ(255, result->Int32Value());
15814 result = CompileRun("var i = 0;"
15815 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15817 CHECK_EQ(255, result->Int32Value());
15819 // Make sure that pixel array ICs recognize when a non-pixel array
15820 // is passed to it.
15821 result = CompileRun("function pa_load(p) {"
15823 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15826 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15827 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15828 "just_ints = new Object();"
15829 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15830 "for (var i = 0; i < 10; ++i) {"
15831 " result = pa_load(just_ints);"
15834 CHECK_EQ(32640, result->Int32Value());
15836 // Make sure that pixel array ICs recognize out-of-bound accesses.
15837 result = CompileRun("function pa_load(p, start) {"
15839 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15842 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15843 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15844 "for (var i = 0; i < 10; ++i) {"
15845 " result = pa_load(pixels,-10);"
15848 CHECK_EQ(0, result->Int32Value());
15850 // Make sure that generic ICs properly handles a pixel array.
15851 result = CompileRun("function pa_load(p) {"
15853 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15856 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15857 "just_ints = new Object();"
15858 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15859 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15860 "for (var i = 0; i < 10; ++i) {"
15861 " result = pa_load(pixels);"
15864 CHECK_EQ(32640, result->Int32Value());
15866 // Make sure that generic load ICs recognize out-of-bound accesses in
15868 result = CompileRun("function pa_load(p, start) {"
15870 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15873 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15874 "just_ints = new Object();"
15875 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15876 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15877 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15878 "for (var i = 0; i < 10; ++i) {"
15879 " result = pa_load(pixels,-10);"
15882 CHECK_EQ(0, result->Int32Value());
15884 // Make sure that generic ICs properly handles other types than pixel
15885 // arrays (that the inlined fast pixel array test leaves the right information
15886 // in the right registers).
15887 result = CompileRun("function pa_load(p) {"
15889 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15892 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15893 "just_ints = new Object();"
15894 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15895 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15896 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15897 "sparse_array = new Object();"
15898 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15899 "sparse_array[1000000] = 3;"
15900 "for (var i = 0; i < 10; ++i) {"
15901 " result = pa_load(sparse_array);"
15904 CHECK_EQ(32640, result->Int32Value());
15906 // Make sure that pixel array store ICs clamp values correctly.
15907 result = CompileRun("function pa_store(p) {"
15908 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15910 "pa_store(pixels);"
15912 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15914 CHECK_EQ(48896, result->Int32Value());
15916 // Make sure that pixel array stores correctly handle accesses outside
15917 // of the pixel array..
15918 result = CompileRun("function pa_store(p,start) {"
15919 " for (var j = 0; j < 256; j++) {"
15920 " p[j+start] = j * 2;"
15923 "pa_store(pixels,0);"
15924 "pa_store(pixels,-128);"
15926 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15928 CHECK_EQ(65280, result->Int32Value());
15930 // Make sure that the generic store stub correctly handle accesses outside
15931 // of the pixel array..
15932 result = CompileRun("function pa_store(p,start) {"
15933 " for (var j = 0; j < 256; j++) {"
15934 " p[j+start] = j * 2;"
15937 "pa_store(pixels,0);"
15938 "just_ints = new Object();"
15939 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15940 "pa_store(just_ints, 0);"
15941 "pa_store(pixels,-128);"
15943 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15945 CHECK_EQ(65280, result->Int32Value());
15947 // Make sure that the generic keyed store stub clamps pixel array values
15949 result = CompileRun("function pa_store(p) {"
15950 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15952 "pa_store(pixels);"
15953 "just_ints = new Object();"
15954 "pa_store(just_ints);"
15955 "pa_store(pixels);"
15957 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15959 CHECK_EQ(48896, result->Int32Value());
15961 // Make sure that pixel array loads are optimized by crankshaft.
15962 result = CompileRun("function pa_load(p) {"
15964 " for (var i=0; i<256; ++i) {"
15969 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15970 "for (var i = 0; i < 5000; ++i) {"
15971 " result = pa_load(pixels);"
15974 CHECK_EQ(32640, result->Int32Value());
15976 // Make sure that pixel array stores are optimized by crankshaft.
15977 result = CompileRun("function pa_init(p) {"
15978 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15980 "function pa_load(p) {"
15982 " for (var i=0; i<256; ++i) {"
15987 "for (var i = 0; i < 5000; ++i) {"
15988 " pa_init(pixels);"
15990 "result = pa_load(pixels);"
15992 CHECK_EQ(32640, result->Int32Value());
15998 THREADED_TEST(PixelArrayInfo) {
15999 LocalContext context;
16000 v8::HandleScope scope(context->GetIsolate());
16001 for (int size = 0; size < 100; size += 10) {
16002 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16003 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16004 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16005 CHECK(obj->HasIndexedPropertiesInPixelData());
16006 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16007 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16013 static void NotHandledIndexedPropertyGetter(
16015 const v8::PropertyCallbackInfo<v8::Value>& info) {
16016 ApiTestFuzzer::Fuzz();
16020 static void NotHandledIndexedPropertySetter(
16022 Local<Value> value,
16023 const v8::PropertyCallbackInfo<v8::Value>& info) {
16024 ApiTestFuzzer::Fuzz();
16028 THREADED_TEST(PixelArrayWithInterceptor) {
16029 LocalContext context;
16030 i::Factory* factory = CcTest::i_isolate()->factory();
16031 v8::Isolate* isolate = context->GetIsolate();
16032 v8::HandleScope scope(isolate);
16033 const int kElementCount = 260;
16034 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16035 i::Handle<i::ExternalUint8ClampedArray> pixels =
16036 i::Handle<i::ExternalUint8ClampedArray>::cast(
16037 factory->NewExternalArray(kElementCount,
16038 v8::kExternalUint8ClampedArray,
16040 for (int i = 0; i < kElementCount; i++) {
16041 pixels->set(i, i % 256);
16043 v8::Handle<v8::ObjectTemplate> templ =
16044 v8::ObjectTemplate::New(context->GetIsolate());
16045 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16046 NotHandledIndexedPropertySetter);
16047 v8::Handle<v8::Object> obj = templ->NewInstance();
16048 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16049 context->Global()->Set(v8_str("pixels"), obj);
16050 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16051 CHECK_EQ(1, result->Int32Value());
16052 result = CompileRun("var sum = 0;"
16053 "for (var i = 0; i < 8; i++) {"
16054 " sum += pixels[i] = pixels[i] = -i;"
16057 CHECK_EQ(-28, result->Int32Value());
16058 result = CompileRun("pixels.hasOwnProperty('1')");
16059 CHECK(result->BooleanValue());
16064 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16065 switch (array_type) {
16066 case v8::kExternalInt8Array:
16067 case v8::kExternalUint8Array:
16068 case v8::kExternalUint8ClampedArray:
16071 case v8::kExternalInt16Array:
16072 case v8::kExternalUint16Array:
16075 case v8::kExternalInt32Array:
16076 case v8::kExternalUint32Array:
16077 case v8::kExternalFloat32Array:
16080 case v8::kExternalFloat64Array:
16092 template <class ExternalArrayClass, class ElementType>
16093 static void ObjectWithExternalArrayTestHelper(
16094 Handle<Context> context,
16095 v8::Handle<Object> obj,
16097 v8::ExternalArrayType array_type,
16098 int64_t low, int64_t high) {
16099 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16100 i::Isolate* isolate = jsobj->GetIsolate();
16101 obj->Set(v8_str("field"),
16102 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16103 context->Global()->Set(v8_str("ext_array"), obj);
16104 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16105 CHECK_EQ(1503, result->Int32Value());
16106 result = CompileRun("ext_array[1]");
16107 CHECK_EQ(1, result->Int32Value());
16109 // Check assigned smis
16110 result = CompileRun("for (var i = 0; i < 8; i++) {"
16111 " ext_array[i] = i;"
16114 "for (var i = 0; i < 8; i++) {"
16115 " sum += ext_array[i];"
16119 CHECK_EQ(28, result->Int32Value());
16120 // Check pass through of assigned smis
16121 result = CompileRun("var sum = 0;"
16122 "for (var i = 0; i < 8; i++) {"
16123 " sum += ext_array[i] = ext_array[i] = -i;"
16126 CHECK_EQ(-28, result->Int32Value());
16129 // Check assigned smis in reverse order
16130 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16131 " ext_array[i] = i;"
16134 "for (var i = 0; i < 8; i++) {"
16135 " sum += ext_array[i];"
16138 CHECK_EQ(28, result->Int32Value());
16140 // Check pass through of assigned HeapNumbers
16141 result = CompileRun("var sum = 0;"
16142 "for (var i = 0; i < 16; i+=2) {"
16143 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16146 CHECK_EQ(-28, result->Int32Value());
16148 // Check assigned HeapNumbers
16149 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16150 " ext_array[i] = (i * 0.5);"
16153 "for (var i = 0; i < 16; i+=2) {"
16154 " sum += ext_array[i];"
16157 CHECK_EQ(28, result->Int32Value());
16159 // Check assigned HeapNumbers in reverse order
16160 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16161 " ext_array[i] = (i * 0.5);"
16164 "for (var i = 0; i < 16; i+=2) {"
16165 " sum += ext_array[i];"
16168 CHECK_EQ(28, result->Int32Value());
16170 i::ScopedVector<char> test_buf(1024);
16172 // Check legal boundary conditions.
16173 // The repeated loads and stores ensure the ICs are exercised.
16174 const char* boundary_program =
16176 "for (var i = 0; i < 16; i++) {"
16177 " ext_array[i] = %lld;"
16179 " res = ext_array[i];"
16183 i::OS::SNPrintF(test_buf,
16186 result = CompileRun(test_buf.start());
16187 CHECK_EQ(low, result->IntegerValue());
16189 i::OS::SNPrintF(test_buf,
16192 result = CompileRun(test_buf.start());
16193 CHECK_EQ(high, result->IntegerValue());
16195 // Check misprediction of type in IC.
16196 result = CompileRun("var tmp_array = ext_array;"
16198 "for (var i = 0; i < 8; i++) {"
16199 " tmp_array[i] = i;"
16200 " sum += tmp_array[i];"
16206 // Force GC to trigger verification.
16207 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16208 CHECK_EQ(28, result->Int32Value());
16210 // Make sure out-of-range loads do not throw.
16211 i::OS::SNPrintF(test_buf,
16212 "var caught_exception = false;"
16216 " caught_exception = true;"
16218 "caught_exception;",
16220 result = CompileRun(test_buf.start());
16221 CHECK_EQ(false, result->BooleanValue());
16223 // Make sure out-of-range stores do not throw.
16224 i::OS::SNPrintF(test_buf,
16225 "var caught_exception = false;"
16227 " ext_array[%d] = 1;"
16229 " caught_exception = true;"
16231 "caught_exception;",
16233 result = CompileRun(test_buf.start());
16234 CHECK_EQ(false, result->BooleanValue());
16236 // Check other boundary conditions, values and operations.
16237 result = CompileRun("for (var i = 0; i < 8; i++) {"
16238 " ext_array[7] = undefined;"
16241 CHECK_EQ(0, result->Int32Value());
16242 if (array_type == v8::kExternalFloat64Array ||
16243 array_type == v8::kExternalFloat32Array) {
16244 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16246 i::Object::GetElement(isolate, jsobj, 7)->Number()));
16248 CheckElementValue(isolate, 0, jsobj, 7);
16251 result = CompileRun("for (var i = 0; i < 8; i++) {"
16252 " ext_array[6] = '2.3';"
16255 CHECK_EQ(2, result->Int32Value());
16258 i::Object::GetElement(isolate, jsobj, 6)->Number()));
16260 if (array_type != v8::kExternalFloat32Array &&
16261 array_type != v8::kExternalFloat64Array) {
16262 // Though the specification doesn't state it, be explicit about
16263 // converting NaNs and +/-Infinity to zero.
16264 result = CompileRun("for (var i = 0; i < 8; i++) {"
16265 " ext_array[i] = 5;"
16267 "for (var i = 0; i < 8; i++) {"
16268 " ext_array[i] = NaN;"
16271 CHECK_EQ(0, result->Int32Value());
16272 CheckElementValue(isolate, 0, jsobj, 5);
16274 result = CompileRun("for (var i = 0; i < 8; i++) {"
16275 " ext_array[i] = 5;"
16277 "for (var i = 0; i < 8; i++) {"
16278 " ext_array[i] = Infinity;"
16281 int expected_value =
16282 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16283 CHECK_EQ(expected_value, result->Int32Value());
16284 CheckElementValue(isolate, expected_value, jsobj, 5);
16286 result = CompileRun("for (var i = 0; i < 8; i++) {"
16287 " ext_array[i] = 5;"
16289 "for (var i = 0; i < 8; i++) {"
16290 " ext_array[i] = -Infinity;"
16293 CHECK_EQ(0, result->Int32Value());
16294 CheckElementValue(isolate, 0, jsobj, 5);
16296 // Check truncation behavior of integral arrays.
16297 const char* unsigned_data =
16298 "var source_data = [0.6, 10.6];"
16299 "var expected_results = [0, 10];";
16300 const char* signed_data =
16301 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16302 "var expected_results = [0, 10, 0, -10];";
16303 const char* pixel_data =
16304 "var source_data = [0.6, 10.6];"
16305 "var expected_results = [1, 11];";
16307 (array_type == v8::kExternalUint8Array ||
16308 array_type == v8::kExternalUint16Array ||
16309 array_type == v8::kExternalUint32Array);
16310 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16312 i::OS::SNPrintF(test_buf,
16314 "var all_passed = true;"
16315 "for (var i = 0; i < source_data.length; i++) {"
16316 " for (var j = 0; j < 8; j++) {"
16317 " ext_array[j] = source_data[i];"
16319 " all_passed = all_passed &&"
16320 " (ext_array[5] == expected_results[i]);"
16325 (is_pixel_data ? pixel_data : signed_data)));
16326 result = CompileRun(test_buf.start());
16327 CHECK_EQ(true, result->BooleanValue());
16330 i::Handle<ExternalArrayClass> array(
16331 ExternalArrayClass::cast(jsobj->elements()));
16332 for (int i = 0; i < element_count; i++) {
16333 array->set(i, static_cast<ElementType>(i));
16336 // Test complex assignments
16337 result = CompileRun("function ee_op_test_complex_func(sum) {"
16338 " for (var i = 0; i < 40; ++i) {"
16339 " sum += (ext_array[i] += 1);"
16340 " sum += (ext_array[i] -= 1);"
16345 "for (var i=0;i<10000;++i) {"
16346 " sum=ee_op_test_complex_func(sum);"
16349 CHECK_EQ(16000000, result->Int32Value());
16351 // Test count operations
16352 result = CompileRun("function ee_op_test_count_func(sum) {"
16353 " for (var i = 0; i < 40; ++i) {"
16354 " sum += (++ext_array[i]);"
16355 " sum += (--ext_array[i]);"
16360 "for (var i=0;i<10000;++i) {"
16361 " sum=ee_op_test_count_func(sum);"
16364 CHECK_EQ(16000000, result->Int32Value());
16366 result = CompileRun("ext_array[3] = 33;"
16367 "delete ext_array[3];"
16369 CHECK_EQ(33, result->Int32Value());
16371 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16372 "ext_array[2] = 12; ext_array[3] = 13;"
16373 "ext_array.__defineGetter__('2',"
16374 "function() { return 120; });"
16376 CHECK_EQ(12, result->Int32Value());
16378 result = CompileRun("var js_array = new Array(40);"
16379 "js_array[0] = 77;"
16381 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16383 result = CompileRun("ext_array[1] = 23;"
16384 "ext_array.__proto__ = [];"
16385 "js_array.__proto__ = ext_array;"
16386 "js_array.concat(ext_array);");
16387 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16388 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16390 result = CompileRun("ext_array[1] = 23;");
16391 CHECK_EQ(23, result->Int32Value());
16395 template <class FixedTypedArrayClass,
16396 i::ElementsKind elements_kind,
16398 static void FixedTypedArrayTestHelper(
16399 v8::ExternalArrayType array_type,
16401 ElementType high) {
16402 i::FLAG_allow_natives_syntax = true;
16403 LocalContext context;
16404 i::Isolate* isolate = CcTest::i_isolate();
16405 i::Factory* factory = isolate->factory();
16406 v8::HandleScope scope(context->GetIsolate());
16407 const int kElementCount = 260;
16408 i::Handle<FixedTypedArrayClass> fixed_array =
16409 i::Handle<FixedTypedArrayClass>::cast(
16410 factory->NewFixedTypedArray(kElementCount, array_type));
16411 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16412 fixed_array->map()->instance_type());
16413 CHECK_EQ(kElementCount, fixed_array->length());
16414 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16415 for (int i = 0; i < kElementCount; i++) {
16416 fixed_array->set(i, static_cast<ElementType>(i));
16418 // Force GC to trigger verification.
16419 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16420 for (int i = 0; i < kElementCount; i++) {
16421 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16422 static_cast<int64_t>(fixed_array->get_scalar(i)));
16424 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16425 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16426 i::Handle<i::Map> fixed_array_map =
16427 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16428 jsobj->set_map(*fixed_array_map);
16429 jsobj->set_elements(*fixed_array);
16431 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16432 context.local(), obj, kElementCount, array_type,
16433 static_cast<int64_t>(low),
16434 static_cast<int64_t>(high));
16438 THREADED_TEST(FixedUint8Array) {
16439 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16440 v8::kExternalUint8Array,
16445 THREADED_TEST(FixedUint8ClampedArray) {
16446 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16447 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16448 v8::kExternalUint8ClampedArray,
16453 THREADED_TEST(FixedInt8Array) {
16454 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16455 v8::kExternalInt8Array,
16460 THREADED_TEST(FixedUint16Array) {
16461 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16462 v8::kExternalUint16Array,
16467 THREADED_TEST(FixedInt16Array) {
16468 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16469 v8::kExternalInt16Array,
16474 THREADED_TEST(FixedUint32Array) {
16475 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16476 v8::kExternalUint32Array,
16481 THREADED_TEST(FixedInt32Array) {
16482 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16483 v8::kExternalInt32Array,
16488 THREADED_TEST(FixedFloat32Array) {
16489 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16490 v8::kExternalFloat32Array,
16495 THREADED_TEST(FixedFloat64Array) {
16496 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16497 v8::kExternalFloat64Array,
16502 template <class ExternalArrayClass, class ElementType>
16503 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16506 LocalContext context;
16507 i::Isolate* isolate = CcTest::i_isolate();
16508 i::Factory* factory = isolate->factory();
16509 v8::HandleScope scope(context->GetIsolate());
16510 const int kElementCount = 40;
16511 int element_size = ExternalArrayElementSize(array_type);
16512 ElementType* array_data =
16513 static_cast<ElementType*>(malloc(kElementCount * element_size));
16514 i::Handle<ExternalArrayClass> array =
16515 i::Handle<ExternalArrayClass>::cast(
16516 factory->NewExternalArray(kElementCount, array_type, array_data));
16517 // Force GC to trigger verification.
16518 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16519 for (int i = 0; i < kElementCount; i++) {
16520 array->set(i, static_cast<ElementType>(i));
16522 // Force GC to trigger verification.
16523 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16524 for (int i = 0; i < kElementCount; i++) {
16525 CHECK_EQ(static_cast<int64_t>(i),
16526 static_cast<int64_t>(array->get_scalar(i)));
16527 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16530 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16531 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16532 // Set the elements to be the external array.
16533 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16538 i::Object::GetElement(isolate, jsobj, 1)->Number()));
16540 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16541 context.local(), obj, kElementCount, array_type, low, high);
16543 v8::Handle<v8::Value> result;
16545 // Test more complex manipulations which cause eax to contain values
16546 // that won't be completely overwritten by loads from the arrays.
16547 // This catches bugs in the instructions used for the KeyedLoadIC
16548 // for byte and word types.
16550 const int kXSize = 300;
16551 const int kYSize = 300;
16552 const int kLargeElementCount = kXSize * kYSize * 4;
16553 ElementType* large_array_data =
16554 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16555 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16556 // Set the elements to be the external array.
16557 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16559 kLargeElementCount);
16560 context->Global()->Set(v8_str("large_array"), large_obj);
16561 // Initialize contents of a few rows.
16562 for (int x = 0; x < 300; x++) {
16564 int offset = row * 300 * 4;
16565 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16566 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16567 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16568 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16570 offset = row * 300 * 4;
16571 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16572 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16573 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16574 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16576 offset = row * 300 * 4;
16577 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16578 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16579 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16580 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16582 // The goal of the code below is to make "offset" large enough
16583 // that the computation of the index (which goes into eax) has
16584 // high bits set which will not be overwritten by a byte or short
16586 result = CompileRun("var failed = false;"
16588 "for (var i = 0; i < 300; i++) {"
16589 " if (large_array[4 * i] != 127 ||"
16590 " large_array[4 * i + 1] != 0 ||"
16591 " large_array[4 * i + 2] != 0 ||"
16592 " large_array[4 * i + 3] != 127) {"
16596 "offset = 150 * 300 * 4;"
16597 "for (var i = 0; i < 300; i++) {"
16598 " if (large_array[offset + 4 * i] != 127 ||"
16599 " large_array[offset + 4 * i + 1] != 0 ||"
16600 " large_array[offset + 4 * i + 2] != 0 ||"
16601 " large_array[offset + 4 * i + 3] != 127) {"
16605 "offset = 298 * 300 * 4;"
16606 "for (var i = 0; i < 300; i++) {"
16607 " if (large_array[offset + 4 * i] != 127 ||"
16608 " large_array[offset + 4 * i + 1] != 0 ||"
16609 " large_array[offset + 4 * i + 2] != 0 ||"
16610 " large_array[offset + 4 * i + 3] != 127) {"
16615 CHECK_EQ(true, result->BooleanValue());
16616 free(large_array_data);
16619 // The "" property descriptor is overloaded to store information about
16620 // the external array. Ensure that setting and accessing the "" property
16621 // works (it should overwrite the information cached about the external
16622 // array in the DescriptorArray) in various situations.
16623 result = CompileRun("ext_array[''] = 23; ext_array['']");
16624 CHECK_EQ(23, result->Int32Value());
16626 // Property "" set after the external array is associated with the object.
16628 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16629 obj2->Set(v8_str("ee_test_field"),
16630 v8::Int32::New(context->GetIsolate(), 256));
16631 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16632 // Set the elements to be the external array.
16633 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16636 context->Global()->Set(v8_str("ext_array"), obj2);
16637 result = CompileRun("ext_array['']");
16638 CHECK_EQ(1503, result->Int32Value());
16641 // Property "" set after the external array is associated with the object.
16643 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16644 obj2->Set(v8_str("ee_test_field_2"),
16645 v8::Int32::New(context->GetIsolate(), 256));
16646 // Set the elements to be the external array.
16647 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16650 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16651 context->Global()->Set(v8_str("ext_array"), obj2);
16652 result = CompileRun("ext_array['']");
16653 CHECK_EQ(1503, result->Int32Value());
16656 // Should reuse the map from previous test.
16658 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16659 obj2->Set(v8_str("ee_test_field_2"),
16660 v8::Int32::New(context->GetIsolate(), 256));
16661 // Set the elements to be the external array. Should re-use the map
16662 // from previous test.
16663 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16666 context->Global()->Set(v8_str("ext_array"), obj2);
16667 result = CompileRun("ext_array['']");
16670 // Property "" is a constant function that shouldn't not be interfered with
16671 // when an external array is set.
16673 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16675 obj2->Set(v8_str("ee_test_field3"),
16676 v8::Int32::New(context->GetIsolate(), 256));
16678 // Add a constant function to an object.
16679 context->Global()->Set(v8_str("ext_array"), obj2);
16680 result = CompileRun("ext_array[''] = function() {return 1503;};"
16681 "ext_array['']();");
16683 // Add an external array transition to the same map that
16684 // has the constant transition.
16685 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16686 obj3->Set(v8_str("ee_test_field3"),
16687 v8::Int32::New(context->GetIsolate(), 256));
16688 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16691 context->Global()->Set(v8_str("ext_array"), obj3);
16694 // If a external array transition is in the map, it should get clobbered
16695 // by a constant function.
16697 // Add an external array transition.
16698 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16699 obj3->Set(v8_str("ee_test_field4"),
16700 v8::Int32::New(context->GetIsolate(), 256));
16701 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16705 // Add a constant function to the same map that just got an external array
16707 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16708 obj2->Set(v8_str("ee_test_field4"),
16709 v8::Int32::New(context->GetIsolate(), 256));
16710 context->Global()->Set(v8_str("ext_array"), obj2);
16711 result = CompileRun("ext_array[''] = function() {return 1503;};"
16712 "ext_array['']();");
16719 THREADED_TEST(ExternalInt8Array) {
16720 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16721 v8::kExternalInt8Array,
16727 THREADED_TEST(ExternalUint8Array) {
16728 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16729 v8::kExternalUint8Array,
16735 THREADED_TEST(ExternalUint8ClampedArray) {
16736 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16737 v8::kExternalUint8ClampedArray,
16743 THREADED_TEST(ExternalInt16Array) {
16744 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16745 v8::kExternalInt16Array,
16751 THREADED_TEST(ExternalUint16Array) {
16752 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16753 v8::kExternalUint16Array,
16759 THREADED_TEST(ExternalInt32Array) {
16760 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16761 v8::kExternalInt32Array,
16762 INT_MIN, // -2147483648
16763 INT_MAX); // 2147483647
16767 THREADED_TEST(ExternalUint32Array) {
16768 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16769 v8::kExternalUint32Array,
16771 UINT_MAX); // 4294967295
16775 THREADED_TEST(ExternalFloat32Array) {
16776 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16777 v8::kExternalFloat32Array,
16783 THREADED_TEST(ExternalFloat64Array) {
16784 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16785 v8::kExternalFloat64Array,
16791 THREADED_TEST(ExternalArrays) {
16792 TestExternalInt8Array();
16793 TestExternalUint8Array();
16794 TestExternalInt16Array();
16795 TestExternalUint16Array();
16796 TestExternalInt32Array();
16797 TestExternalUint32Array();
16798 TestExternalFloat32Array();
16802 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16803 LocalContext context;
16804 v8::HandleScope scope(context->GetIsolate());
16805 for (int size = 0; size < 100; size += 10) {
16806 int element_size = ExternalArrayElementSize(array_type);
16807 void* external_data = malloc(size * element_size);
16808 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16809 obj->SetIndexedPropertiesToExternalArrayData(
16810 external_data, array_type, size);
16811 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16812 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16813 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16814 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16815 free(external_data);
16820 THREADED_TEST(ExternalArrayInfo) {
16821 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16822 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16823 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16824 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16825 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16826 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16827 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16828 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16829 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16833 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16834 v8::ExternalArrayType array_type,
16836 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16837 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16838 last_location = last_message = NULL;
16839 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16840 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16841 CHECK_NE(NULL, last_location);
16842 CHECK_NE(NULL, last_message);
16846 TEST(ExternalArrayLimits) {
16847 LocalContext context;
16848 v8::Isolate* isolate = context->GetIsolate();
16849 v8::HandleScope scope(isolate);
16850 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16851 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16852 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16853 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16854 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16855 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16856 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16857 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16858 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16859 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16860 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16861 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16862 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16863 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16864 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16865 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16866 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16867 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16871 template <typename ElementType, typename TypedArray,
16872 class ExternalArrayClass>
16873 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16874 int64_t low, int64_t high) {
16875 const int kElementCount = 50;
16877 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16880 v8::Isolate* isolate = env->GetIsolate();
16881 v8::HandleScope handle_scope(isolate);
16883 Local<v8::ArrayBuffer> ab =
16884 v8::ArrayBuffer::New(isolate, backing_store.start(),
16885 (kElementCount + 2) * sizeof(ElementType));
16886 Local<TypedArray> ta =
16887 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16888 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16889 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16890 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16891 CHECK_EQ(kElementCount*sizeof(ElementType),
16892 static_cast<int>(ta->ByteLength()));
16893 CHECK_EQ(ab, ta->Buffer());
16895 ElementType* data = backing_store.start() + 2;
16896 for (int i = 0; i < kElementCount; i++) {
16897 data[i] = static_cast<ElementType>(i);
16900 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16901 env.local(), ta, kElementCount, array_type, low, high);
16905 THREADED_TEST(Uint8Array) {
16906 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16907 v8::kExternalUint8Array, 0, 0xFF);
16911 THREADED_TEST(Int8Array) {
16912 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16913 v8::kExternalInt8Array, -0x80, 0x7F);
16917 THREADED_TEST(Uint16Array) {
16918 TypedArrayTestHelper<uint16_t,
16920 i::ExternalUint16Array>(
16921 v8::kExternalUint16Array, 0, 0xFFFF);
16925 THREADED_TEST(Int16Array) {
16926 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16927 v8::kExternalInt16Array, -0x8000, 0x7FFF);
16931 THREADED_TEST(Uint32Array) {
16932 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16933 v8::kExternalUint32Array, 0, UINT_MAX);
16937 THREADED_TEST(Int32Array) {
16938 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16939 v8::kExternalInt32Array, INT_MIN, INT_MAX);
16943 THREADED_TEST(Float32Array) {
16944 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16945 v8::kExternalFloat32Array, -500, 500);
16949 THREADED_TEST(Float64Array) {
16950 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16951 v8::kExternalFloat64Array, -500, 500);
16955 THREADED_TEST(Uint8ClampedArray) {
16956 TypedArrayTestHelper<uint8_t,
16957 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16958 v8::kExternalUint8ClampedArray, 0, 0xFF);
16962 THREADED_TEST(DataView) {
16963 const int kSize = 50;
16965 i::ScopedVector<uint8_t> backing_store(kSize+2);
16968 v8::Isolate* isolate = env->GetIsolate();
16969 v8::HandleScope handle_scope(isolate);
16971 Local<v8::ArrayBuffer> ab =
16972 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16973 Local<v8::DataView> dv =
16974 v8::DataView::New(ab, 2, kSize);
16975 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16976 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16977 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16978 CHECK_EQ(ab, dv->Buffer());
16982 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16983 THREADED_TEST(Is##View) { \
16984 LocalContext env; \
16985 v8::Isolate* isolate = env->GetIsolate(); \
16986 v8::HandleScope handle_scope(isolate); \
16988 Handle<Value> result = CompileRun( \
16989 "var ab = new ArrayBuffer(128);" \
16990 "new " #View "(ab)"); \
16991 CHECK(result->IsArrayBufferView()); \
16992 CHECK(result->Is##View()); \
16993 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16996 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16997 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16998 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16999 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17000 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17001 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17002 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17003 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17004 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17005 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17007 #undef IS_ARRAY_BUFFER_VIEW_TEST
17011 THREADED_TEST(ScriptContextDependence) {
17013 v8::HandleScope scope(c1->GetIsolate());
17014 const char *source = "foo";
17015 v8::Handle<v8::Script> dep = v8_compile(source);
17016 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17017 c1->GetIsolate(), source));
17018 v8::Handle<v8::UnboundScript> indep =
17019 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17020 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17021 v8::Integer::New(c1->GetIsolate(), 100));
17022 CHECK_EQ(dep->Run()->Int32Value(), 100);
17023 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17025 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17026 v8::Integer::New(c2->GetIsolate(), 101));
17027 CHECK_EQ(dep->Run()->Int32Value(), 100);
17028 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17032 THREADED_TEST(StackTrace) {
17033 LocalContext context;
17034 v8::HandleScope scope(context->GetIsolate());
17035 v8::TryCatch try_catch;
17036 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17037 v8::Handle<v8::String> src =
17038 v8::String::NewFromUtf8(context->GetIsolate(), source);
17039 v8::Handle<v8::String> origin =
17040 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17041 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17042 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17043 ->BindToCurrentContext()
17045 CHECK(try_catch.HasCaught());
17046 v8::String::Utf8Value stack(try_catch.StackTrace());
17047 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17051 // Checks that a StackFrame has certain expected values.
17052 void checkStackFrame(const char* expected_script_name,
17053 const char* expected_func_name, int expected_line_number,
17054 int expected_column, bool is_eval, bool is_constructor,
17055 v8::Handle<v8::StackFrame> frame) {
17056 v8::HandleScope scope(CcTest::isolate());
17057 v8::String::Utf8Value func_name(frame->GetFunctionName());
17058 v8::String::Utf8Value script_name(frame->GetScriptName());
17059 if (*script_name == NULL) {
17060 // The situation where there is no associated script, like for evals.
17061 CHECK(expected_script_name == NULL);
17063 CHECK(strstr(*script_name, expected_script_name) != NULL);
17065 CHECK(strstr(*func_name, expected_func_name) != NULL);
17066 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17067 CHECK_EQ(expected_column, frame->GetColumn());
17068 CHECK_EQ(is_eval, frame->IsEval());
17069 CHECK_EQ(is_constructor, frame->IsConstructor());
17073 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17074 v8::HandleScope scope(args.GetIsolate());
17075 const char* origin = "capture-stack-trace-test";
17076 const int kOverviewTest = 1;
17077 const int kDetailedTest = 2;
17079 ASSERT(args.Length() == 1);
17081 int testGroup = args[0]->Int32Value();
17082 if (testGroup == kOverviewTest) {
17083 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17084 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17085 CHECK_EQ(4, stackTrace->GetFrameCount());
17086 checkStackFrame(origin, "bar", 2, 10, false, false,
17087 stackTrace->GetFrame(0));
17088 checkStackFrame(origin, "foo", 6, 3, false, false,
17089 stackTrace->GetFrame(1));
17090 // This is the source string inside the eval which has the call to foo.
17091 checkStackFrame(NULL, "", 1, 5, false, false,
17092 stackTrace->GetFrame(2));
17093 // The last frame is an anonymous function which has the initial eval call.
17094 checkStackFrame(origin, "", 8, 7, false, false,
17095 stackTrace->GetFrame(3));
17097 CHECK(stackTrace->AsArray()->IsArray());
17098 } else if (testGroup == kDetailedTest) {
17099 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17100 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17101 CHECK_EQ(4, stackTrace->GetFrameCount());
17102 checkStackFrame(origin, "bat", 4, 22, false, false,
17103 stackTrace->GetFrame(0));
17104 checkStackFrame(origin, "baz", 8, 3, false, true,
17105 stackTrace->GetFrame(1));
17106 #ifdef ENABLE_DEBUGGER_SUPPORT
17107 bool is_eval = true;
17108 #else // ENABLE_DEBUGGER_SUPPORT
17109 bool is_eval = false;
17110 #endif // ENABLE_DEBUGGER_SUPPORT
17112 // This is the source string inside the eval which has the call to baz.
17113 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17114 stackTrace->GetFrame(2));
17115 // The last frame is an anonymous function which has the initial eval call.
17116 checkStackFrame(origin, "", 10, 1, false, false,
17117 stackTrace->GetFrame(3));
17119 CHECK(stackTrace->AsArray()->IsArray());
17124 // Tests the C++ StackTrace API.
17125 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17126 // THREADED_TEST(CaptureStackTrace) {
17127 TEST(CaptureStackTrace) {
17128 v8::Isolate* isolate = CcTest::isolate();
17129 v8::HandleScope scope(isolate);
17130 v8::Handle<v8::String> origin =
17131 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17133 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17134 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17135 LocalContext context(0, templ);
17137 // Test getting OVERVIEW information. Should ignore information that is not
17138 // script name, function name, line number, and column offset.
17139 const char *overview_source =
17140 "function bar() {\n"
17141 " var y; AnalyzeStackInNativeCode(1);\n"
17143 "function foo() {\n"
17147 "var x;eval('new foo();');";
17148 v8::Handle<v8::String> overview_src =
17149 v8::String::NewFromUtf8(isolate, overview_source);
17150 v8::ScriptCompiler::Source script_source(overview_src,
17151 v8::ScriptOrigin(origin));
17152 v8::Handle<Value> overview_result(
17153 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17154 ->BindToCurrentContext()
17156 CHECK(!overview_result.IsEmpty());
17157 CHECK(overview_result->IsObject());
17159 // Test getting DETAILED information.
17160 const char *detailed_source =
17161 "function bat() {AnalyzeStackInNativeCode(2);\n"
17164 "function baz() {\n"
17167 "eval('new baz();');";
17168 v8::Handle<v8::String> detailed_src =
17169 v8::String::NewFromUtf8(isolate, detailed_source);
17170 // Make the script using a non-zero line and column offset.
17171 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17172 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17173 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17174 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17175 v8::Handle<v8::UnboundScript> detailed_script(
17176 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17177 v8::Handle<Value> detailed_result(
17178 detailed_script->BindToCurrentContext()->Run());
17179 CHECK(!detailed_result.IsEmpty());
17180 CHECK(detailed_result->IsObject());
17184 static void StackTraceForUncaughtExceptionListener(
17185 v8::Handle<v8::Message> message,
17186 v8::Handle<Value>) {
17187 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17188 CHECK_EQ(2, stack_trace->GetFrameCount());
17189 checkStackFrame("origin", "foo", 2, 3, false, false,
17190 stack_trace->GetFrame(0));
17191 checkStackFrame("origin", "bar", 5, 3, false, false,
17192 stack_trace->GetFrame(1));
17196 TEST(CaptureStackTraceForUncaughtException) {
17199 v8::HandleScope scope(env->GetIsolate());
17200 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17201 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17203 CompileRunWithOrigin(
17204 "function foo() {\n"
17207 "function bar() {\n"
17211 v8::Local<v8::Object> global = env->Global();
17212 Local<Value> trouble = global->Get(v8_str("bar"));
17213 CHECK(trouble->IsFunction());
17214 Function::Cast(*trouble)->Call(global, 0, NULL);
17215 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17216 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17220 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17222 v8::HandleScope scope(env->GetIsolate());
17223 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17225 v8::StackTrace::kDetailed);
17228 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17229 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17230 " 'isConstructor'];\n"
17231 "for (var i = 0; i < setters.length; i++) {\n"
17232 " var prop = setters[i];\n"
17233 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17235 CompileRun("throw 'exception';");
17236 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17240 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17241 v8::Handle<v8::Value> data) {
17242 // Use the frame where JavaScript is called from.
17243 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17244 CHECK(!stack_trace.IsEmpty());
17245 int frame_count = stack_trace->GetFrameCount();
17246 CHECK_EQ(3, frame_count);
17247 int line_number[] = {1, 2, 5};
17248 for (int i = 0; i < frame_count; i++) {
17249 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17254 // Test that we only return the stack trace at the site where the exception
17255 // is first thrown (not where it is rethrown).
17256 TEST(RethrowStackTrace) {
17258 v8::HandleScope scope(env->GetIsolate());
17259 // We make sure that
17260 // - the stack trace of the ReferenceError in g() is reported.
17261 // - the stack trace is not overwritten when e1 is rethrown by t().
17262 // - the stack trace of e2 does not overwrite that of e1.
17263 const char* source =
17264 "function g() { error; } \n"
17265 "function f() { g(); } \n"
17266 "function t(e) { throw e; } \n"
17269 "} catch (e1) { \n"
17272 " } catch (e2) { \n"
17276 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17277 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17278 CompileRun(source);
17279 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17280 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17284 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17285 v8::Handle<v8::Value> data) {
17286 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17287 CHECK(!stack_trace.IsEmpty());
17288 int frame_count = stack_trace->GetFrameCount();
17289 CHECK_EQ(2, frame_count);
17290 int line_number[] = {3, 7};
17291 for (int i = 0; i < frame_count; i++) {
17292 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17297 // Test that we do not recognize identity for primitive exceptions.
17298 TEST(RethrowPrimitiveStackTrace) {
17300 v8::HandleScope scope(env->GetIsolate());
17301 // We do not capture stack trace for non Error objects on creation time.
17302 // Instead, we capture the stack trace on last throw.
17303 const char* source =
17304 "function g() { throw 404; } \n"
17305 "function f() { g(); } \n"
17306 "function t(e) { throw e; } \n"
17309 "} catch (e1) { \n"
17312 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17313 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17314 CompileRun(source);
17315 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17316 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17320 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17321 v8::Handle<v8::Value> data) {
17322 // Use the frame where JavaScript is called from.
17323 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17324 CHECK(!stack_trace.IsEmpty());
17325 CHECK_EQ(1, stack_trace->GetFrameCount());
17326 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17330 // Test that the stack trace is captured when the error object is created and
17331 // not where it is thrown.
17332 TEST(RethrowExistingStackTrace) {
17334 v8::HandleScope scope(env->GetIsolate());
17335 const char* source =
17336 "var e = new Error(); \n"
17338 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17339 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17340 CompileRun(source);
17341 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17342 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17346 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17347 v8::Handle<v8::Value> data) {
17348 // Use the frame where JavaScript is called from.
17349 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17350 CHECK(!stack_trace.IsEmpty());
17351 CHECK_EQ(1, stack_trace->GetFrameCount());
17352 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17356 // Test that the stack trace is captured where the bogus Error object is thrown.
17357 TEST(RethrowBogusErrorStackTrace) {
17359 v8::HandleScope scope(env->GetIsolate());
17360 const char* source =
17361 "var e = {__proto__: new Error()} \n"
17363 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17364 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17365 CompileRun(source);
17366 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17367 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17371 void AnalyzeStackOfEvalWithSourceURL(
17372 const v8::FunctionCallbackInfo<v8::Value>& args) {
17373 v8::HandleScope scope(args.GetIsolate());
17374 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17375 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17376 CHECK_EQ(5, stackTrace->GetFrameCount());
17377 v8::Handle<v8::String> url = v8_str("eval_url");
17378 for (int i = 0; i < 3; i++) {
17379 v8::Handle<v8::String> name =
17380 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17381 CHECK(!name.IsEmpty());
17382 CHECK_EQ(url, name);
17387 TEST(SourceURLInStackTrace) {
17388 v8::Isolate* isolate = CcTest::isolate();
17389 v8::HandleScope scope(isolate);
17390 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17391 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17392 v8::FunctionTemplate::New(isolate,
17393 AnalyzeStackOfEvalWithSourceURL));
17394 LocalContext context(0, templ);
17396 const char *source =
17397 "function outer() {\n"
17398 "function bar() {\n"
17399 " AnalyzeStackOfEvalWithSourceURL();\n"
17401 "function foo() {\n"
17407 "eval('(' + outer +')()%s');";
17409 i::ScopedVector<char> code(1024);
17410 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17411 CHECK(CompileRun(code.start())->IsUndefined());
17412 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17413 CHECK(CompileRun(code.start())->IsUndefined());
17417 static int scriptIdInStack[2];
17419 void AnalyzeScriptIdInStack(
17420 const v8::FunctionCallbackInfo<v8::Value>& args) {
17421 v8::HandleScope scope(args.GetIsolate());
17422 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17423 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17424 CHECK_EQ(2, stackTrace->GetFrameCount());
17425 for (int i = 0; i < 2; i++) {
17426 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17431 TEST(ScriptIdInStackTrace) {
17432 v8::Isolate* isolate = CcTest::isolate();
17433 v8::HandleScope scope(isolate);
17434 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17435 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17436 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17437 LocalContext context(0, templ);
17439 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17441 "function foo() {\n"
17442 " AnalyzeScriptIdInStack();"
17445 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17447 for (int i = 0; i < 2; i++) {
17448 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17449 CHECK_EQ(scriptIdInStack[i], script->GetId());
17454 void AnalyzeStackOfInlineScriptWithSourceURL(
17455 const v8::FunctionCallbackInfo<v8::Value>& args) {
17456 v8::HandleScope scope(args.GetIsolate());
17457 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17458 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17459 CHECK_EQ(4, stackTrace->GetFrameCount());
17460 v8::Handle<v8::String> url = v8_str("url");
17461 for (int i = 0; i < 3; i++) {
17462 v8::Handle<v8::String> name =
17463 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17464 CHECK(!name.IsEmpty());
17465 CHECK_EQ(url, name);
17470 TEST(InlineScriptWithSourceURLInStackTrace) {
17471 v8::Isolate* isolate = CcTest::isolate();
17472 v8::HandleScope scope(isolate);
17473 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17474 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17475 v8::FunctionTemplate::New(
17476 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17477 LocalContext context(0, templ);
17479 const char *source =
17480 "function outer() {\n"
17481 "function bar() {\n"
17482 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17484 "function foo() {\n"
17492 i::ScopedVector<char> code(1024);
17493 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17494 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17495 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17496 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17500 void AnalyzeStackOfDynamicScriptWithSourceURL(
17501 const v8::FunctionCallbackInfo<v8::Value>& args) {
17502 v8::HandleScope scope(args.GetIsolate());
17503 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17504 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17505 CHECK_EQ(4, stackTrace->GetFrameCount());
17506 v8::Handle<v8::String> url = v8_str("source_url");
17507 for (int i = 0; i < 3; i++) {
17508 v8::Handle<v8::String> name =
17509 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17510 CHECK(!name.IsEmpty());
17511 CHECK_EQ(url, name);
17516 TEST(DynamicWithSourceURLInStackTrace) {
17517 v8::Isolate* isolate = CcTest::isolate();
17518 v8::HandleScope scope(isolate);
17519 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17520 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17521 v8::FunctionTemplate::New(
17522 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17523 LocalContext context(0, templ);
17525 const char *source =
17526 "function outer() {\n"
17527 "function bar() {\n"
17528 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17530 "function foo() {\n"
17538 i::ScopedVector<char> code(1024);
17539 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17540 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17541 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17542 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17546 TEST(DynamicWithSourceURLInStackTraceString) {
17547 LocalContext context;
17548 v8::HandleScope scope(context->GetIsolate());
17550 const char *source =
17551 "function outer() {\n"
17552 " function foo() {\n"
17559 i::ScopedVector<char> code(1024);
17560 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17561 v8::TryCatch try_catch;
17562 CompileRunWithOrigin(code.start(), "", 0, 0);
17563 CHECK(try_catch.HasCaught());
17564 v8::String::Utf8Value stack(try_catch.StackTrace());
17565 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17569 static void CreateGarbageInOldSpace() {
17570 i::Factory* factory = CcTest::i_isolate()->factory();
17571 v8::HandleScope scope(CcTest::isolate());
17572 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17573 for (int i = 0; i < 1000; i++) {
17574 factory->NewFixedArray(1000, i::TENURED);
17579 // Test that idle notification can be handled and eventually returns true.
17580 TEST(IdleNotification) {
17581 const intptr_t MB = 1024 * 1024;
17583 v8::HandleScope scope(env->GetIsolate());
17584 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17585 CreateGarbageInOldSpace();
17586 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17587 CHECK_GT(size_with_garbage, initial_size + MB);
17588 bool finished = false;
17589 for (int i = 0; i < 200 && !finished; i++) {
17590 finished = v8::V8::IdleNotification();
17592 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17594 CHECK_LT(final_size, initial_size + 1);
17598 // Test that idle notification can be handled and eventually collects garbage.
17599 TEST(IdleNotificationWithSmallHint) {
17600 const intptr_t MB = 1024 * 1024;
17601 const int IdlePauseInMs = 900;
17603 v8::HandleScope scope(env->GetIsolate());
17604 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17605 CreateGarbageInOldSpace();
17606 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17607 CHECK_GT(size_with_garbage, initial_size + MB);
17608 bool finished = false;
17609 for (int i = 0; i < 200 && !finished; i++) {
17610 finished = v8::V8::IdleNotification(IdlePauseInMs);
17612 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17614 CHECK_LT(final_size, initial_size + 1);
17618 // Test that idle notification can be handled and eventually collects garbage.
17619 TEST(IdleNotificationWithLargeHint) {
17620 const intptr_t MB = 1024 * 1024;
17621 const int IdlePauseInMs = 900;
17623 v8::HandleScope scope(env->GetIsolate());
17624 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17625 CreateGarbageInOldSpace();
17626 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17627 CHECK_GT(size_with_garbage, initial_size + MB);
17628 bool finished = false;
17629 for (int i = 0; i < 200 && !finished; i++) {
17630 finished = v8::V8::IdleNotification(IdlePauseInMs);
17632 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17634 CHECK_LT(final_size, initial_size + 1);
17638 TEST(Regress2107) {
17639 const intptr_t MB = 1024 * 1024;
17640 const int kShortIdlePauseInMs = 100;
17641 const int kLongIdlePauseInMs = 1000;
17643 v8::Isolate* isolate = env->GetIsolate();
17644 v8::HandleScope scope(env->GetIsolate());
17645 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17646 // Send idle notification to start a round of incremental GCs.
17647 v8::V8::IdleNotification(kShortIdlePauseInMs);
17648 // Emulate 7 page reloads.
17649 for (int i = 0; i < 7; i++) {
17651 v8::HandleScope inner_scope(env->GetIsolate());
17652 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17654 CreateGarbageInOldSpace();
17657 v8::V8::ContextDisposedNotification();
17658 v8::V8::IdleNotification(kLongIdlePauseInMs);
17660 // Create garbage and check that idle notification still collects it.
17661 CreateGarbageInOldSpace();
17662 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17663 CHECK_GT(size_with_garbage, initial_size + MB);
17664 bool finished = false;
17665 for (int i = 0; i < 200 && !finished; i++) {
17666 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17668 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17669 CHECK_LT(final_size, initial_size + 1);
17673 TEST(Regress2333) {
17675 for (int i = 0; i < 3; i++) {
17676 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17680 static uint32_t* stack_limit;
17682 static void GetStackLimitCallback(
17683 const v8::FunctionCallbackInfo<v8::Value>& args) {
17684 stack_limit = reinterpret_cast<uint32_t*>(
17685 CcTest::i_isolate()->stack_guard()->real_climit());
17689 // Uses the address of a local variable to determine the stack top now.
17690 // Given a size, returns an address that is that far from the current
17692 static uint32_t* ComputeStackLimit(uint32_t size) {
17693 uint32_t* answer = &size - (size / sizeof(size));
17694 // If the size is very large and the stack is very near the bottom of
17695 // memory then the calculation above may wrap around and give an address
17696 // that is above the (downwards-growing) stack. In that case we return
17697 // a very low address.
17698 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17703 // We need at least 165kB for an x64 debug build with clang and ASAN.
17704 static const int stack_breathing_room = 256 * i::KB;
17707 TEST(SetResourceConstraints) {
17708 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17710 // Set stack limit.
17711 v8::ResourceConstraints constraints;
17712 constraints.set_stack_limit(set_limit);
17713 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17715 // Execute a script.
17717 v8::HandleScope scope(env->GetIsolate());
17718 Local<v8::FunctionTemplate> fun_templ =
17719 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17720 Local<Function> fun = fun_templ->GetFunction();
17721 env->Global()->Set(v8_str("get_stack_limit"), fun);
17722 CompileRun("get_stack_limit();");
17724 CHECK(stack_limit == set_limit);
17728 TEST(SetResourceConstraintsInThread) {
17729 uint32_t* set_limit;
17731 v8::Locker locker(CcTest::isolate());
17732 set_limit = ComputeStackLimit(stack_breathing_room);
17734 // Set stack limit.
17735 v8::ResourceConstraints constraints;
17736 constraints.set_stack_limit(set_limit);
17737 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17739 // Execute a script.
17740 v8::HandleScope scope(CcTest::isolate());
17742 Local<v8::FunctionTemplate> fun_templ =
17743 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17744 Local<Function> fun = fun_templ->GetFunction();
17745 env->Global()->Set(v8_str("get_stack_limit"), fun);
17746 CompileRun("get_stack_limit();");
17748 CHECK(stack_limit == set_limit);
17751 v8::Locker locker(CcTest::isolate());
17752 CHECK(stack_limit == set_limit);
17757 THREADED_TEST(GetHeapStatistics) {
17759 v8::HandleScope scope(c1->GetIsolate());
17760 v8::HeapStatistics heap_statistics;
17761 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17762 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17763 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17764 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17765 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17769 class VisitorImpl : public v8::ExternalResourceVisitor {
17771 explicit VisitorImpl(TestResource** resource) {
17772 for (int i = 0; i < 4; i++) {
17773 resource_[i] = resource[i];
17774 found_resource_[i] = false;
17777 virtual ~VisitorImpl() {}
17778 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17779 if (!string->IsExternal()) {
17780 CHECK(string->IsExternalAscii());
17783 v8::String::ExternalStringResource* resource =
17784 string->GetExternalStringResource();
17786 for (int i = 0; i < 4; i++) {
17787 if (resource_[i] == resource) {
17788 CHECK(!found_resource_[i]);
17789 found_resource_[i] = true;
17793 void CheckVisitedResources() {
17794 for (int i = 0; i < 4; i++) {
17795 CHECK(found_resource_[i]);
17800 v8::String::ExternalStringResource* resource_[4];
17801 bool found_resource_[4];
17805 TEST(ExternalizeOldSpaceTwoByteCons) {
17807 v8::HandleScope scope(env->GetIsolate());
17808 v8::Local<v8::String> cons =
17809 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17810 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17811 CcTest::heap()->CollectAllAvailableGarbage();
17812 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17813 *v8::Utils::OpenHandle(*cons)));
17815 TestResource* resource = new TestResource(
17816 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17817 cons->MakeExternal(resource);
17819 CHECK(cons->IsExternal());
17820 CHECK_EQ(resource, cons->GetExternalStringResource());
17821 String::Encoding encoding;
17822 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17823 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17827 TEST(ExternalizeOldSpaceOneByteCons) {
17829 v8::HandleScope scope(env->GetIsolate());
17830 v8::Local<v8::String> cons =
17831 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17832 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17833 CcTest::heap()->CollectAllAvailableGarbage();
17834 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17835 *v8::Utils::OpenHandle(*cons)));
17837 TestAsciiResource* resource =
17838 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17839 cons->MakeExternal(resource);
17841 CHECK(cons->IsExternalAscii());
17842 CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17843 String::Encoding encoding;
17844 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17845 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17849 TEST(VisitExternalStrings) {
17851 v8::HandleScope scope(env->GetIsolate());
17852 const char* string = "Some string";
17853 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17854 TestResource* resource[4];
17855 resource[0] = new TestResource(two_byte_string);
17856 v8::Local<v8::String> string0 =
17857 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17858 resource[1] = new TestResource(two_byte_string, NULL, false);
17859 v8::Local<v8::String> string1 =
17860 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17862 // Externalized symbol.
17863 resource[2] = new TestResource(two_byte_string, NULL, false);
17864 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17865 env->GetIsolate(), string, v8::String::kInternalizedString);
17866 CHECK(string2->MakeExternal(resource[2]));
17868 // Symbolized External.
17869 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17870 v8::Local<v8::String> string3 =
17871 v8::String::NewExternal(env->GetIsolate(), resource[3]);
17872 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17873 // Turn into a symbol.
17874 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17875 CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17876 CHECK(string3_i->IsInternalizedString());
17878 // We need to add usages for string* to avoid warnings in GCC 4.7
17879 CHECK(string0->IsExternal());
17880 CHECK(string1->IsExternal());
17881 CHECK(string2->IsExternal());
17882 CHECK(string3->IsExternal());
17884 VisitorImpl visitor(resource);
17885 v8::V8::VisitExternalResources(&visitor);
17886 visitor.CheckVisitedResources();
17890 TEST(ExternalStringCollectedAtTearDown) {
17892 v8::Isolate* isolate = v8::Isolate::New();
17893 { v8::Isolate::Scope isolate_scope(isolate);
17894 v8::HandleScope handle_scope(isolate);
17895 const char* s = "One string to test them all, one string to find them.";
17896 TestAsciiResource* inscription =
17897 new TestAsciiResource(i::StrDup(s), &destroyed);
17898 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17899 // Ring is still alive. Orcs are roaming freely across our lands.
17900 CHECK_EQ(0, destroyed);
17904 isolate->Dispose();
17905 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17906 CHECK_EQ(1, destroyed);
17910 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17912 v8::Isolate* isolate = v8::Isolate::New();
17913 { v8::Isolate::Scope isolate_scope(isolate);
17914 LocalContext env(isolate);
17915 v8::HandleScope handle_scope(isolate);
17916 CompileRun("var ring = 'One string to test them all';");
17917 const char* s = "One string to test them all";
17918 TestAsciiResource* inscription =
17919 new TestAsciiResource(i::StrDup(s), &destroyed);
17920 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17921 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17922 ring->MakeExternal(inscription);
17923 // Ring is still alive. Orcs are roaming freely across our lands.
17924 CHECK_EQ(0, destroyed);
17928 isolate->Dispose();
17929 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17930 CHECK_EQ(1, destroyed);
17934 TEST(ExternalInternalizedStringCollectedAtGC) {
17936 { LocalContext env;
17937 v8::HandleScope handle_scope(env->GetIsolate());
17938 CompileRun("var ring = 'One string to test them all';");
17939 const char* s = "One string to test them all";
17940 TestAsciiResource* inscription =
17941 new TestAsciiResource(i::StrDup(s), &destroyed);
17942 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17943 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17944 ring->MakeExternal(inscription);
17945 // Ring is still alive. Orcs are roaming freely across our lands.
17946 CHECK_EQ(0, destroyed);
17950 // Garbage collector deals swift blows to evil.
17951 CcTest::i_isolate()->compilation_cache()->Clear();
17952 CcTest::heap()->CollectAllAvailableGarbage();
17954 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17955 CHECK_EQ(1, destroyed);
17959 static double DoubleFromBits(uint64_t value) {
17961 i::OS::MemCopy(&target, &value, sizeof(target));
17966 static uint64_t DoubleToBits(double value) {
17968 i::OS::MemCopy(&target, &value, sizeof(target));
17973 static double DoubleToDateTime(double input) {
17974 double date_limit = 864e13;
17975 if (std::isnan(input) || input < -date_limit || input > date_limit) {
17976 return i::OS::nan_value();
17978 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17982 // We don't have a consistent way to write 64-bit constants syntactically, so we
17983 // split them into two 32-bit constants and combine them programmatically.
17984 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17985 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17989 THREADED_TEST(QuietSignalingNaNs) {
17990 LocalContext context;
17991 v8::Isolate* isolate = context->GetIsolate();
17992 v8::HandleScope scope(isolate);
17993 v8::TryCatch try_catch;
17995 // Special double values.
17996 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17997 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17998 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17999 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18000 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18001 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18002 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18004 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18005 // on either side of the epoch.
18006 double date_limit = 864e13;
18008 double test_values[] = {
18030 int num_test_values = 20;
18032 for (int i = 0; i < num_test_values; i++) {
18033 double test_value = test_values[i];
18035 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18036 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18037 double stored_number = number->NumberValue();
18038 if (!std::isnan(test_value)) {
18039 CHECK_EQ(test_value, stored_number);
18041 uint64_t stored_bits = DoubleToBits(stored_number);
18042 // Check if quiet nan (bits 51..62 all set).
18043 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18044 // Most significant fraction bit for quiet nan is set to 0
18045 // on MIPS architecture. Allowed by IEEE-754.
18046 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18048 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18052 // Check that Date::New preserves non-NaNs in the date range and
18054 v8::Handle<v8::Value> date =
18055 v8::Date::New(isolate, test_value);
18056 double expected_stored_date = DoubleToDateTime(test_value);
18057 double stored_date = date->NumberValue();
18058 if (!std::isnan(expected_stored_date)) {
18059 CHECK_EQ(expected_stored_date, stored_date);
18061 uint64_t stored_bits = DoubleToBits(stored_date);
18062 // Check if quiet nan (bits 51..62 all set).
18063 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18064 // Most significant fraction bit for quiet nan is set to 0
18065 // on MIPS architecture. Allowed by IEEE-754.
18066 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18068 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18075 static void SpaghettiIncident(
18076 const v8::FunctionCallbackInfo<v8::Value>& args) {
18077 v8::HandleScope scope(args.GetIsolate());
18079 v8::Handle<v8::String> str(args[0]->ToString());
18081 if (tc.HasCaught())
18086 // Test that an exception can be propagated down through a spaghetti
18087 // stack using ReThrow.
18088 THREADED_TEST(SpaghettiStackReThrow) {
18089 v8::Isolate* isolate = CcTest::isolate();
18090 v8::HandleScope scope(isolate);
18091 LocalContext context;
18092 context->Global()->Set(
18093 v8::String::NewFromUtf8(isolate, "s"),
18094 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18095 v8::TryCatch try_catch;
18099 " toString: function () {"
18109 CHECK(try_catch.HasCaught());
18110 v8::String::Utf8Value value(try_catch.Exception());
18111 CHECK_EQ(0, strcmp(*value, "Hey!"));
18116 v8::V8::Initialize();
18117 v8::Isolate* isolate = CcTest::isolate();
18118 v8::HandleScope scope(isolate);
18119 v8::Local<Context> other_context;
18122 // Create a context used to keep the code from aging in the compilation
18124 other_context = Context::New(isolate);
18126 // Context-dependent context data creates reference from the compilation
18127 // cache to the global object.
18128 const char* source_simple = "1";
18130 v8::HandleScope scope(isolate);
18131 v8::Local<Context> context = Context::New(isolate);
18134 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18135 context->SetEmbedderData(0, obj);
18136 CompileRun(source_simple);
18139 v8::V8::ContextDisposedNotification();
18140 for (gc_count = 1; gc_count < 10; gc_count++) {
18141 other_context->Enter();
18142 CompileRun(source_simple);
18143 other_context->Exit();
18144 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18145 if (GetGlobalObjectsCount() == 1) break;
18147 CHECK_GE(2, gc_count);
18148 CHECK_EQ(1, GetGlobalObjectsCount());
18150 // Eval in a function creates reference from the compilation cache to the
18152 const char* source_eval = "function f(){eval('1')}; f()";
18154 v8::HandleScope scope(isolate);
18155 v8::Local<Context> context = Context::New(isolate);
18158 CompileRun(source_eval);
18161 v8::V8::ContextDisposedNotification();
18162 for (gc_count = 1; gc_count < 10; gc_count++) {
18163 other_context->Enter();
18164 CompileRun(source_eval);
18165 other_context->Exit();
18166 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18167 if (GetGlobalObjectsCount() == 1) break;
18169 CHECK_GE(2, gc_count);
18170 CHECK_EQ(1, GetGlobalObjectsCount());
18172 // Looking up the line number for an exception creates reference from the
18173 // compilation cache to the global object.
18174 const char* source_exception = "function f(){throw 1;} f()";
18176 v8::HandleScope scope(isolate);
18177 v8::Local<Context> context = Context::New(isolate);
18180 v8::TryCatch try_catch;
18181 CompileRun(source_exception);
18182 CHECK(try_catch.HasCaught());
18183 v8::Handle<v8::Message> message = try_catch.Message();
18184 CHECK(!message.IsEmpty());
18185 CHECK_EQ(1, message->GetLineNumber());
18188 v8::V8::ContextDisposedNotification();
18189 for (gc_count = 1; gc_count < 10; gc_count++) {
18190 other_context->Enter();
18191 CompileRun(source_exception);
18192 other_context->Exit();
18193 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18194 if (GetGlobalObjectsCount() == 1) break;
18196 CHECK_GE(2, gc_count);
18197 CHECK_EQ(1, GetGlobalObjectsCount());
18199 v8::V8::ContextDisposedNotification();
18203 THREADED_TEST(ScriptOrigin) {
18205 v8::HandleScope scope(env->GetIsolate());
18206 v8::ScriptOrigin origin =
18207 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18208 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18209 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18210 v8::Script::Compile(script, &origin)->Run();
18211 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18212 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18213 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18214 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18216 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18217 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18218 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18220 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18221 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18222 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18226 THREADED_TEST(FunctionGetInferredName) {
18228 v8::HandleScope scope(env->GetIsolate());
18229 v8::ScriptOrigin origin =
18230 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18231 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18233 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18234 v8::Script::Compile(script, &origin)->Run();
18235 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18236 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18237 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18241 THREADED_TEST(FunctionGetDisplayName) {
18243 v8::HandleScope scope(env->GetIsolate());
18244 const char* code = "var error = false;"
18245 "function a() { this.x = 1; };"
18246 "a.displayName = 'display_a';"
18247 "var b = (function() {"
18248 " var f = function() { this.x = 2; };"
18249 " f.displayName = 'display_b';"
18252 "var c = function() {};"
18253 "c.__defineGetter__('displayName', function() {"
18255 " throw new Error();"
18258 "d.__defineGetter__('displayName', function() {"
18260 " return 'wrong_display_name';"
18263 "e.displayName = 'wrong_display_name';"
18264 "e.__defineSetter__('displayName', function() {"
18266 " throw new Error();"
18269 "f.displayName = { 'foo': 6, toString: function() {"
18271 " return 'wrong_display_name';"
18273 "var g = function() {"
18274 " arguments.callee.displayName = 'set_in_runtime';"
18277 v8::ScriptOrigin origin =
18278 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18279 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18281 v8::Local<v8::Value> error =
18282 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18283 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18284 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18285 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18286 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18287 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18288 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18289 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18290 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18291 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18292 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18293 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18294 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18295 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18296 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18297 CHECK_EQ(false, error->BooleanValue());
18298 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18299 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18300 CHECK(c->GetDisplayName()->IsUndefined());
18301 CHECK(d->GetDisplayName()->IsUndefined());
18302 CHECK(e->GetDisplayName()->IsUndefined());
18303 CHECK(f->GetDisplayName()->IsUndefined());
18304 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18308 THREADED_TEST(ScriptLineNumber) {
18310 v8::HandleScope scope(env->GetIsolate());
18311 v8::ScriptOrigin origin =
18312 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18313 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18314 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18315 v8::Script::Compile(script, &origin)->Run();
18316 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18317 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18318 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18319 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18320 CHECK_EQ(0, f->GetScriptLineNumber());
18321 CHECK_EQ(2, g->GetScriptLineNumber());
18325 THREADED_TEST(ScriptColumnNumber) {
18327 v8::Isolate* isolate = env->GetIsolate();
18328 v8::HandleScope scope(isolate);
18329 v8::ScriptOrigin origin =
18330 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18331 v8::Integer::New(isolate, 3),
18332 v8::Integer::New(isolate, 2));
18333 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18334 isolate, "function foo() {}\n\n function bar() {}");
18335 v8::Script::Compile(script, &origin)->Run();
18336 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18337 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18338 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18339 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18340 CHECK_EQ(14, foo->GetScriptColumnNumber());
18341 CHECK_EQ(17, bar->GetScriptColumnNumber());
18345 THREADED_TEST(FunctionIsBuiltin) {
18347 v8::Isolate* isolate = env->GetIsolate();
18348 v8::HandleScope scope(isolate);
18349 v8::Local<v8::Function> f;
18350 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18351 CHECK(f->IsBuiltin());
18352 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18353 CHECK(f->IsBuiltin());
18354 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18355 CHECK(f->IsBuiltin());
18356 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18357 CHECK(f->IsBuiltin());
18358 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18359 CHECK(!f->IsBuiltin());
18363 THREADED_TEST(FunctionGetScriptId) {
18365 v8::Isolate* isolate = env->GetIsolate();
18366 v8::HandleScope scope(isolate);
18367 v8::ScriptOrigin origin =
18368 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18369 v8::Integer::New(isolate, 3),
18370 v8::Integer::New(isolate, 2));
18371 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18372 isolate, "function foo() {}\n\n function bar() {}");
18373 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18375 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18376 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18377 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18378 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18379 CHECK_EQ(script->GetId(), foo->ScriptId());
18380 CHECK_EQ(script->GetId(), bar->ScriptId());
18384 THREADED_TEST(FunctionGetBoundFunction) {
18386 v8::HandleScope scope(env->GetIsolate());
18387 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18388 env->GetIsolate(), "test"));
18389 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18391 "var a = new Object();\n"
18393 "function f () { return this.x };\n"
18394 "var g = f.bind(a);\n"
18396 v8::Script::Compile(script, &origin)->Run();
18397 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18398 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18399 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18400 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18401 CHECK(g->GetBoundFunction()->IsFunction());
18402 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18403 g->GetBoundFunction());
18404 CHECK_EQ(f->GetName(), original_function->GetName());
18405 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18406 CHECK_EQ(f->GetScriptColumnNumber(),
18407 original_function->GetScriptColumnNumber());
18411 static void GetterWhichReturns42(
18412 Local<String> name,
18413 const v8::PropertyCallbackInfo<v8::Value>& info) {
18414 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18415 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18416 info.GetReturnValue().Set(v8_num(42));
18420 static void SetterWhichSetsYOnThisTo23(
18421 Local<String> name,
18422 Local<Value> value,
18423 const v8::PropertyCallbackInfo<void>& info) {
18424 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18425 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18426 info.This()->Set(v8_str("y"), v8_num(23));
18430 void FooGetInterceptor(Local<String> name,
18431 const v8::PropertyCallbackInfo<v8::Value>& info) {
18432 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18433 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18434 if (!name->Equals(v8_str("foo"))) return;
18435 info.GetReturnValue().Set(v8_num(42));
18439 void FooSetInterceptor(Local<String> name,
18440 Local<Value> value,
18441 const v8::PropertyCallbackInfo<v8::Value>& info) {
18442 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18443 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18444 if (!name->Equals(v8_str("foo"))) return;
18445 info.This()->Set(v8_str("y"), v8_num(23));
18446 info.GetReturnValue().Set(v8_num(23));
18450 TEST(SetterOnConstructorPrototype) {
18451 v8::Isolate* isolate = CcTest::isolate();
18452 v8::HandleScope scope(isolate);
18453 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18454 templ->SetAccessor(v8_str("x"),
18455 GetterWhichReturns42,
18456 SetterWhichSetsYOnThisTo23);
18457 LocalContext context;
18458 context->Global()->Set(v8_str("P"), templ->NewInstance());
18459 CompileRun("function C1() {"
18462 "C1.prototype = P;"
18466 "C2.prototype = { };"
18467 "C2.prototype.__proto__ = P;");
18469 v8::Local<v8::Script> script;
18470 script = v8_compile("new C1();");
18471 for (int i = 0; i < 10; i++) {
18472 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18473 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18474 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18477 script = v8_compile("new C2();");
18478 for (int i = 0; i < 10; i++) {
18479 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18480 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18481 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18486 static void NamedPropertyGetterWhichReturns42(
18487 Local<String> name,
18488 const v8::PropertyCallbackInfo<v8::Value>& info) {
18489 info.GetReturnValue().Set(v8_num(42));
18493 static void NamedPropertySetterWhichSetsYOnThisTo23(
18494 Local<String> name,
18495 Local<Value> value,
18496 const v8::PropertyCallbackInfo<v8::Value>& info) {
18497 if (name->Equals(v8_str("x"))) {
18498 info.This()->Set(v8_str("y"), v8_num(23));
18503 THREADED_TEST(InterceptorOnConstructorPrototype) {
18504 v8::Isolate* isolate = CcTest::isolate();
18505 v8::HandleScope scope(isolate);
18506 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18507 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18508 NamedPropertySetterWhichSetsYOnThisTo23);
18509 LocalContext context;
18510 context->Global()->Set(v8_str("P"), templ->NewInstance());
18511 CompileRun("function C1() {"
18514 "C1.prototype = P;"
18518 "C2.prototype = { };"
18519 "C2.prototype.__proto__ = P;");
18521 v8::Local<v8::Script> script;
18522 script = v8_compile("new C1();");
18523 for (int i = 0; i < 10; i++) {
18524 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18525 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18526 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18529 script = v8_compile("new C2();");
18530 for (int i = 0; i < 10; i++) {
18531 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18532 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18533 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18539 const char* source = "function C1() {"
18542 "C1.prototype = P;";
18544 LocalContext context;
18545 v8::Isolate* isolate = context->GetIsolate();
18546 v8::HandleScope scope(isolate);
18547 v8::Local<v8::Script> script;
18549 // Use a simple object as prototype.
18550 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18551 prototype->Set(v8_str("y"), v8_num(42));
18552 context->Global()->Set(v8_str("P"), prototype);
18554 // This compile will add the code to the compilation cache.
18555 CompileRun(source);
18557 script = v8_compile("new C1();");
18558 // Allow enough iterations for the inobject slack tracking logic
18559 // to finalize instance size and install the fast construct stub.
18560 for (int i = 0; i < 256; i++) {
18561 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18562 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18563 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18566 // Use an API object with accessors as prototype.
18567 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18568 templ->SetAccessor(v8_str("x"),
18569 GetterWhichReturns42,
18570 SetterWhichSetsYOnThisTo23);
18571 context->Global()->Set(v8_str("P"), templ->NewInstance());
18573 // This compile will get the code from the compilation cache.
18574 CompileRun(source);
18576 script = v8_compile("new C1();");
18577 for (int i = 0; i < 10; i++) {
18578 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18579 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18580 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18584 v8::Isolate* gc_callbacks_isolate = NULL;
18585 int prologue_call_count = 0;
18586 int epilogue_call_count = 0;
18587 int prologue_call_count_second = 0;
18588 int epilogue_call_count_second = 0;
18589 int prologue_call_count_alloc = 0;
18590 int epilogue_call_count_alloc = 0;
18592 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18593 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18594 ++prologue_call_count;
18598 void PrologueCallback(v8::Isolate* isolate,
18600 v8::GCCallbackFlags flags) {
18601 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18602 CHECK_EQ(gc_callbacks_isolate, isolate);
18603 ++prologue_call_count;
18607 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18608 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18609 ++epilogue_call_count;
18613 void EpilogueCallback(v8::Isolate* isolate,
18615 v8::GCCallbackFlags flags) {
18616 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18617 CHECK_EQ(gc_callbacks_isolate, isolate);
18618 ++epilogue_call_count;
18622 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18623 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18624 ++prologue_call_count_second;
18628 void PrologueCallbackSecond(v8::Isolate* isolate,
18630 v8::GCCallbackFlags flags) {
18631 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18632 CHECK_EQ(gc_callbacks_isolate, isolate);
18633 ++prologue_call_count_second;
18637 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18638 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18639 ++epilogue_call_count_second;
18643 void EpilogueCallbackSecond(v8::Isolate* isolate,
18645 v8::GCCallbackFlags flags) {
18646 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18647 CHECK_EQ(gc_callbacks_isolate, isolate);
18648 ++epilogue_call_count_second;
18652 void PrologueCallbackAlloc(v8::Isolate* isolate,
18654 v8::GCCallbackFlags flags) {
18655 v8::HandleScope scope(isolate);
18657 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18658 CHECK_EQ(gc_callbacks_isolate, isolate);
18659 ++prologue_call_count_alloc;
18661 // Simulate full heap to see if we will reenter this callback
18662 SimulateFullSpace(CcTest::heap()->new_space());
18664 Local<Object> obj = Object::New(isolate);
18665 CHECK(!obj.IsEmpty());
18667 CcTest::heap()->CollectAllGarbage(
18668 i::Heap::kAbortIncrementalMarkingMask);
18672 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18674 v8::GCCallbackFlags flags) {
18675 v8::HandleScope scope(isolate);
18677 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18678 CHECK_EQ(gc_callbacks_isolate, isolate);
18679 ++epilogue_call_count_alloc;
18681 // Simulate full heap to see if we will reenter this callback
18682 SimulateFullSpace(CcTest::heap()->new_space());
18684 Local<Object> obj = Object::New(isolate);
18685 CHECK(!obj.IsEmpty());
18687 CcTest::heap()->CollectAllGarbage(
18688 i::Heap::kAbortIncrementalMarkingMask);
18692 TEST(GCCallbacksOld) {
18693 LocalContext context;
18695 v8::V8::AddGCPrologueCallback(PrologueCallback);
18696 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18697 CHECK_EQ(0, prologue_call_count);
18698 CHECK_EQ(0, epilogue_call_count);
18699 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18700 CHECK_EQ(1, prologue_call_count);
18701 CHECK_EQ(1, epilogue_call_count);
18702 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18703 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18704 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18705 CHECK_EQ(2, prologue_call_count);
18706 CHECK_EQ(2, epilogue_call_count);
18707 CHECK_EQ(1, prologue_call_count_second);
18708 CHECK_EQ(1, epilogue_call_count_second);
18709 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18710 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18711 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18712 CHECK_EQ(2, prologue_call_count);
18713 CHECK_EQ(2, epilogue_call_count);
18714 CHECK_EQ(2, prologue_call_count_second);
18715 CHECK_EQ(2, epilogue_call_count_second);
18716 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18717 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18718 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18719 CHECK_EQ(2, prologue_call_count);
18720 CHECK_EQ(2, epilogue_call_count);
18721 CHECK_EQ(2, prologue_call_count_second);
18722 CHECK_EQ(2, epilogue_call_count_second);
18726 TEST(GCCallbacks) {
18727 LocalContext context;
18728 v8::Isolate* isolate = context->GetIsolate();
18729 gc_callbacks_isolate = isolate;
18730 isolate->AddGCPrologueCallback(PrologueCallback);
18731 isolate->AddGCEpilogueCallback(EpilogueCallback);
18732 CHECK_EQ(0, prologue_call_count);
18733 CHECK_EQ(0, epilogue_call_count);
18734 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18735 CHECK_EQ(1, prologue_call_count);
18736 CHECK_EQ(1, epilogue_call_count);
18737 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18738 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18739 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18740 CHECK_EQ(2, prologue_call_count);
18741 CHECK_EQ(2, epilogue_call_count);
18742 CHECK_EQ(1, prologue_call_count_second);
18743 CHECK_EQ(1, epilogue_call_count_second);
18744 isolate->RemoveGCPrologueCallback(PrologueCallback);
18745 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18746 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18747 CHECK_EQ(2, prologue_call_count);
18748 CHECK_EQ(2, epilogue_call_count);
18749 CHECK_EQ(2, prologue_call_count_second);
18750 CHECK_EQ(2, epilogue_call_count_second);
18751 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18752 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18753 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18754 CHECK_EQ(2, prologue_call_count);
18755 CHECK_EQ(2, epilogue_call_count);
18756 CHECK_EQ(2, prologue_call_count_second);
18757 CHECK_EQ(2, epilogue_call_count_second);
18759 CHECK_EQ(0, prologue_call_count_alloc);
18760 CHECK_EQ(0, epilogue_call_count_alloc);
18761 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18762 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18763 CcTest::heap()->CollectAllGarbage(
18764 i::Heap::kAbortIncrementalMarkingMask);
18765 CHECK_EQ(1, prologue_call_count_alloc);
18766 CHECK_EQ(1, epilogue_call_count_alloc);
18767 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18768 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18772 THREADED_TEST(AddToJSFunctionResultCache) {
18773 i::FLAG_stress_compaction = false;
18774 i::FLAG_allow_natives_syntax = true;
18775 v8::HandleScope scope(CcTest::isolate());
18777 LocalContext context;
18783 " var r0 = %_GetFromCache(0, key0);"
18784 " var r1 = %_GetFromCache(0, key1);"
18785 " var r0_ = %_GetFromCache(0, key0);"
18787 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18788 " var r1_ = %_GetFromCache(0, key1);"
18790 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18791 " return 'PASSED';"
18793 CcTest::heap()->ClearJSFunctionResultCaches();
18794 ExpectString(code, "PASSED");
18798 THREADED_TEST(FillJSFunctionResultCache) {
18799 i::FLAG_allow_natives_syntax = true;
18800 LocalContext context;
18801 v8::HandleScope scope(context->GetIsolate());
18806 " var r = %_GetFromCache(0, k);"
18807 " for (var i = 0; i < 16; i++) {"
18808 " %_GetFromCache(0, 'a' + i);"
18810 " if (r === %_GetFromCache(0, k))"
18811 " return 'FAILED: k0CacheSize is too small';"
18812 " return 'PASSED';"
18814 CcTest::heap()->ClearJSFunctionResultCaches();
18815 ExpectString(code, "PASSED");
18819 THREADED_TEST(RoundRobinGetFromCache) {
18820 i::FLAG_allow_natives_syntax = true;
18821 LocalContext context;
18822 v8::HandleScope scope(context->GetIsolate());
18827 " for (var i = 0; i < 16; i++) keys.push(i);"
18828 " var values = [];"
18829 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18830 " for (var i = 0; i < 16; i++) {"
18831 " var v = %_GetFromCache(0, keys[i]);"
18832 " if (v.toString() !== values[i].toString())"
18833 " return 'Wrong value for ' + "
18834 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18836 " return 'PASSED';"
18838 CcTest::heap()->ClearJSFunctionResultCaches();
18839 ExpectString(code, "PASSED");
18843 THREADED_TEST(ReverseGetFromCache) {
18844 i::FLAG_allow_natives_syntax = true;
18845 LocalContext context;
18846 v8::HandleScope scope(context->GetIsolate());
18851 " for (var i = 0; i < 16; i++) keys.push(i);"
18852 " var values = [];"
18853 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18854 " for (var i = 15; i >= 16; i--) {"
18855 " var v = %_GetFromCache(0, keys[i]);"
18856 " if (v !== values[i])"
18857 " return 'Wrong value for ' + "
18858 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18860 " return 'PASSED';"
18862 CcTest::heap()->ClearJSFunctionResultCaches();
18863 ExpectString(code, "PASSED");
18867 THREADED_TEST(TestEviction) {
18868 i::FLAG_allow_natives_syntax = true;
18869 LocalContext context;
18870 v8::HandleScope scope(context->GetIsolate());
18874 " for (var i = 0; i < 2*16; i++) {"
18875 " %_GetFromCache(0, 'a' + i);"
18877 " return 'PASSED';"
18879 CcTest::heap()->ClearJSFunctionResultCaches();
18880 ExpectString(code, "PASSED");
18884 THREADED_TEST(TwoByteStringInAsciiCons) {
18885 // See Chromium issue 47824.
18886 LocalContext context;
18887 v8::HandleScope scope(context->GetIsolate());
18889 const char* init_code =
18890 "var str1 = 'abelspendabel';"
18891 "var str2 = str1 + str1 + str1;"
18893 Local<Value> result = CompileRun(init_code);
18895 Local<Value> indexof = CompileRun("str2.indexOf('els')");
18896 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18898 CHECK(result->IsString());
18899 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18900 int length = string->length();
18901 CHECK(string->IsOneByteRepresentation());
18903 FlattenString(string);
18904 i::Handle<i::String> flat_string = FlattenGetString(string);
18906 CHECK(string->IsOneByteRepresentation());
18907 CHECK(flat_string->IsOneByteRepresentation());
18909 // Create external resource.
18910 uint16_t* uc16_buffer = new uint16_t[length + 1];
18912 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18913 uc16_buffer[length] = 0;
18915 TestResource resource(uc16_buffer);
18917 flat_string->MakeExternal(&resource);
18919 CHECK(flat_string->IsTwoByteRepresentation());
18921 // If the cons string has been short-circuited, skip the following checks.
18922 if (!string.is_identical_to(flat_string)) {
18923 // At this point, we should have a Cons string which is flat and ASCII,
18924 // with a first half that is a two-byte string (although it only contains
18925 // ASCII characters). This is a valid sequence of steps, and it can happen
18927 CHECK(string->IsOneByteRepresentation());
18928 i::ConsString* cons = i::ConsString::cast(*string);
18929 CHECK_EQ(0, cons->second()->length());
18930 CHECK(cons->first()->IsTwoByteRepresentation());
18933 // Check that some string operations work.
18936 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18937 CHECK_EQ(6, reresult->Int32Value());
18940 reresult = CompileRun("str2.match(/abe./g).length;");
18941 CHECK_EQ(6, reresult->Int32Value());
18943 reresult = CompileRun("str2.search(/bel/g);");
18944 CHECK_EQ(1, reresult->Int32Value());
18946 reresult = CompileRun("str2.search(/be./g);");
18947 CHECK_EQ(1, reresult->Int32Value());
18949 ExpectTrue("/bel/g.test(str2);");
18951 ExpectTrue("/be./g.test(str2);");
18953 reresult = CompileRun("/bel/g.exec(str2);");
18954 CHECK(!reresult->IsNull());
18956 reresult = CompileRun("/be./g.exec(str2);");
18957 CHECK(!reresult->IsNull());
18959 ExpectString("str2.substring(2, 10);", "elspenda");
18961 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18963 ExpectString("str2.charAt(2);", "e");
18965 ExpectObject("str2.indexOf('els');", indexof);
18967 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18969 reresult = CompileRun("str2.charCodeAt(2);");
18970 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18974 TEST(ContainsOnlyOneByte) {
18975 v8::V8::Initialize();
18976 v8::Isolate* isolate = CcTest::isolate();
18977 v8::HandleScope scope(isolate);
18978 // Make a buffer long enough that it won't automatically be converted.
18979 const int length = 512;
18980 // Ensure word aligned assignment.
18981 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18982 i::SmartArrayPointer<uintptr_t>
18983 aligned_contents(new uintptr_t[aligned_length]);
18984 uint16_t* string_contents =
18985 reinterpret_cast<uint16_t*>(aligned_contents.get());
18986 // Set to contain only one byte.
18987 for (int i = 0; i < length-1; i++) {
18988 string_contents[i] = 0x41;
18990 string_contents[length-1] = 0;
18992 Handle<String> string =
18993 String::NewExternal(isolate,
18994 new TestResource(string_contents, NULL, false));
18995 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18996 // Counter example.
18997 string = String::NewFromTwoByte(isolate, string_contents);
18998 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18999 // Test left right and balanced cons strings.
19000 Handle<String> base = String::NewFromUtf8(isolate, "a");
19001 Handle<String> left = base;
19002 Handle<String> right = base;
19003 for (int i = 0; i < 1000; i++) {
19004 left = String::Concat(base, left);
19005 right = String::Concat(right, base);
19007 Handle<String> balanced = String::Concat(left, base);
19008 balanced = String::Concat(balanced, right);
19009 Handle<String> cons_strings[] = {left, balanced, right};
19010 Handle<String> two_byte =
19011 String::NewExternal(isolate,
19012 new TestResource(string_contents, NULL, false));
19013 USE(two_byte); USE(cons_strings);
19014 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19015 // Base assumptions.
19016 string = cons_strings[i];
19017 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19018 // Test left and right concatentation.
19019 string = String::Concat(two_byte, cons_strings[i]);
19020 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19021 string = String::Concat(cons_strings[i], two_byte);
19022 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19024 // Set bits in different positions
19025 // for strings of different lengths and alignments.
19026 for (int alignment = 0; alignment < 7; alignment++) {
19027 for (int size = 2; alignment + size < length; size *= 2) {
19028 int zero_offset = size + alignment;
19029 string_contents[zero_offset] = 0;
19030 for (int i = 0; i < size; i++) {
19031 int shift = 8 + (i % 7);
19032 string_contents[alignment + i] = 1 << shift;
19033 string = String::NewExternal(
19035 new TestResource(string_contents + alignment, NULL, false));
19036 CHECK_EQ(size, string->Length());
19037 CHECK(!string->ContainsOnlyOneByte());
19038 string_contents[alignment + i] = 0x41;
19040 string_contents[zero_offset] = 0x41;
19046 // Failed access check callback that performs a GC on each invocation.
19047 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19048 v8::AccessType type,
19049 Local<v8::Value> data) {
19050 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19054 TEST(GCInFailedAccessCheckCallback) {
19055 // Install a failed access check callback that performs a GC on each
19056 // invocation. Then force the callback to be called from va
19058 v8::V8::Initialize();
19059 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19061 v8::Isolate* isolate = CcTest::isolate();
19062 v8::HandleScope scope(isolate);
19064 // Create an ObjectTemplate for global objects and install access
19065 // check callbacks that will block access.
19066 v8::Handle<v8::ObjectTemplate> global_template =
19067 v8::ObjectTemplate::New(isolate);
19068 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19069 IndexedGetAccessBlocker,
19070 v8::Handle<v8::Value>(),
19073 // Create a context and set an x property on it's global object.
19074 LocalContext context0(NULL, global_template);
19075 context0->Global()->Set(v8_str("x"), v8_num(42));
19076 v8::Handle<v8::Object> global0 = context0->Global();
19078 // Create a context with a different security token so that the
19079 // failed access check callback will be called on each access.
19080 LocalContext context1(NULL, global_template);
19081 context1->Global()->Set(v8_str("other"), global0);
19083 // Get property with failed access check.
19084 ExpectUndefined("other.x");
19086 // Get element with failed access check.
19087 ExpectUndefined("other[0]");
19089 // Set property with failed access check.
19090 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19091 CHECK(result->IsObject());
19093 // Set element with failed access check.
19094 result = CompileRun("other[0] = new Object()");
19095 CHECK(result->IsObject());
19097 // Get property attribute with failed access check.
19098 ExpectFalse("\'x\' in other");
19100 // Get property attribute for element with failed access check.
19101 ExpectFalse("0 in other");
19103 // Delete property.
19104 ExpectFalse("delete other.x");
19107 CHECK_EQ(false, global0->Delete(0));
19111 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19113 // Define JavaScript accessor.
19114 ExpectUndefined("Object.prototype.__defineGetter__.call("
19115 " other, \'x\', function() { return 42; })");
19118 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19121 // HasLocalElement.
19122 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19124 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19125 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19126 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19128 // Reset the failed access check callback so it does not influence
19129 // the other tests.
19130 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19134 TEST(IsolateNewDispose) {
19135 v8::Isolate* current_isolate = CcTest::isolate();
19136 v8::Isolate* isolate = v8::Isolate::New();
19137 CHECK(isolate != NULL);
19138 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19139 CHECK(current_isolate != isolate);
19140 CHECK(current_isolate == CcTest::isolate());
19142 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19143 last_location = last_message = NULL;
19144 isolate->Dispose();
19145 CHECK_EQ(last_location, NULL);
19146 CHECK_EQ(last_message, NULL);
19150 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19151 v8::Isolate* isolate = v8::Isolate::New();
19153 v8::Isolate::Scope i_scope(isolate);
19154 v8::HandleScope scope(isolate);
19155 LocalContext context(isolate);
19156 // Run something in this isolate.
19157 ExpectTrue("true");
19158 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19159 last_location = last_message = NULL;
19160 // Still entered, should fail.
19161 isolate->Dispose();
19162 CHECK_NE(last_location, NULL);
19163 CHECK_NE(last_message, NULL);
19165 isolate->Dispose();
19169 TEST(RunTwoIsolatesOnSingleThread) {
19171 v8::Isolate* isolate1 = v8::Isolate::New();
19173 v8::Persistent<v8::Context> context1;
19175 v8::HandleScope scope(isolate1);
19176 context1.Reset(isolate1, Context::New(isolate1));
19180 v8::HandleScope scope(isolate1);
19181 v8::Local<v8::Context> context =
19182 v8::Local<v8::Context>::New(isolate1, context1);
19183 v8::Context::Scope context_scope(context);
19184 // Run something in new isolate.
19185 CompileRun("var foo = 'isolate 1';");
19186 ExpectString("function f() { return foo; }; f()", "isolate 1");
19190 v8::Isolate* isolate2 = v8::Isolate::New();
19191 v8::Persistent<v8::Context> context2;
19194 v8::Isolate::Scope iscope(isolate2);
19195 v8::HandleScope scope(isolate2);
19196 context2.Reset(isolate2, Context::New(isolate2));
19197 v8::Local<v8::Context> context =
19198 v8::Local<v8::Context>::New(isolate2, context2);
19199 v8::Context::Scope context_scope(context);
19201 // Run something in new isolate.
19202 CompileRun("var foo = 'isolate 2';");
19203 ExpectString("function f() { return foo; }; f()", "isolate 2");
19207 v8::HandleScope scope(isolate1);
19208 v8::Local<v8::Context> context =
19209 v8::Local<v8::Context>::New(isolate1, context1);
19210 v8::Context::Scope context_scope(context);
19211 // Now again in isolate 1
19212 ExpectString("function f() { return foo; }; f()", "isolate 1");
19217 // Run some stuff in default isolate.
19218 v8::Persistent<v8::Context> context_default;
19220 v8::Isolate* isolate = CcTest::isolate();
19221 v8::Isolate::Scope iscope(isolate);
19222 v8::HandleScope scope(isolate);
19223 context_default.Reset(isolate, Context::New(isolate));
19227 v8::HandleScope scope(CcTest::isolate());
19228 v8::Local<v8::Context> context =
19229 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19230 v8::Context::Scope context_scope(context);
19231 // Variables in other isolates should be not available, verify there
19232 // is an exception.
19233 ExpectTrue("function f() {"
19241 "var isDefaultIsolate = true;"
19248 v8::Isolate::Scope iscope(isolate2);
19249 v8::HandleScope scope(isolate2);
19250 v8::Local<v8::Context> context =
19251 v8::Local<v8::Context>::New(isolate2, context2);
19252 v8::Context::Scope context_scope(context);
19253 ExpectString("function f() { return foo; }; f()", "isolate 2");
19257 v8::HandleScope scope(v8::Isolate::GetCurrent());
19258 v8::Local<v8::Context> context =
19259 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19260 v8::Context::Scope context_scope(context);
19261 ExpectString("function f() { return foo; }; f()", "isolate 1");
19265 v8::Isolate::Scope iscope(isolate2);
19272 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19273 last_location = last_message = NULL;
19275 isolate1->Dispose();
19276 CHECK_EQ(last_location, NULL);
19277 CHECK_EQ(last_message, NULL);
19279 isolate2->Dispose();
19280 CHECK_EQ(last_location, NULL);
19281 CHECK_EQ(last_message, NULL);
19283 // Check that default isolate still runs.
19285 v8::HandleScope scope(CcTest::isolate());
19286 v8::Local<v8::Context> context =
19287 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19288 v8::Context::Scope context_scope(context);
19289 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19294 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19295 v8::Isolate::Scope isolate_scope(isolate);
19296 v8::HandleScope scope(isolate);
19297 LocalContext context(isolate);
19298 i::ScopedVector<char> code(1024);
19299 i::OS::SNPrintF(code, "function fib(n) {"
19300 " if (n <= 2) return 1;"
19301 " return fib(n-1) + fib(n-2);"
19304 Local<Value> value = CompileRun(code.start());
19305 CHECK(value->IsNumber());
19306 return static_cast<int>(value->NumberValue());
19309 class IsolateThread : public v8::internal::Thread {
19311 IsolateThread(v8::Isolate* isolate, int fib_limit)
19312 : Thread("IsolateThread"),
19314 fib_limit_(fib_limit),
19318 result_ = CalcFibonacci(isolate_, fib_limit_);
19321 int result() { return result_; }
19324 v8::Isolate* isolate_;
19330 TEST(MultipleIsolatesOnIndividualThreads) {
19331 v8::Isolate* isolate1 = v8::Isolate::New();
19332 v8::Isolate* isolate2 = v8::Isolate::New();
19334 IsolateThread thread1(isolate1, 21);
19335 IsolateThread thread2(isolate2, 12);
19337 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19341 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19342 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19347 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19348 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19349 CHECK_EQ(result1, 10946);
19350 CHECK_EQ(result2, 144);
19351 CHECK_EQ(result1, thread1.result());
19352 CHECK_EQ(result2, thread2.result());
19354 isolate1->Dispose();
19355 isolate2->Dispose();
19359 TEST(IsolateDifferentContexts) {
19360 v8::Isolate* isolate = v8::Isolate::New();
19361 Local<v8::Context> context;
19363 v8::Isolate::Scope isolate_scope(isolate);
19364 v8::HandleScope handle_scope(isolate);
19365 context = v8::Context::New(isolate);
19366 v8::Context::Scope context_scope(context);
19367 Local<Value> v = CompileRun("2");
19368 CHECK(v->IsNumber());
19369 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19372 v8::Isolate::Scope isolate_scope(isolate);
19373 v8::HandleScope handle_scope(isolate);
19374 context = v8::Context::New(isolate);
19375 v8::Context::Scope context_scope(context);
19376 Local<Value> v = CompileRun("22");
19377 CHECK(v->IsNumber());
19378 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19380 isolate->Dispose();
19383 class InitDefaultIsolateThread : public v8::internal::Thread {
19386 SetResourceConstraints,
19388 SetCounterFunction,
19389 SetCreateHistogramFunction,
19390 SetAddHistogramSampleFunction
19393 explicit InitDefaultIsolateThread(TestCase testCase)
19394 : Thread("InitDefaultIsolateThread"),
19395 testCase_(testCase),
19399 v8::Isolate* isolate = v8::Isolate::New();
19401 switch (testCase_) {
19402 case SetResourceConstraints: {
19403 static const int K = 1024;
19404 v8::ResourceConstraints constraints;
19405 constraints.set_max_young_space_size(256 * K);
19406 constraints.set_max_old_space_size(4 * K * K);
19407 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19411 case SetFatalHandler:
19412 v8::V8::SetFatalErrorHandler(NULL);
19415 case SetCounterFunction:
19416 v8::V8::SetCounterFunction(NULL);
19419 case SetCreateHistogramFunction:
19420 v8::V8::SetCreateHistogramFunction(NULL);
19423 case SetAddHistogramSampleFunction:
19424 v8::V8::SetAddHistogramSampleFunction(NULL);
19428 isolate->Dispose();
19432 bool result() { return result_; }
19435 TestCase testCase_;
19440 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19441 InitDefaultIsolateThread thread(testCase);
19444 CHECK_EQ(thread.result(), true);
19448 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19449 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19453 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19454 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19458 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19459 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19463 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19464 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19468 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19469 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19473 TEST(StringCheckMultipleContexts) {
19475 "(function() { return \"a\".charAt(0); })()";
19478 // Run the code twice in the first context to initialize the call IC.
19479 LocalContext context1;
19480 v8::HandleScope scope(context1->GetIsolate());
19481 ExpectString(code, "a");
19482 ExpectString(code, "a");
19486 // Change the String.prototype in the second context and check
19487 // that the right function gets called.
19488 LocalContext context2;
19489 v8::HandleScope scope(context2->GetIsolate());
19490 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19491 ExpectString(code, "not a");
19496 TEST(NumberCheckMultipleContexts) {
19498 "(function() { return (42).toString(); })()";
19501 // Run the code twice in the first context to initialize the call IC.
19502 LocalContext context1;
19503 v8::HandleScope scope(context1->GetIsolate());
19504 ExpectString(code, "42");
19505 ExpectString(code, "42");
19509 // Change the Number.prototype in the second context and check
19510 // that the right function gets called.
19511 LocalContext context2;
19512 v8::HandleScope scope(context2->GetIsolate());
19513 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19514 ExpectString(code, "not 42");
19519 TEST(BooleanCheckMultipleContexts) {
19521 "(function() { return true.toString(); })()";
19524 // Run the code twice in the first context to initialize the call IC.
19525 LocalContext context1;
19526 v8::HandleScope scope(context1->GetIsolate());
19527 ExpectString(code, "true");
19528 ExpectString(code, "true");
19532 // Change the Boolean.prototype in the second context and check
19533 // that the right function gets called.
19534 LocalContext context2;
19535 v8::HandleScope scope(context2->GetIsolate());
19536 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19537 ExpectString(code, "");
19542 TEST(DontDeleteCellLoadIC) {
19543 const char* function_code =
19544 "function readCell() { while (true) { return cell; } }";
19547 // Run the code twice in the first context to initialize the load
19548 // IC for a don't delete cell.
19549 LocalContext context1;
19550 v8::HandleScope scope(context1->GetIsolate());
19551 CompileRun("var cell = \"first\";");
19552 ExpectBoolean("delete cell", false);
19553 CompileRun(function_code);
19554 ExpectString("readCell()", "first");
19555 ExpectString("readCell()", "first");
19559 // Use a deletable cell in the second context.
19560 LocalContext context2;
19561 v8::HandleScope scope(context2->GetIsolate());
19562 CompileRun("cell = \"second\";");
19563 CompileRun(function_code);
19564 ExpectString("readCell()", "second");
19565 ExpectBoolean("delete cell", true);
19566 ExpectString("(function() {"
19568 " return readCell();"
19570 " return e.toString();"
19573 "ReferenceError: cell is not defined");
19574 CompileRun("cell = \"new_second\";");
19575 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19576 ExpectString("readCell()", "new_second");
19577 ExpectString("readCell()", "new_second");
19582 TEST(DontDeleteCellLoadICForceDelete) {
19583 const char* function_code =
19584 "function readCell() { while (true) { return cell; } }";
19586 // Run the code twice to initialize the load IC for a don't delete
19588 LocalContext context;
19589 v8::HandleScope scope(context->GetIsolate());
19590 CompileRun("var cell = \"value\";");
19591 ExpectBoolean("delete cell", false);
19592 CompileRun(function_code);
19593 ExpectString("readCell()", "value");
19594 ExpectString("readCell()", "value");
19596 // Delete the cell using the API and check the inlined code works
19598 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19599 ExpectString("(function() {"
19601 " return readCell();"
19603 " return e.toString();"
19606 "ReferenceError: cell is not defined");
19610 TEST(DontDeleteCellLoadICAPI) {
19611 const char* function_code =
19612 "function readCell() { while (true) { return cell; } }";
19614 // Run the code twice to initialize the load IC for a don't delete
19615 // cell created using the API.
19616 LocalContext context;
19617 v8::HandleScope scope(context->GetIsolate());
19618 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19619 ExpectBoolean("delete cell", false);
19620 CompileRun(function_code);
19621 ExpectString("readCell()", "value");
19622 ExpectString("readCell()", "value");
19624 // Delete the cell using the API and check the inlined code works
19626 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19627 ExpectString("(function() {"
19629 " return readCell();"
19631 " return e.toString();"
19634 "ReferenceError: cell is not defined");
19638 class Visitor42 : public v8::PersistentHandleVisitor {
19640 explicit Visitor42(v8::Persistent<v8::Object>* object)
19641 : counter_(0), object_(object) { }
19643 virtual void VisitPersistentHandle(Persistent<Value>* value,
19644 uint16_t class_id) {
19645 if (class_id != 42) return;
19646 CHECK_EQ(42, value->WrapperClassId());
19647 v8::Isolate* isolate = CcTest::isolate();
19648 v8::HandleScope handle_scope(isolate);
19649 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19650 v8::Handle<v8::Value> object =
19651 v8::Local<v8::Object>::New(isolate, *object_);
19652 CHECK(handle->IsObject());
19653 CHECK_EQ(Handle<Object>::Cast(handle), object);
19658 v8::Persistent<v8::Object>* object_;
19662 TEST(PersistentHandleVisitor) {
19663 LocalContext context;
19664 v8::Isolate* isolate = context->GetIsolate();
19665 v8::HandleScope scope(isolate);
19666 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19667 CHECK_EQ(0, object.WrapperClassId());
19668 object.SetWrapperClassId(42);
19669 CHECK_EQ(42, object.WrapperClassId());
19671 Visitor42 visitor(&object);
19672 v8::V8::VisitHandlesWithClassIds(&visitor);
19673 CHECK_EQ(1, visitor.counter_);
19679 TEST(WrapperClassId) {
19680 LocalContext context;
19681 v8::Isolate* isolate = context->GetIsolate();
19682 v8::HandleScope scope(isolate);
19683 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19684 CHECK_EQ(0, object.WrapperClassId());
19685 object.SetWrapperClassId(65535);
19686 CHECK_EQ(65535, object.WrapperClassId());
19691 TEST(PersistentHandleInNewSpaceVisitor) {
19692 LocalContext context;
19693 v8::Isolate* isolate = context->GetIsolate();
19694 v8::HandleScope scope(isolate);
19695 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19696 CHECK_EQ(0, object1.WrapperClassId());
19697 object1.SetWrapperClassId(42);
19698 CHECK_EQ(42, object1.WrapperClassId());
19700 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19702 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19703 CHECK_EQ(0, object2.WrapperClassId());
19704 object2.SetWrapperClassId(42);
19705 CHECK_EQ(42, object2.WrapperClassId());
19707 Visitor42 visitor(&object2);
19708 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19709 CHECK_EQ(1, visitor.counter_);
19717 LocalContext context;
19718 v8::HandleScope scope(context->GetIsolate());
19720 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19721 CHECK(re->IsRegExp());
19722 CHECK(re->GetSource()->Equals(v8_str("foo")));
19723 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19725 re = v8::RegExp::New(v8_str("bar"),
19726 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19727 v8::RegExp::kGlobal));
19728 CHECK(re->IsRegExp());
19729 CHECK(re->GetSource()->Equals(v8_str("bar")));
19730 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19731 static_cast<int>(re->GetFlags()));
19733 re = v8::RegExp::New(v8_str("baz"),
19734 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19735 v8::RegExp::kMultiline));
19736 CHECK(re->IsRegExp());
19737 CHECK(re->GetSource()->Equals(v8_str("baz")));
19738 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19739 static_cast<int>(re->GetFlags()));
19741 re = CompileRun("/quux/").As<v8::RegExp>();
19742 CHECK(re->IsRegExp());
19743 CHECK(re->GetSource()->Equals(v8_str("quux")));
19744 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19746 re = CompileRun("/quux/gm").As<v8::RegExp>();
19747 CHECK(re->IsRegExp());
19748 CHECK(re->GetSource()->Equals(v8_str("quux")));
19749 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19750 static_cast<int>(re->GetFlags()));
19752 // Override the RegExp constructor and check the API constructor
19754 CompileRun("RegExp = function() {}");
19756 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19757 CHECK(re->IsRegExp());
19758 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19759 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19761 re = v8::RegExp::New(v8_str("foobarbaz"),
19762 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19763 v8::RegExp::kMultiline));
19764 CHECK(re->IsRegExp());
19765 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19766 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19767 static_cast<int>(re->GetFlags()));
19769 context->Global()->Set(v8_str("re"), re);
19770 ExpectTrue("re.test('FoobarbaZ')");
19772 // RegExps are objects on which you can set properties.
19773 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19774 v8::Handle<v8::Value> value(CompileRun("re.property"));
19775 CHECK_EQ(32, value->Int32Value());
19777 v8::TryCatch try_catch;
19778 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19779 CHECK(re.IsEmpty());
19780 CHECK(try_catch.HasCaught());
19781 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19782 ExpectTrue("ex instanceof SyntaxError");
19786 THREADED_TEST(Equals) {
19787 LocalContext localContext;
19788 v8::HandleScope handleScope(localContext->GetIsolate());
19790 v8::Handle<v8::Object> globalProxy = localContext->Global();
19791 v8::Handle<Value> global = globalProxy->GetPrototype();
19793 CHECK(global->StrictEquals(global));
19794 CHECK(!global->StrictEquals(globalProxy));
19795 CHECK(!globalProxy->StrictEquals(global));
19796 CHECK(globalProxy->StrictEquals(globalProxy));
19798 CHECK(global->Equals(global));
19799 CHECK(!global->Equals(globalProxy));
19800 CHECK(!globalProxy->Equals(global));
19801 CHECK(globalProxy->Equals(globalProxy));
19805 static void Getter(v8::Local<v8::String> property,
19806 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19807 info.GetReturnValue().Set(v8_str("42!"));
19811 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19812 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19813 result->Set(0, v8_str("universalAnswer"));
19814 info.GetReturnValue().Set(result);
19818 TEST(NamedEnumeratorAndForIn) {
19819 LocalContext context;
19820 v8::Isolate* isolate = context->GetIsolate();
19821 v8::HandleScope handle_scope(isolate);
19822 v8::Context::Scope context_scope(context.local());
19824 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19825 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19826 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19827 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19828 "var result = []; for (var k in o) result.push(k); result"));
19829 CHECK_EQ(1, result->Length());
19830 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19834 TEST(DefinePropertyPostDetach) {
19835 LocalContext context;
19836 v8::HandleScope scope(context->GetIsolate());
19837 v8::Handle<v8::Object> proxy = context->Global();
19838 v8::Handle<v8::Function> define_property =
19839 CompileRun("(function() {"
19840 " Object.defineProperty("
19843 " { configurable: true, enumerable: true, value: 3 });"
19844 "})").As<Function>();
19845 context->DetachGlobal();
19846 define_property->Call(proxy, 0, NULL);
19850 static void InstallContextId(v8::Handle<Context> context, int id) {
19851 Context::Scope scope(context);
19852 CompileRun("Object.prototype").As<Object>()->
19853 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19857 static void CheckContextId(v8::Handle<Object> object, int expected) {
19858 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19862 THREADED_TEST(CreationContext) {
19863 v8::Isolate* isolate = CcTest::isolate();
19864 HandleScope handle_scope(isolate);
19865 Handle<Context> context1 = Context::New(isolate);
19866 InstallContextId(context1, 1);
19867 Handle<Context> context2 = Context::New(isolate);
19868 InstallContextId(context2, 2);
19869 Handle<Context> context3 = Context::New(isolate);
19870 InstallContextId(context3, 3);
19872 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19874 Local<Object> object1;
19875 Local<Function> func1;
19877 Context::Scope scope(context1);
19878 object1 = Object::New(isolate);
19879 func1 = tmpl->GetFunction();
19882 Local<Object> object2;
19883 Local<Function> func2;
19885 Context::Scope scope(context2);
19886 object2 = Object::New(isolate);
19887 func2 = tmpl->GetFunction();
19890 Local<Object> instance1;
19891 Local<Object> instance2;
19894 Context::Scope scope(context3);
19895 instance1 = func1->NewInstance();
19896 instance2 = func2->NewInstance();
19899 CHECK(object1->CreationContext() == context1);
19900 CheckContextId(object1, 1);
19901 CHECK(func1->CreationContext() == context1);
19902 CheckContextId(func1, 1);
19903 CHECK(instance1->CreationContext() == context1);
19904 CheckContextId(instance1, 1);
19905 CHECK(object2->CreationContext() == context2);
19906 CheckContextId(object2, 2);
19907 CHECK(func2->CreationContext() == context2);
19908 CheckContextId(func2, 2);
19909 CHECK(instance2->CreationContext() == context2);
19910 CheckContextId(instance2, 2);
19913 Context::Scope scope(context1);
19914 CHECK(object1->CreationContext() == context1);
19915 CheckContextId(object1, 1);
19916 CHECK(func1->CreationContext() == context1);
19917 CheckContextId(func1, 1);
19918 CHECK(instance1->CreationContext() == context1);
19919 CheckContextId(instance1, 1);
19920 CHECK(object2->CreationContext() == context2);
19921 CheckContextId(object2, 2);
19922 CHECK(func2->CreationContext() == context2);
19923 CheckContextId(func2, 2);
19924 CHECK(instance2->CreationContext() == context2);
19925 CheckContextId(instance2, 2);
19929 Context::Scope scope(context2);
19930 CHECK(object1->CreationContext() == context1);
19931 CheckContextId(object1, 1);
19932 CHECK(func1->CreationContext() == context1);
19933 CheckContextId(func1, 1);
19934 CHECK(instance1->CreationContext() == context1);
19935 CheckContextId(instance1, 1);
19936 CHECK(object2->CreationContext() == context2);
19937 CheckContextId(object2, 2);
19938 CHECK(func2->CreationContext() == context2);
19939 CheckContextId(func2, 2);
19940 CHECK(instance2->CreationContext() == context2);
19941 CheckContextId(instance2, 2);
19946 THREADED_TEST(CreationContextOfJsFunction) {
19947 HandleScope handle_scope(CcTest::isolate());
19948 Handle<Context> context = Context::New(CcTest::isolate());
19949 InstallContextId(context, 1);
19951 Local<Object> function;
19953 Context::Scope scope(context);
19954 function = CompileRun("function foo() {}; foo").As<Object>();
19957 CHECK(function->CreationContext() == context);
19958 CheckContextId(function, 1);
19962 void HasOwnPropertyIndexedPropertyGetter(
19964 const v8::PropertyCallbackInfo<v8::Value>& info) {
19965 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19969 void HasOwnPropertyNamedPropertyGetter(
19970 Local<String> property,
19971 const v8::PropertyCallbackInfo<v8::Value>& info) {
19972 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19976 void HasOwnPropertyIndexedPropertyQuery(
19977 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19978 if (index == 42) info.GetReturnValue().Set(1);
19982 void HasOwnPropertyNamedPropertyQuery(
19983 Local<String> property,
19984 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19985 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19989 void HasOwnPropertyNamedPropertyQuery2(
19990 Local<String> property,
19991 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19992 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19996 void HasOwnPropertyAccessorGetter(
19997 Local<String> property,
19998 const v8::PropertyCallbackInfo<v8::Value>& info) {
19999 info.GetReturnValue().Set(v8_str("yes"));
20003 TEST(HasOwnProperty) {
20005 v8::Isolate* isolate = env->GetIsolate();
20006 v8::HandleScope scope(isolate);
20007 { // Check normal properties and defined getters.
20008 Handle<Value> value = CompileRun(
20011 " this.__defineGetter__('baz', function() { return 1; });"
20013 "function Bar() { "
20015 " this.__defineGetter__('bla', function() { return 2; });"
20017 "Bar.prototype = new Foo();"
20019 CHECK(value->IsObject());
20020 Handle<Object> object = value->ToObject();
20021 CHECK(object->Has(v8_str("foo")));
20022 CHECK(!object->HasOwnProperty(v8_str("foo")));
20023 CHECK(object->HasOwnProperty(v8_str("bar")));
20024 CHECK(object->Has(v8_str("baz")));
20025 CHECK(!object->HasOwnProperty(v8_str("baz")));
20026 CHECK(object->HasOwnProperty(v8_str("bla")));
20028 { // Check named getter interceptors.
20029 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20030 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20031 Handle<Object> instance = templ->NewInstance();
20032 CHECK(!instance->HasOwnProperty(v8_str("42")));
20033 CHECK(instance->HasOwnProperty(v8_str("foo")));
20034 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20036 { // Check indexed getter interceptors.
20037 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20038 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20039 Handle<Object> instance = templ->NewInstance();
20040 CHECK(instance->HasOwnProperty(v8_str("42")));
20041 CHECK(!instance->HasOwnProperty(v8_str("43")));
20042 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20044 { // Check named query interceptors.
20045 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20046 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20047 Handle<Object> instance = templ->NewInstance();
20048 CHECK(instance->HasOwnProperty(v8_str("foo")));
20049 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20051 { // Check indexed query interceptors.
20052 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20053 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20054 Handle<Object> instance = templ->NewInstance();
20055 CHECK(instance->HasOwnProperty(v8_str("42")));
20056 CHECK(!instance->HasOwnProperty(v8_str("41")));
20058 { // Check callbacks.
20059 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20060 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20061 Handle<Object> instance = templ->NewInstance();
20062 CHECK(instance->HasOwnProperty(v8_str("foo")));
20063 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20065 { // Check that query wins on disagreement.
20066 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20067 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20069 HasOwnPropertyNamedPropertyQuery2);
20070 Handle<Object> instance = templ->NewInstance();
20071 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20072 CHECK(instance->HasOwnProperty(v8_str("bar")));
20077 TEST(IndexedInterceptorWithStringProto) {
20078 v8::Isolate* isolate = CcTest::isolate();
20079 v8::HandleScope scope(isolate);
20080 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20081 templ->SetIndexedPropertyHandler(NULL,
20083 HasOwnPropertyIndexedPropertyQuery);
20084 LocalContext context;
20085 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20086 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20087 // These should be intercepted.
20088 CHECK(CompileRun("42 in obj")->BooleanValue());
20089 CHECK(CompileRun("'42' in obj")->BooleanValue());
20090 // These should fall through to the String prototype.
20091 CHECK(CompileRun("0 in obj")->BooleanValue());
20092 CHECK(CompileRun("'0' in obj")->BooleanValue());
20093 // And these should both fail.
20094 CHECK(!CompileRun("32 in obj")->BooleanValue());
20095 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20099 void CheckCodeGenerationAllowed() {
20100 Handle<Value> result = CompileRun("eval('42')");
20101 CHECK_EQ(42, result->Int32Value());
20102 result = CompileRun("(function(e) { return e('42'); })(eval)");
20103 CHECK_EQ(42, result->Int32Value());
20104 result = CompileRun("var f = new Function('return 42'); f()");
20105 CHECK_EQ(42, result->Int32Value());
20109 void CheckCodeGenerationDisallowed() {
20110 TryCatch try_catch;
20112 Handle<Value> result = CompileRun("eval('42')");
20113 CHECK(result.IsEmpty());
20114 CHECK(try_catch.HasCaught());
20117 result = CompileRun("(function(e) { return e('42'); })(eval)");
20118 CHECK(result.IsEmpty());
20119 CHECK(try_catch.HasCaught());
20122 result = CompileRun("var f = new Function('return 42'); f()");
20123 CHECK(result.IsEmpty());
20124 CHECK(try_catch.HasCaught());
20128 bool CodeGenerationAllowed(Local<Context> context) {
20129 ApiTestFuzzer::Fuzz();
20134 bool CodeGenerationDisallowed(Local<Context> context) {
20135 ApiTestFuzzer::Fuzz();
20140 THREADED_TEST(AllowCodeGenFromStrings) {
20141 LocalContext context;
20142 v8::HandleScope scope(context->GetIsolate());
20144 // eval and the Function constructor allowed by default.
20145 CHECK(context->IsCodeGenerationFromStringsAllowed());
20146 CheckCodeGenerationAllowed();
20148 // Disallow eval and the Function constructor.
20149 context->AllowCodeGenerationFromStrings(false);
20150 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20151 CheckCodeGenerationDisallowed();
20154 context->AllowCodeGenerationFromStrings(true);
20155 CheckCodeGenerationAllowed();
20157 // Disallow but setting a global callback that will allow the calls.
20158 context->AllowCodeGenerationFromStrings(false);
20159 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20160 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20161 CheckCodeGenerationAllowed();
20163 // Set a callback that disallows the code generation.
20164 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20165 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20166 CheckCodeGenerationDisallowed();
20170 TEST(SetErrorMessageForCodeGenFromStrings) {
20171 LocalContext context;
20172 v8::HandleScope scope(context->GetIsolate());
20173 TryCatch try_catch;
20175 Handle<String> message = v8_str("Message") ;
20176 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20177 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20178 context->AllowCodeGenerationFromStrings(false);
20179 context->SetErrorMessageForCodeGenerationFromStrings(message);
20180 Handle<Value> result = CompileRun("eval('42')");
20181 CHECK(result.IsEmpty());
20182 CHECK(try_catch.HasCaught());
20183 Handle<String> actual_message = try_catch.Message()->Get();
20184 CHECK(expected_message->Equals(actual_message));
20188 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20192 THREADED_TEST(CallAPIFunctionOnNonObject) {
20193 LocalContext context;
20194 v8::Isolate* isolate = context->GetIsolate();
20195 v8::HandleScope scope(isolate);
20196 Handle<FunctionTemplate> templ =
20197 v8::FunctionTemplate::New(isolate, NonObjectThis);
20198 Handle<Function> function = templ->GetFunction();
20199 context->Global()->Set(v8_str("f"), function);
20200 TryCatch try_catch;
20201 CompileRun("f.call(2)");
20205 // Regression test for issue 1470.
20206 THREADED_TEST(ReadOnlyIndexedProperties) {
20207 v8::Isolate* isolate = CcTest::isolate();
20208 v8::HandleScope scope(isolate);
20209 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20211 LocalContext context;
20212 Local<v8::Object> obj = templ->NewInstance();
20213 context->Global()->Set(v8_str("obj"), obj);
20214 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20215 obj->Set(v8_str("1"), v8_str("foobar"));
20216 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20217 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20218 obj->Set(v8_num(2), v8_str("foobar"));
20219 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20221 // Test non-smi case.
20222 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20223 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20224 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20228 THREADED_TEST(Regress1516) {
20229 LocalContext context;
20230 v8::HandleScope scope(context->GetIsolate());
20232 { v8::HandleScope temp_scope(context->GetIsolate());
20233 CompileRun("({'a': 0})");
20237 { i::MapCache* map_cache =
20238 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20239 elements = map_cache->NumberOfElements();
20240 CHECK_LE(1, elements);
20243 CcTest::heap()->CollectAllGarbage(
20244 i::Heap::kAbortIncrementalMarkingMask);
20245 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20246 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20247 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20248 CHECK_GT(elements, map_cache->NumberOfElements());
20254 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20256 v8::AccessType type,
20257 Local<Value> data) {
20258 // Only block read access to __proto__.
20259 if (type == v8::ACCESS_GET &&
20260 name->IsString() &&
20261 name->ToString()->Length() == 9 &&
20262 name->ToString()->Utf8Length() == 9) {
20264 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20265 return strncmp(buffer, "__proto__", 9) != 0;
20272 THREADED_TEST(Regress93759) {
20273 v8::Isolate* isolate = CcTest::isolate();
20274 HandleScope scope(isolate);
20276 // Template for object with security check.
20277 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20278 // We don't do indexing, so any callback can be used for that.
20279 no_proto_template->SetAccessCheckCallbacks(
20280 BlockProtoNamedSecurityTestCallback,
20281 IndexedSecurityTestCallback);
20283 // Templates for objects with hidden prototypes and possibly security check.
20284 Local<FunctionTemplate> hidden_proto_template =
20285 v8::FunctionTemplate::New(isolate);
20286 hidden_proto_template->SetHiddenPrototype(true);
20288 Local<FunctionTemplate> protected_hidden_proto_template =
20289 v8::FunctionTemplate::New(isolate);
20290 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20291 BlockProtoNamedSecurityTestCallback,
20292 IndexedSecurityTestCallback);
20293 protected_hidden_proto_template->SetHiddenPrototype(true);
20295 // Context for "foreign" objects used in test.
20296 Local<Context> context = v8::Context::New(isolate);
20299 // Plain object, no security check.
20300 Local<Object> simple_object = Object::New(isolate);
20302 // Object with explicit security check.
20303 Local<Object> protected_object =
20304 no_proto_template->NewInstance();
20306 // JSGlobalProxy object, always have security check.
20307 Local<Object> proxy_object =
20310 // Global object, the prototype of proxy_object. No security checks.
20311 Local<Object> global_object =
20312 proxy_object->GetPrototype()->ToObject();
20314 // Hidden prototype without security check.
20315 Local<Object> hidden_prototype =
20316 hidden_proto_template->GetFunction()->NewInstance();
20317 Local<Object> object_with_hidden =
20318 Object::New(isolate);
20319 object_with_hidden->SetPrototype(hidden_prototype);
20321 // Hidden prototype with security check on the hidden prototype.
20322 Local<Object> protected_hidden_prototype =
20323 protected_hidden_proto_template->GetFunction()->NewInstance();
20324 Local<Object> object_with_protected_hidden =
20325 Object::New(isolate);
20326 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20330 // Template for object for second context. Values to test are put on it as
20332 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20333 global_template->Set(v8_str("simple"), simple_object);
20334 global_template->Set(v8_str("protected"), protected_object);
20335 global_template->Set(v8_str("global"), global_object);
20336 global_template->Set(v8_str("proxy"), proxy_object);
20337 global_template->Set(v8_str("hidden"), object_with_hidden);
20338 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20340 LocalContext context2(NULL, global_template);
20342 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20343 CHECK(result1->Equals(simple_object->GetPrototype()));
20345 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20346 CHECK(result2->Equals(Undefined(isolate)));
20348 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20349 CHECK(result3->Equals(global_object->GetPrototype()));
20351 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20352 CHECK(result4->Equals(Undefined(isolate)));
20354 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20355 CHECK(result5->Equals(
20356 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20358 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20359 CHECK(result6->Equals(Undefined(isolate)));
20363 THREADED_TEST(Regress125988) {
20364 v8::HandleScope scope(CcTest::isolate());
20365 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20366 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20368 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20369 CompileRun("var a = new Object();"
20370 "var b = new Intercept();"
20371 "var c = new Object();"
20375 "for (var i = 0; i < 3; i++) c.x;");
20376 ExpectBoolean("c.hasOwnProperty('x')", false);
20377 ExpectInt32("c.x", 23);
20378 CompileRun("a.y = 42;"
20379 "for (var i = 0; i < 3; i++) c.x;");
20380 ExpectBoolean("c.hasOwnProperty('x')", false);
20381 ExpectInt32("c.x", 23);
20382 ExpectBoolean("c.hasOwnProperty('y')", false);
20383 ExpectInt32("c.y", 42);
20387 static void TestReceiver(Local<Value> expected_result,
20388 Local<Value> expected_receiver,
20389 const char* code) {
20390 Local<Value> result = CompileRun(code);
20391 CHECK(result->IsObject());
20392 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20393 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20397 THREADED_TEST(ForeignFunctionReceiver) {
20398 v8::Isolate* isolate = CcTest::isolate();
20399 HandleScope scope(isolate);
20401 // Create two contexts with different "id" properties ('i' and 'o').
20402 // Call a function both from its own context and from a the foreign
20403 // context, and see what "this" is bound to (returning both "this"
20404 // and "this.id" for comparison).
20406 Local<Context> foreign_context = v8::Context::New(isolate);
20407 foreign_context->Enter();
20408 Local<Value> foreign_function =
20409 CompileRun("function func() { return { 0: this.id, "
20411 " toString: function() { "
20418 CHECK(foreign_function->IsFunction());
20419 foreign_context->Exit();
20421 LocalContext context;
20423 Local<String> password = v8_str("Password");
20424 // Don't get hit by security checks when accessing foreign_context's
20425 // global receiver (aka. global proxy).
20426 context->SetSecurityToken(password);
20427 foreign_context->SetSecurityToken(password);
20429 Local<String> i = v8_str("i");
20430 Local<String> o = v8_str("o");
20431 Local<String> id = v8_str("id");
20433 CompileRun("function ownfunc() { return { 0: this.id, "
20435 " toString: function() { "
20442 context->Global()->Set(v8_str("func"), foreign_function);
20444 // Sanity check the contexts.
20445 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20446 CHECK(o->Equals(context->Global()->Get(id)));
20448 // Checking local function's receiver.
20449 // Calling function using its call/apply methods.
20450 TestReceiver(o, context->Global(), "ownfunc.call()");
20451 TestReceiver(o, context->Global(), "ownfunc.apply()");
20452 // Making calls through built-in functions.
20453 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20454 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20455 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20456 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20457 // Calling with environment record as base.
20458 TestReceiver(o, context->Global(), "ownfunc()");
20459 // Calling with no base.
20460 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20462 // Checking foreign function return value.
20463 // Calling function using its call/apply methods.
20464 TestReceiver(i, foreign_context->Global(), "func.call()");
20465 TestReceiver(i, foreign_context->Global(), "func.apply()");
20466 // Calling function using another context's call/apply methods.
20467 TestReceiver(i, foreign_context->Global(),
20468 "Function.prototype.call.call(func)");
20469 TestReceiver(i, foreign_context->Global(),
20470 "Function.prototype.call.apply(func)");
20471 TestReceiver(i, foreign_context->Global(),
20472 "Function.prototype.apply.call(func)");
20473 TestReceiver(i, foreign_context->Global(),
20474 "Function.prototype.apply.apply(func)");
20475 // Making calls through built-in functions.
20476 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20477 // ToString(func()) is func()[0], i.e., the returned this.id.
20478 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20479 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20480 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20482 // Calling with environment record as base.
20483 TestReceiver(i, foreign_context->Global(), "func()");
20484 // Calling with no base.
20485 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20489 uint8_t callback_fired = 0;
20492 void CallCompletedCallback1() {
20493 i::OS::Print("Firing callback 1.\n");
20494 callback_fired ^= 1; // Toggle first bit.
20498 void CallCompletedCallback2() {
20499 i::OS::Print("Firing callback 2.\n");
20500 callback_fired ^= 2; // Toggle second bit.
20504 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20505 int32_t level = args[0]->Int32Value();
20508 i::OS::Print("Entering recursion level %d.\n", level);
20510 i::Vector<char> script_vector(script, sizeof(script));
20511 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20512 CompileRun(script_vector.start());
20513 i::OS::Print("Leaving recursion level %d.\n", level);
20514 CHECK_EQ(0, callback_fired);
20516 i::OS::Print("Recursion ends.\n");
20517 CHECK_EQ(0, callback_fired);
20522 TEST(CallCompletedCallback) {
20524 v8::HandleScope scope(env->GetIsolate());
20525 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20526 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20527 env->Global()->Set(v8_str("recursion"),
20528 recursive_runtime->GetFunction());
20529 // Adding the same callback a second time has no effect.
20530 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20531 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20532 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20533 i::OS::Print("--- Script (1) ---\n");
20534 Local<Script> script = v8::Script::Compile(
20535 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20537 CHECK_EQ(3, callback_fired);
20539 i::OS::Print("\n--- Script (2) ---\n");
20540 callback_fired = 0;
20541 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20543 CHECK_EQ(2, callback_fired);
20545 i::OS::Print("\n--- Function ---\n");
20546 callback_fired = 0;
20547 Local<Function> recursive_function =
20548 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20549 v8::Handle<Value> args[] = { v8_num(0) };
20550 recursive_function->Call(env->Global(), 1, args);
20551 CHECK_EQ(2, callback_fired);
20555 void CallCompletedCallbackNoException() {
20556 v8::HandleScope scope(CcTest::isolate());
20557 CompileRun("1+1;");
20561 void CallCompletedCallbackException() {
20562 v8::HandleScope scope(CcTest::isolate());
20563 CompileRun("throw 'second exception';");
20567 TEST(CallCompletedCallbackOneException) {
20569 v8::HandleScope scope(env->GetIsolate());
20570 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20571 CompileRun("throw 'exception';");
20575 TEST(CallCompletedCallbackTwoExceptions) {
20577 v8::HandleScope scope(env->GetIsolate());
20578 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20579 CompileRun("throw 'first exception';");
20583 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20584 v8::HandleScope scope(info.GetIsolate());
20585 CompileRun("ext1Calls++;");
20589 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20590 v8::HandleScope scope(info.GetIsolate());
20591 CompileRun("ext2Calls++;");
20595 TEST(EnqueueMicrotask) {
20597 v8::HandleScope scope(env->GetIsolate());
20599 "var ext1Calls = 0;"
20600 "var ext2Calls = 0;");
20601 CompileRun("1+1;");
20602 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20603 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20605 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20606 Function::New(env->GetIsolate(), MicrotaskOne));
20607 CompileRun("1+1;");
20608 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20609 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20611 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20612 Function::New(env->GetIsolate(), MicrotaskOne));
20613 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20614 Function::New(env->GetIsolate(), MicrotaskTwo));
20615 CompileRun("1+1;");
20616 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20617 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20619 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20620 Function::New(env->GetIsolate(), MicrotaskTwo));
20621 CompileRun("1+1;");
20622 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20623 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20625 CompileRun("1+1;");
20626 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20627 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20631 TEST(SetAutorunMicrotasks) {
20633 v8::HandleScope scope(env->GetIsolate());
20635 "var ext1Calls = 0;"
20636 "var ext2Calls = 0;");
20637 CompileRun("1+1;");
20638 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20639 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20641 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20642 Function::New(env->GetIsolate(), MicrotaskOne));
20643 CompileRun("1+1;");
20644 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20645 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20647 V8::SetAutorunMicrotasks(env->GetIsolate(), false);
20648 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20649 Function::New(env->GetIsolate(), MicrotaskOne));
20650 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20651 Function::New(env->GetIsolate(), MicrotaskTwo));
20652 CompileRun("1+1;");
20653 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20654 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20656 V8::RunMicrotasks(env->GetIsolate());
20657 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20658 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20660 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20661 Function::New(env->GetIsolate(), MicrotaskTwo));
20662 CompileRun("1+1;");
20663 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20664 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20666 V8::RunMicrotasks(env->GetIsolate());
20667 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20668 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20670 V8::SetAutorunMicrotasks(env->GetIsolate(), true);
20671 v8::V8::EnqueueMicrotask(env->GetIsolate(),
20672 Function::New(env->GetIsolate(), MicrotaskTwo));
20673 CompileRun("1+1;");
20674 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20675 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20679 static int probes_counter = 0;
20680 static int misses_counter = 0;
20681 static int updates_counter = 0;
20684 static int* LookupCounter(const char* name) {
20685 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20686 return &probes_counter;
20687 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20688 return &misses_counter;
20689 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20690 return &updates_counter;
20696 static const char* kMegamorphicTestProgram =
20697 "function ClassA() { };"
20698 "function ClassB() { };"
20699 "ClassA.prototype.foo = function() { };"
20700 "ClassB.prototype.foo = function() { };"
20701 "function fooify(obj) { obj.foo(); };"
20702 "var a = new ClassA();"
20703 "var b = new ClassB();"
20704 "for (var i = 0; i < 10000; i++) {"
20710 static void StubCacheHelper(bool primary) {
20711 V8::SetCounterFunction(LookupCounter);
20712 USE(kMegamorphicTestProgram);
20714 i::FLAG_native_code_counters = true;
20716 i::FLAG_test_primary_stub_cache = true;
20718 i::FLAG_test_secondary_stub_cache = true;
20720 i::FLAG_crankshaft = false;
20722 v8::HandleScope scope(env->GetIsolate());
20723 int initial_probes = probes_counter;
20724 int initial_misses = misses_counter;
20725 int initial_updates = updates_counter;
20726 CompileRun(kMegamorphicTestProgram);
20727 int probes = probes_counter - initial_probes;
20728 int misses = misses_counter - initial_misses;
20729 int updates = updates_counter - initial_updates;
20730 CHECK_LT(updates, 10);
20731 CHECK_LT(misses, 10);
20732 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20733 // before megamorphism. The number of probes will only work once we teach the
20734 // serializer to embed references to counters in the stubs, given that the
20735 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20736 CHECK_GE(probes, 0);
20741 TEST(SecondaryStubCache) {
20742 StubCacheHelper(true);
20746 TEST(PrimaryStubCache) {
20747 StubCacheHelper(false);
20751 static int cow_arrays_created_runtime = 0;
20754 static int* LookupCounterCOWArrays(const char* name) {
20755 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20756 return &cow_arrays_created_runtime;
20762 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20763 V8::SetCounterFunction(LookupCounterCOWArrays);
20765 i::FLAG_native_code_counters = true;
20767 v8::HandleScope scope(env->GetIsolate());
20768 int initial_cow_arrays = cow_arrays_created_runtime;
20769 CompileRun("var o = [1, 2, 3];");
20770 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20771 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20772 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20773 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20774 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20779 TEST(StaticGetters) {
20780 LocalContext context;
20781 i::Factory* factory = CcTest::i_isolate()->factory();
20782 v8::Isolate* isolate = CcTest::isolate();
20783 v8::HandleScope scope(isolate);
20784 i::Handle<i::Object> undefined_value = factory->undefined_value();
20785 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20786 i::Handle<i::Object> null_value = factory->null_value();
20787 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20788 i::Handle<i::Object> true_value = factory->true_value();
20789 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20790 i::Handle<i::Object> false_value = factory->false_value();
20791 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20795 UNINITIALIZED_TEST(IsolateEmbedderData) {
20796 CcTest::DisableAutomaticDispose();
20797 v8::Isolate* isolate = v8::Isolate::New();
20799 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20800 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20801 CHECK_EQ(NULL, isolate->GetData(slot));
20802 CHECK_EQ(NULL, i_isolate->GetData(slot));
20804 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20805 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20806 isolate->SetData(slot, data);
20808 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20809 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20810 CHECK_EQ(data, isolate->GetData(slot));
20811 CHECK_EQ(data, i_isolate->GetData(slot));
20813 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20814 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20815 isolate->SetData(slot, data);
20817 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20818 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20819 CHECK_EQ(data, isolate->GetData(slot));
20820 CHECK_EQ(data, i_isolate->GetData(slot));
20823 isolate->Dispose();
20827 TEST(StringEmpty) {
20828 LocalContext context;
20829 i::Factory* factory = CcTest::i_isolate()->factory();
20830 v8::Isolate* isolate = CcTest::isolate();
20831 v8::HandleScope scope(isolate);
20832 i::Handle<i::Object> empty_string = factory->empty_string();
20833 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20837 static int instance_checked_getter_count = 0;
20838 static void InstanceCheckedGetter(
20839 Local<String> name,
20840 const v8::PropertyCallbackInfo<v8::Value>& info) {
20841 CHECK_EQ(name, v8_str("foo"));
20842 instance_checked_getter_count++;
20843 info.GetReturnValue().Set(v8_num(11));
20847 static int instance_checked_setter_count = 0;
20848 static void InstanceCheckedSetter(Local<String> name,
20849 Local<Value> value,
20850 const v8::PropertyCallbackInfo<void>& info) {
20851 CHECK_EQ(name, v8_str("foo"));
20852 CHECK_EQ(value, v8_num(23));
20853 instance_checked_setter_count++;
20857 static void CheckInstanceCheckedResult(int getters,
20859 bool expects_callbacks,
20860 TryCatch* try_catch) {
20861 if (expects_callbacks) {
20862 CHECK(!try_catch->HasCaught());
20863 CHECK_EQ(getters, instance_checked_getter_count);
20864 CHECK_EQ(setters, instance_checked_setter_count);
20866 CHECK(try_catch->HasCaught());
20867 CHECK_EQ(0, instance_checked_getter_count);
20868 CHECK_EQ(0, instance_checked_setter_count);
20870 try_catch->Reset();
20874 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20875 instance_checked_getter_count = 0;
20876 instance_checked_setter_count = 0;
20877 TryCatch try_catch;
20879 // Test path through generic runtime code.
20880 CompileRun("obj.foo");
20881 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20882 CompileRun("obj.foo = 23");
20883 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20885 // Test path through generated LoadIC and StoredIC.
20886 CompileRun("function test_get(o) { o.foo; }"
20888 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20889 CompileRun("test_get(obj);");
20890 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20891 CompileRun("test_get(obj);");
20892 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20893 CompileRun("function test_set(o) { o.foo = 23; }"
20895 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20896 CompileRun("test_set(obj);");
20897 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20898 CompileRun("test_set(obj);");
20899 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20901 // Test path through optimized code.
20902 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20904 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20905 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20907 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20909 // Cleanup so that closures start out fresh in next check.
20910 CompileRun("%DeoptimizeFunction(test_get);"
20911 "%ClearFunctionTypeFeedback(test_get);"
20912 "%DeoptimizeFunction(test_set);"
20913 "%ClearFunctionTypeFeedback(test_set);");
20917 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20918 v8::internal::FLAG_allow_natives_syntax = true;
20919 LocalContext context;
20920 v8::HandleScope scope(context->GetIsolate());
20922 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20923 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20924 inst->SetAccessor(v8_str("foo"),
20925 InstanceCheckedGetter, InstanceCheckedSetter,
20929 v8::AccessorSignature::New(context->GetIsolate(), templ));
20930 context->Global()->Set(v8_str("f"), templ->GetFunction());
20932 printf("Testing positive ...\n");
20933 CompileRun("var obj = new f();");
20934 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20935 CheckInstanceCheckedAccessors(true);
20937 printf("Testing negative ...\n");
20938 CompileRun("var obj = {};"
20939 "obj.__proto__ = new f();");
20940 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20941 CheckInstanceCheckedAccessors(false);
20945 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20946 v8::internal::FLAG_allow_natives_syntax = true;
20947 LocalContext context;
20948 v8::HandleScope scope(context->GetIsolate());
20950 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20951 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20952 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20953 inst->SetAccessor(v8_str("foo"),
20954 InstanceCheckedGetter, InstanceCheckedSetter,
20958 v8::AccessorSignature::New(context->GetIsolate(), templ));
20959 context->Global()->Set(v8_str("f"), templ->GetFunction());
20961 printf("Testing positive ...\n");
20962 CompileRun("var obj = new f();");
20963 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20964 CheckInstanceCheckedAccessors(true);
20966 printf("Testing negative ...\n");
20967 CompileRun("var obj = {};"
20968 "obj.__proto__ = new f();");
20969 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20970 CheckInstanceCheckedAccessors(false);
20974 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20975 v8::internal::FLAG_allow_natives_syntax = true;
20976 LocalContext context;
20977 v8::HandleScope scope(context->GetIsolate());
20979 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20980 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20981 proto->SetAccessor(v8_str("foo"),
20982 InstanceCheckedGetter, InstanceCheckedSetter,
20986 v8::AccessorSignature::New(context->GetIsolate(), templ));
20987 context->Global()->Set(v8_str("f"), templ->GetFunction());
20989 printf("Testing positive ...\n");
20990 CompileRun("var obj = new f();");
20991 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20992 CheckInstanceCheckedAccessors(true);
20994 printf("Testing negative ...\n");
20995 CompileRun("var obj = {};"
20996 "obj.__proto__ = new f();");
20997 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20998 CheckInstanceCheckedAccessors(false);
21000 printf("Testing positive with modified prototype chain ...\n");
21001 CompileRun("var obj = new f();"
21003 "pro.__proto__ = obj.__proto__;"
21004 "obj.__proto__ = pro;");
21005 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21006 CheckInstanceCheckedAccessors(true);
21010 TEST(TryFinallyMessage) {
21011 LocalContext context;
21012 v8::HandleScope scope(context->GetIsolate());
21014 // Test that the original error message is not lost if there is a
21015 // recursive call into Javascript is done in the finally block, e.g. to
21016 // initialize an IC. (crbug.com/129171)
21017 TryCatch try_catch;
21018 const char* trigger_ic =
21020 " throw new Error('test'); \n"
21023 " x++; \n" // Trigger an IC initialization here.
21025 CompileRun(trigger_ic);
21026 CHECK(try_catch.HasCaught());
21027 Local<Message> message = try_catch.Message();
21028 CHECK(!message.IsEmpty());
21029 CHECK_EQ(2, message->GetLineNumber());
21033 // Test that the original exception message is indeed overwritten if
21034 // a new error is thrown in the finally block.
21035 TryCatch try_catch;
21036 const char* throw_again =
21038 " throw new Error('test'); \n"
21042 " throw new Error('again'); \n" // This is the new uncaught error.
21044 CompileRun(throw_again);
21045 CHECK(try_catch.HasCaught());
21046 Local<Message> message = try_catch.Message();
21047 CHECK(!message.IsEmpty());
21048 CHECK_EQ(6, message->GetLineNumber());
21053 static void Helper137002(bool do_store,
21055 bool remove_accessor,
21056 bool interceptor) {
21057 LocalContext context;
21058 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21060 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21062 templ->SetAccessor(v8_str("foo"),
21063 GetterWhichReturns42,
21064 SetterWhichSetsYOnThisTo23);
21066 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21068 // Turn monomorphic on slow object with native accessor, then turn
21069 // polymorphic, finally optimize to create negative lookup and fail.
21070 CompileRun(do_store ?
21071 "function f(x) { x.foo = void 0; }" :
21072 "function f(x) { return x.foo; }");
21073 CompileRun("obj.y = void 0;");
21074 if (!interceptor) {
21075 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21077 CompileRun("obj.__proto__ = null;"
21078 "f(obj); f(obj); f(obj);");
21080 CompileRun("f({});");
21082 CompileRun("obj.y = void 0;"
21083 "%OptimizeFunctionOnNextCall(f);");
21084 if (remove_accessor) {
21085 CompileRun("delete obj.foo;");
21087 CompileRun("var result = f(obj);");
21089 CompileRun("result = obj.y;");
21091 if (remove_accessor && !interceptor) {
21092 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21094 CHECK_EQ(do_store ? 23 : 42,
21095 context->Global()->Get(v8_str("result"))->Int32Value());
21100 THREADED_TEST(Regress137002a) {
21101 i::FLAG_allow_natives_syntax = true;
21102 i::FLAG_compilation_cache = false;
21103 v8::HandleScope scope(CcTest::isolate());
21104 for (int i = 0; i < 16; i++) {
21105 Helper137002(i & 8, i & 4, i & 2, i & 1);
21110 THREADED_TEST(Regress137002b) {
21111 i::FLAG_allow_natives_syntax = true;
21112 LocalContext context;
21113 v8::Isolate* isolate = context->GetIsolate();
21114 v8::HandleScope scope(isolate);
21115 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21116 templ->SetAccessor(v8_str("foo"),
21117 GetterWhichReturns42,
21118 SetterWhichSetsYOnThisTo23);
21119 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21121 // Turn monomorphic on slow object with native accessor, then just
21122 // delete the property and fail.
21123 CompileRun("function load(x) { return x.foo; }"
21124 "function store(x) { x.foo = void 0; }"
21125 "function keyed_load(x, key) { return x[key]; }"
21126 // Second version of function has a different source (add void 0)
21127 // so that it does not share code with the first version. This
21128 // ensures that the ICs are monomorphic.
21129 "function load2(x) { void 0; return x.foo; }"
21130 "function store2(x) { void 0; x.foo = void 0; }"
21131 "function keyed_load2(x, key) { void 0; return x[key]; }"
21134 "obj.__proto__ = null;"
21136 "subobj.y = void 0;"
21137 "subobj.__proto__ = obj;"
21138 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21140 // Make the ICs monomorphic.
21141 "load(obj); load(obj);"
21142 "load2(subobj); load2(subobj);"
21143 "store(obj); store(obj);"
21144 "store2(subobj); store2(subobj);"
21145 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21146 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21148 // Actually test the shiny new ICs and better not crash. This
21149 // serves as a regression test for issue 142088 as well.
21154 "keyed_load(obj, 'foo');"
21155 "keyed_load2(subobj, 'foo');"
21157 // Delete the accessor. It better not be called any more now.
21160 "subobj.y = void 0;"
21162 "var load_result = load(obj);"
21163 "var load_result2 = load2(subobj);"
21164 "var keyed_load_result = keyed_load(obj, 'foo');"
21165 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21168 "var y_from_obj = obj.y;"
21169 "var y_from_subobj = subobj.y;");
21170 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21171 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21172 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21173 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21174 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21175 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21179 THREADED_TEST(Regress142088) {
21180 i::FLAG_allow_natives_syntax = true;
21181 LocalContext context;
21182 v8::Isolate* isolate = context->GetIsolate();
21183 v8::HandleScope scope(isolate);
21184 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21185 templ->SetAccessor(v8_str("foo"),
21186 GetterWhichReturns42,
21187 SetterWhichSetsYOnThisTo23);
21188 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21190 CompileRun("function load(x) { return x.foo; }"
21191 "var o = Object.create(obj);"
21192 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21193 "load(o); load(o); load(o); load(o);");
21197 THREADED_TEST(Regress137496) {
21198 i::FLAG_expose_gc = true;
21199 LocalContext context;
21200 v8::HandleScope scope(context->GetIsolate());
21202 // Compile a try-finally clause where the finally block causes a GC
21203 // while there still is a message pending for external reporting.
21204 TryCatch try_catch;
21205 try_catch.SetVerbose(true);
21206 CompileRun("try { throw new Error(); } finally { gc(); }");
21207 CHECK(try_catch.HasCaught());
21211 THREADED_TEST(Regress149912) {
21212 LocalContext context;
21213 v8::HandleScope scope(context->GetIsolate());
21214 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21215 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21216 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21217 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21221 THREADED_TEST(Regress157124) {
21222 LocalContext context;
21223 v8::Isolate* isolate = context->GetIsolate();
21224 v8::HandleScope scope(isolate);
21225 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21226 Local<Object> obj = templ->NewInstance();
21227 obj->GetIdentityHash();
21228 obj->DeleteHiddenValue(v8_str("Bug"));
21232 THREADED_TEST(Regress2535) {
21233 i::FLAG_harmony_collections = true;
21234 LocalContext context;
21235 v8::HandleScope scope(context->GetIsolate());
21236 Local<Value> set_value = CompileRun("new Set();");
21237 Local<Object> set_object(Local<Object>::Cast(set_value));
21238 CHECK_EQ(0, set_object->InternalFieldCount());
21239 Local<Value> map_value = CompileRun("new Map();");
21240 Local<Object> map_object(Local<Object>::Cast(map_value));
21241 CHECK_EQ(0, map_object->InternalFieldCount());
21245 THREADED_TEST(Regress2746) {
21246 LocalContext context;
21247 v8::Isolate* isolate = context->GetIsolate();
21248 v8::HandleScope scope(isolate);
21249 Local<Object> obj = Object::New(isolate);
21250 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21251 obj->SetHiddenValue(key, v8::Undefined(isolate));
21252 Local<Value> value = obj->GetHiddenValue(key);
21253 CHECK(!value.IsEmpty());
21254 CHECK(value->IsUndefined());
21258 THREADED_TEST(Regress260106) {
21259 LocalContext context;
21260 v8::Isolate* isolate = context->GetIsolate();
21261 v8::HandleScope scope(isolate);
21262 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21264 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21265 Local<Function> function = templ->GetFunction();
21266 CHECK(!function.IsEmpty());
21267 CHECK(function->IsFunction());
21271 THREADED_TEST(JSONParseObject) {
21272 LocalContext context;
21273 HandleScope scope(context->GetIsolate());
21274 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21275 Handle<Object> global = context->Global();
21276 global->Set(v8_str("obj"), obj);
21277 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21281 THREADED_TEST(JSONParseNumber) {
21282 LocalContext context;
21283 HandleScope scope(context->GetIsolate());
21284 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21285 Handle<Object> global = context->Global();
21286 global->Set(v8_str("obj"), obj);
21287 ExpectString("JSON.stringify(obj)", "42");
21292 class ThreadInterruptTest {
21294 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21295 ~ThreadInterruptTest() {}
21298 InterruptThread i_thread(this);
21302 CHECK_EQ(kExpectedValue, sem_value_);
21306 static const int kExpectedValue = 1;
21308 class InterruptThread : public i::Thread {
21310 explicit InterruptThread(ThreadInterruptTest* test)
21311 : Thread("InterruptThread"), test_(test) {}
21313 virtual void Run() {
21314 struct sigaction action;
21316 // Ensure that we'll enter waiting condition
21319 // Setup signal handler
21320 memset(&action, 0, sizeof(action));
21321 action.sa_handler = SignalHandler;
21322 sigaction(SIGCHLD, &action, NULL);
21325 kill(getpid(), SIGCHLD);
21327 // Ensure that if wait has returned because of error
21330 // Set value and signal semaphore
21331 test_->sem_value_ = 1;
21332 test_->sem_.Signal();
21335 static void SignalHandler(int signal) {
21339 ThreadInterruptTest* test_;
21343 volatile int sem_value_;
21347 THREADED_TEST(SemaphoreInterruption) {
21348 ThreadInterruptTest().RunTest();
21352 #endif // V8_OS_POSIX
21355 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21357 v8::AccessType type,
21358 Local<Value> data) {
21359 i::PrintF("Named access blocked.\n");
21364 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21366 v8::AccessType type,
21367 Local<Value> data) {
21368 i::PrintF("Indexed access blocked.\n");
21373 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21378 TEST(JSONStringifyAccessCheck) {
21379 v8::V8::Initialize();
21380 v8::Isolate* isolate = CcTest::isolate();
21381 v8::HandleScope scope(isolate);
21383 // Create an ObjectTemplate for global objects and install access
21384 // check callbacks that will block access.
21385 v8::Handle<v8::ObjectTemplate> global_template =
21386 v8::ObjectTemplate::New(isolate);
21387 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21388 IndexAccessAlwaysBlocked);
21390 // Create a context and set an x property on it's global object.
21391 LocalContext context0(NULL, global_template);
21392 v8::Handle<v8::Object> global0 = context0->Global();
21393 global0->Set(v8_str("x"), v8_num(42));
21394 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21396 for (int i = 0; i < 2; i++) {
21398 // Install a toJSON function on the second run.
21399 v8::Handle<v8::FunctionTemplate> toJSON =
21400 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21402 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21404 // Create a context with a different security token so that the
21405 // failed access check callback will be called on each access.
21406 LocalContext context1(NULL, global_template);
21407 context1->Global()->Set(v8_str("other"), global0);
21409 ExpectString("JSON.stringify(other)", "{}");
21410 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21411 "{\"a\":{},\"b\":[\"c\"]}");
21412 ExpectString("JSON.stringify([other, 'b', 'c'])",
21413 "[{},\"b\",\"c\"]");
21415 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21416 array->Set(0, v8_str("a"));
21417 array->Set(1, v8_str("b"));
21418 context1->Global()->Set(v8_str("array"), array);
21419 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21420 array->TurnOnAccessCheck();
21421 ExpectString("JSON.stringify(array)", "[]");
21422 ExpectString("JSON.stringify([array])", "[[]]");
21423 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21428 bool access_check_fail_thrown = false;
21429 bool catch_callback_called = false;
21432 // Failed access check callback that performs a GC on each invocation.
21433 void FailedAccessCheckThrows(Local<v8::Object> target,
21434 v8::AccessType type,
21435 Local<v8::Value> data) {
21436 access_check_fail_thrown = true;
21437 i::PrintF("Access check failed. Error thrown.\n");
21438 CcTest::isolate()->ThrowException(
21439 v8::Exception::Error(v8_str("cross context")));
21443 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21444 for (int i = 0; i < args.Length(); i++) {
21445 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21447 catch_callback_called = true;
21451 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21452 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21456 void CheckCorrectThrow(const char* script) {
21457 // Test that the script, when wrapped into a try-catch, triggers the catch
21458 // clause due to failed access check throwing an exception.
21459 // The subsequent try-catch should run without any exception.
21460 access_check_fail_thrown = false;
21461 catch_callback_called = false;
21462 i::ScopedVector<char> source(1024);
21463 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21464 CompileRun(source.start());
21465 CHECK(access_check_fail_thrown);
21466 CHECK(catch_callback_called);
21468 access_check_fail_thrown = false;
21469 catch_callback_called = false;
21470 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21471 CHECK(!access_check_fail_thrown);
21472 CHECK(!catch_callback_called);
21476 TEST(AccessCheckThrows) {
21477 i::FLAG_allow_natives_syntax = true;
21478 v8::V8::Initialize();
21479 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21480 v8::Isolate* isolate = CcTest::isolate();
21481 v8::HandleScope scope(isolate);
21483 // Create an ObjectTemplate for global objects and install access
21484 // check callbacks that will block access.
21485 v8::Handle<v8::ObjectTemplate> global_template =
21486 v8::ObjectTemplate::New(isolate);
21487 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21488 IndexAccessAlwaysBlocked);
21490 // Create a context and set an x property on it's global object.
21491 LocalContext context0(NULL, global_template);
21492 context0->Global()->Set(v8_str("x"), v8_num(42));
21493 v8::Handle<v8::Object> global0 = context0->Global();
21495 // Create a context with a different security token so that the
21496 // failed access check callback will be called on each access.
21497 LocalContext context1(NULL, global_template);
21498 context1->Global()->Set(v8_str("other"), global0);
21500 v8::Handle<v8::FunctionTemplate> catcher_fun =
21501 v8::FunctionTemplate::New(isolate, CatcherCallback);
21502 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21504 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21505 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21506 context1->Global()->Set(v8_str("has_own_property"),
21507 has_own_property_fun->GetFunction());
21509 { v8::TryCatch try_catch;
21510 access_check_fail_thrown = false;
21511 CompileRun("other.x;");
21512 CHECK(access_check_fail_thrown);
21513 CHECK(try_catch.HasCaught());
21516 CheckCorrectThrow("other.x");
21517 CheckCorrectThrow("other[1]");
21518 CheckCorrectThrow("JSON.stringify(other)");
21519 CheckCorrectThrow("has_own_property(other, 'x')");
21520 CheckCorrectThrow("%GetProperty(other, 'x')");
21521 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21522 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21523 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21524 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21525 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21526 CheckCorrectThrow("%HasProperty(other, 'x')");
21527 CheckCorrectThrow("%HasElement(other, 1)");
21528 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21529 CheckCorrectThrow("%GetPropertyNames(other)");
21530 // PROPERTY_ATTRIBUTES_NONE = 0
21531 CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21532 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21533 "other, 'x', null, null, 1)");
21535 // Reset the failed access check callback so it does not influence
21536 // the other tests.
21537 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21541 THREADED_TEST(Regress256330) {
21542 i::FLAG_allow_natives_syntax = true;
21543 LocalContext context;
21544 v8::HandleScope scope(context->GetIsolate());
21545 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21546 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21547 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21548 CompileRun("\"use strict\"; var o = new Bug;"
21549 "function f(o) { o.x = 10; };"
21550 "f(o); f(o); f(o);"
21551 "%OptimizeFunctionOnNextCall(f);"
21553 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21557 THREADED_TEST(CrankshaftInterceptorSetter) {
21558 i::FLAG_allow_natives_syntax = true;
21559 v8::HandleScope scope(CcTest::isolate());
21560 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21561 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21563 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21564 CompileRun("var obj = new Obj;"
21565 // Initialize fields to avoid transitions later.
21567 "obj.accessor_age = 42;"
21568 "function setter(i) { this.accessor_age = i; };"
21569 "function getter() { return this.accessor_age; };"
21570 "function setAge(i) { obj.age = i; };"
21571 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21575 "%OptimizeFunctionOnNextCall(setAge);"
21577 // All stores went through the interceptor.
21578 ExpectInt32("obj.interceptor_age", 4);
21579 ExpectInt32("obj.accessor_age", 42);
21583 THREADED_TEST(CrankshaftInterceptorGetter) {
21584 i::FLAG_allow_natives_syntax = true;
21585 v8::HandleScope scope(CcTest::isolate());
21586 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21587 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21589 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21590 CompileRun("var obj = new Obj;"
21591 // Initialize fields to avoid transitions later.
21593 "obj.accessor_age = 42;"
21594 "function getter() { return this.accessor_age; };"
21595 "function getAge() { return obj.interceptor_age; };"
21596 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21600 "%OptimizeFunctionOnNextCall(getAge);");
21601 // Access through interceptor.
21602 ExpectInt32("getAge()", 1);
21606 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21607 i::FLAG_allow_natives_syntax = true;
21608 v8::HandleScope scope(CcTest::isolate());
21609 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21610 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21612 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21613 CompileRun("var obj = new Obj;"
21614 "obj.__proto__.interceptor_age = 42;"
21616 "function getAge() { return obj.interceptor_age; };");
21617 ExpectInt32("getAge();", 100);
21618 ExpectInt32("getAge();", 100);
21619 ExpectInt32("getAge();", 100);
21620 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21621 // Access through interceptor.
21622 ExpectInt32("getAge();", 100);
21626 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21627 i::FLAG_allow_natives_syntax = true;
21628 v8::HandleScope scope(CcTest::isolate());
21629 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21630 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21632 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21633 CompileRun("var obj = new Obj;"
21634 "obj.age = 100000;"
21635 "function setAge(i) { obj.age = i };"
21639 "%OptimizeFunctionOnNextCall(setAge);"
21641 ExpectInt32("obj.age", 100000);
21642 ExpectInt32("obj.interceptor_age", 103);
21646 class RequestInterruptTestBase {
21648 RequestInterruptTestBase()
21650 isolate_(env_->GetIsolate()),
21653 should_continue_(true) {
21656 virtual ~RequestInterruptTestBase() { }
21658 virtual void TestBody() = 0;
21661 InterruptThread i_thread(this);
21664 v8::HandleScope handle_scope(isolate_);
21668 isolate_->ClearInterrupt();
21670 // Verify we arrived here because interruptor was called
21671 // not due to a bug causing us to exit the loop too early.
21672 CHECK(!should_continue());
21675 void WakeUpInterruptor() {
21679 bool should_continue() const { return should_continue_; }
21681 bool ShouldContinue() {
21683 if (--warmup_ == 0) {
21684 WakeUpInterruptor();
21688 return should_continue_;
21692 static void ShouldContinueCallback(
21693 const v8::FunctionCallbackInfo<Value>& info) {
21694 RequestInterruptTestBase* test =
21695 reinterpret_cast<RequestInterruptTestBase*>(
21696 info.Data().As<v8::External>()->Value());
21697 info.GetReturnValue().Set(test->ShouldContinue());
21700 class InterruptThread : public i::Thread {
21702 explicit InterruptThread(RequestInterruptTestBase* test)
21703 : Thread("RequestInterruptTest"), test_(test) {}
21705 virtual void Run() {
21706 test_->sem_.Wait();
21707 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21710 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21711 reinterpret_cast<RequestInterruptTestBase*>(data)->
21712 should_continue_ = false;
21716 RequestInterruptTestBase* test_;
21720 v8::Isolate* isolate_;
21723 bool should_continue_;
21727 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21729 virtual void TestBody() {
21730 Local<Function> func = Function::New(
21731 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21732 env_->Global()->Set(v8_str("ShouldContinue"), func);
21734 CompileRun("while (ShouldContinue()) { }");
21739 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21741 virtual void TestBody() {
21742 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21743 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21744 proto->Set(v8_str("shouldContinue"), Function::New(
21745 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21746 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21748 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21753 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21755 virtual void TestBody() {
21756 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21757 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21758 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21759 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21760 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21762 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21767 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21769 virtual void TestBody() {
21770 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21771 t->InstanceTemplate()->SetNativeDataProperty(
21772 v8_str("shouldContinue"),
21773 &ShouldContinueNativeGetter,
21775 v8::External::New(isolate_, this));
21776 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21778 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21782 static void ShouldContinueNativeGetter(
21783 Local<String> property,
21784 const v8::PropertyCallbackInfo<v8::Value>& info) {
21785 RequestInterruptTestBase* test =
21786 reinterpret_cast<RequestInterruptTestBase*>(
21787 info.Data().As<v8::External>()->Value());
21788 info.GetReturnValue().Set(test->ShouldContinue());
21793 class RequestInterruptTestWithMethodCallAndInterceptor
21794 : public RequestInterruptTestBase {
21796 virtual void TestBody() {
21797 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21798 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21799 proto->Set(v8_str("shouldContinue"), Function::New(
21800 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21801 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21802 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21804 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21806 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21810 static void EmptyInterceptor(
21811 Local<String> property,
21812 const v8::PropertyCallbackInfo<v8::Value>& info) {
21817 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21819 virtual void TestBody() {
21820 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21822 WakeUpInterruptorCallback,
21823 v8::External::New(isolate_, this)));
21825 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21827 ShouldContinueCallback,
21828 v8::External::New(isolate_, this)));
21830 i::FLAG_allow_natives_syntax = true;
21831 CompileRun("function loopish(o) {"
21833 " while (o.abs(1) > 0) {"
21834 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21836 " if (--pre === 0) WakeUpInterruptor(o === Math);"
21841 "var obj = {abs: function () { return i-- }, x: null};"
21844 "%OptimizeFunctionOnNextCall(loopish);"
21847 i::FLAG_allow_natives_syntax = false;
21851 static void WakeUpInterruptorCallback(
21852 const v8::FunctionCallbackInfo<Value>& info) {
21853 if (!info[0]->BooleanValue()) return;
21855 RequestInterruptTestBase* test =
21856 reinterpret_cast<RequestInterruptTestBase*>(
21857 info.Data().As<v8::External>()->Value());
21858 test->WakeUpInterruptor();
21861 static void ShouldContinueCallback(
21862 const v8::FunctionCallbackInfo<Value>& info) {
21863 RequestInterruptTestBase* test =
21864 reinterpret_cast<RequestInterruptTestBase*>(
21865 info.Data().As<v8::External>()->Value());
21866 info.GetReturnValue().Set(test->should_continue());
21871 TEST(RequestInterruptTestWithFunctionCall) {
21872 RequestInterruptTestWithFunctionCall().RunTest();
21876 TEST(RequestInterruptTestWithMethodCall) {
21877 RequestInterruptTestWithMethodCall().RunTest();
21881 TEST(RequestInterruptTestWithAccessor) {
21882 RequestInterruptTestWithAccessor().RunTest();
21886 TEST(RequestInterruptTestWithNativeAccessor) {
21887 RequestInterruptTestWithNativeAccessor().RunTest();
21891 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21892 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21896 TEST(RequestInterruptTestWithMathAbs) {
21897 RequestInterruptTestWithMathAbs().RunTest();
21901 static Local<Value> function_new_expected_env;
21902 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21903 CHECK_EQ(function_new_expected_env, info.Data());
21904 info.GetReturnValue().Set(17);
21908 THREADED_TEST(FunctionNew) {
21910 v8::Isolate* isolate = env->GetIsolate();
21911 v8::HandleScope scope(isolate);
21912 Local<Object> data = v8::Object::New(isolate);
21913 function_new_expected_env = data;
21914 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21915 env->Global()->Set(v8_str("func"), func);
21916 Local<Value> result = CompileRun("func();");
21917 CHECK_EQ(v8::Integer::New(isolate, 17), result);
21918 // Verify function not cached
21919 int serial_number =
21920 i::Smi::cast(v8::Utils::OpenHandle(*func)
21921 ->shared()->get_api_func_data()->serial_number())->value();
21922 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21923 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
21924 i::Handle<i::Object> elm =
21925 i::Object::GetElementNoExceptionThrown(i_isolate, cache, serial_number);
21926 CHECK(elm->IsUndefined());
21927 // Verify that each Function::New creates a new function instance
21928 Local<Object> data2 = v8::Object::New(isolate);
21929 function_new_expected_env = data2;
21930 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21931 CHECK(!func2->IsNull());
21932 CHECK_NE(func, func2);
21933 env->Global()->Set(v8_str("func2"), func2);
21934 Local<Value> result2 = CompileRun("func2();");
21935 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21939 TEST(EscapeableHandleScope) {
21940 HandleScope outer_scope(CcTest::isolate());
21941 LocalContext context;
21942 const int runs = 10;
21943 Local<String> values[runs];
21944 for (int i = 0; i < runs; i++) {
21945 v8::EscapableHandleScope inner_scope(CcTest::isolate());
21946 Local<String> value;
21947 if (i != 0) value = v8_str("escape value");
21948 values[i] = inner_scope.Escape(value);
21950 for (int i = 0; i < runs; i++) {
21951 Local<String> expected;
21953 CHECK_EQ(v8_str("escape value"), values[i]);
21955 CHECK(values[i].IsEmpty());
21961 static void SetterWhichExpectsThisAndHolderToDiffer(
21962 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21963 CHECK(info.Holder() != info.This());
21967 TEST(Regress239669) {
21968 LocalContext context;
21969 v8::Isolate* isolate = context->GetIsolate();
21970 v8::HandleScope scope(isolate);
21971 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21972 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21973 context->Global()->Set(v8_str("P"), templ->NewInstance());
21978 "C1.prototype = P;"
21979 "for (var i = 0; i < 4; i++ ) {"
21985 class ApiCallOptimizationChecker {
21987 static Local<Object> data;
21988 static Local<Object> receiver;
21989 static Local<Object> holder;
21990 static Local<Object> callee;
21993 static void OptimizationCallback(
21994 const v8::FunctionCallbackInfo<v8::Value>& info) {
21995 CHECK(callee == info.Callee());
21996 CHECK(data == info.Data());
21997 CHECK(receiver == info.This());
21998 if (info.Length() == 1) {
21999 CHECK_EQ(v8_num(1), info[0]);
22001 CHECK(holder == info.Holder());
22003 info.GetReturnValue().Set(v8_str("returned"));
22007 enum SignatureType {
22009 kSignatureOnReceiver,
22010 kSignatureOnPrototype
22014 SignatureType signature_types[] =
22015 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22016 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22017 SignatureType signature_type = signature_types[i];
22018 for (int j = 0; j < 2; j++) {
22019 bool global = j == 0;
22020 int key = signature_type +
22021 ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22022 Run(signature_type, global, key);
22027 void Run(SignatureType signature_type, bool global, int key) {
22028 v8::Isolate* isolate = CcTest::isolate();
22029 v8::HandleScope scope(isolate);
22030 // Build a template for signature checks.
22031 Local<v8::ObjectTemplate> signature_template;
22032 Local<v8::Signature> signature;
22034 Local<v8::FunctionTemplate> parent_template =
22035 FunctionTemplate::New(isolate);
22036 parent_template->SetHiddenPrototype(true);
22037 Local<v8::FunctionTemplate> function_template
22038 = FunctionTemplate::New(isolate);
22039 function_template->Inherit(parent_template);
22040 switch (signature_type) {
22043 case kSignatureOnReceiver:
22044 signature = v8::Signature::New(isolate, function_template);
22046 case kSignatureOnPrototype:
22047 signature = v8::Signature::New(isolate, parent_template);
22050 signature_template = function_template->InstanceTemplate();
22052 // Global object must pass checks.
22053 Local<v8::Context> context =
22054 v8::Context::New(isolate, NULL, signature_template);
22055 v8::Context::Scope context_scope(context);
22056 // Install regular object that can pass signature checks.
22057 Local<Object> function_receiver = signature_template->NewInstance();
22058 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22059 // Get the holder objects.
22060 Local<Object> inner_global =
22061 Local<Object>::Cast(context->Global()->GetPrototype());
22062 // Install functions on hidden prototype object if there is one.
22063 data = Object::New(isolate);
22064 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22065 isolate, OptimizationCallback, data, signature);
22066 Local<Function> function = function_template->GetFunction();
22067 Local<Object> global_holder = inner_global;
22068 Local<Object> function_holder = function_receiver;
22069 if (signature_type == kSignatureOnPrototype) {
22070 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22071 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22073 global_holder->Set(v8_str("g_f"), function);
22074 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22075 function_holder->Set(v8_str("f"), function);
22076 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22077 // Initialize expected values.
22081 receiver = context->Global();
22082 holder = inner_global;
22084 holder = function_receiver;
22085 // If not using a signature, add something else to the prototype chain
22086 // to test the case that holder != receiver
22087 if (signature_type == kNoSignature) {
22088 receiver = Local<Object>::Cast(CompileRun(
22089 "var receiver_subclass = {};\n"
22090 "receiver_subclass.__proto__ = function_receiver;\n"
22091 "receiver_subclass"));
22093 receiver = Local<Object>::Cast(CompileRun(
22094 "var receiver_subclass = function_receiver;\n"
22095 "receiver_subclass"));
22098 // With no signature, the holder is not set.
22099 if (signature_type == kNoSignature) holder = receiver;
22100 // build wrap_function
22101 i::ScopedVector<char> wrap_function(200);
22105 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22106 "function wrap_get_%d() { return this.g_acc; }\n"
22107 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22112 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22113 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22114 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22117 // build source string
22118 i::ScopedVector<char> source(1000);
22121 "%s\n" // wrap functions
22122 "function wrap_f() { return wrap_f_%d(); }\n"
22123 "function wrap_get() { return wrap_get_%d(); }\n"
22124 "function wrap_set() { return wrap_set_%d(); }\n"
22125 "check = function(returned) {\n"
22126 " if (returned !== 'returned') { throw returned; }\n"
22129 "check(wrap_f());\n"
22130 "check(wrap_f());\n"
22131 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22132 "check(wrap_f());\n"
22134 "check(wrap_get());\n"
22135 "check(wrap_get());\n"
22136 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22137 "check(wrap_get());\n"
22139 "check = function(returned) {\n"
22140 " if (returned !== 1) { throw returned; }\n"
22142 "check(wrap_set());\n"
22143 "check(wrap_set());\n"
22144 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22145 "check(wrap_set());\n",
22146 wrap_function.start(), key, key, key, key, key, key);
22147 v8::TryCatch try_catch;
22148 CompileRun(source.start());
22149 ASSERT(!try_catch.HasCaught());
22150 CHECK_EQ(9, count);
22155 Local<Object> ApiCallOptimizationChecker::data;
22156 Local<Object> ApiCallOptimizationChecker::receiver;
22157 Local<Object> ApiCallOptimizationChecker::holder;
22158 Local<Object> ApiCallOptimizationChecker::callee;
22159 int ApiCallOptimizationChecker::count = 0;
22162 TEST(TestFunctionCallOptimization) {
22163 i::FLAG_allow_natives_syntax = true;
22164 ApiCallOptimizationChecker checker;
22169 static const char* last_event_message;
22170 static int last_event_status;
22171 void StoringEventLoggerCallback(const char* message, int status) {
22172 last_event_message = message;
22173 last_event_status = status;
22177 TEST(EventLogging) {
22178 v8::Isolate* isolate = CcTest::isolate();
22179 isolate->SetEventLogger(StoringEventLoggerCallback);
22180 v8::internal::HistogramTimer* histogramTimer =
22181 new v8::internal::HistogramTimer(
22182 "V8.Test", 0, 10000, 50,
22183 reinterpret_cast<v8::internal::Isolate*>(isolate));
22184 histogramTimer->Start();
22185 CHECK_EQ("V8.Test", last_event_message);
22186 CHECK_EQ(0, last_event_status);
22187 histogramTimer->Stop();
22188 CHECK_EQ("V8.Test", last_event_message);
22189 CHECK_EQ(1, last_event_status);
22194 LocalContext context;
22195 v8::Isolate* isolate = context->GetIsolate();
22196 v8::HandleScope scope(isolate);
22197 Handle<Object> global = context->Global();
22200 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22201 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22202 Handle<v8::Promise> p = pr->GetPromise();
22203 Handle<v8::Promise> r = rr->GetPromise();
22205 // IsPromise predicate.
22206 CHECK(p->IsPromise());
22207 CHECK(r->IsPromise());
22208 Handle<Value> o = v8::Object::New(isolate);
22209 CHECK(!o->IsPromise());
22211 // Resolution and rejection.
22212 pr->Resolve(v8::Integer::New(isolate, 1));
22213 CHECK(p->IsPromise());
22214 rr->Reject(v8::Integer::New(isolate, 2));
22215 CHECK(r->IsPromise());
22217 // Chaining non-pending promises.
22221 "function f1(x) { x1 = x; return x+1 };\n"
22222 "function f2(x) { x2 = x; return x+1 };\n");
22223 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22224 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22227 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22228 V8::RunMicrotasks(isolate);
22229 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22232 V8::RunMicrotasks(isolate);
22233 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22236 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22237 V8::RunMicrotasks(isolate);
22238 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22241 V8::RunMicrotasks(isolate);
22242 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22244 // Chaining pending promises.
22245 CompileRun("x1 = x2 = 0;");
22246 pr = v8::Promise::Resolver::New(isolate);
22247 rr = v8::Promise::Resolver::New(isolate);
22249 pr->GetPromise()->Chain(f1);
22250 rr->GetPromise()->Catch(f2);
22251 V8::RunMicrotasks(isolate);
22252 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22253 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22255 pr->Resolve(v8::Integer::New(isolate, 1));
22256 rr->Reject(v8::Integer::New(isolate, 2));
22257 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22258 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22260 V8::RunMicrotasks(isolate);
22261 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22262 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22265 CompileRun("x1 = x2 = 0;");
22266 pr = v8::Promise::Resolver::New(isolate);
22267 pr->GetPromise()->Chain(f1)->Chain(f2);
22268 pr->Resolve(v8::Integer::New(isolate, 3));
22269 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22270 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22271 V8::RunMicrotasks(isolate);
22272 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22273 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22275 CompileRun("x1 = x2 = 0;");
22276 rr = v8::Promise::Resolver::New(isolate);
22277 rr->GetPromise()->Catch(f1)->Chain(f2);
22278 rr->Reject(v8::Integer::New(isolate, 3));
22279 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22280 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22281 V8::RunMicrotasks(isolate);
22282 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22283 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22287 TEST(DisallowJavascriptExecutionScope) {
22288 LocalContext context;
22289 v8::Isolate* isolate = context->GetIsolate();
22290 v8::HandleScope scope(isolate);
22291 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22292 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22297 TEST(AllowJavascriptExecutionScope) {
22298 LocalContext context;
22299 v8::Isolate* isolate = context->GetIsolate();
22300 v8::HandleScope scope(isolate);
22301 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22302 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22303 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22304 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22305 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22311 TEST(ThrowOnJavascriptExecution) {
22312 LocalContext context;
22313 v8::Isolate* isolate = context->GetIsolate();
22314 v8::HandleScope scope(isolate);
22315 v8::TryCatch try_catch;
22316 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22317 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22319 CHECK(try_catch.HasCaught());
22323 TEST(Regress354123) {
22324 LocalContext current;
22325 v8::Isolate* isolate = current->GetIsolate();
22326 v8::HandleScope scope(isolate);
22328 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22329 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22330 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22332 // Test access using __proto__ from the prototype chain.
22333 named_access_count = 0;
22334 CompileRun("friend.__proto__ = {};");
22335 CHECK_EQ(2, named_access_count);
22336 CompileRun("friend.__proto__;");
22337 CHECK_EQ(4, named_access_count);
22339 // Test access using __proto__ as a hijacked function (A).
22340 named_access_count = 0;
22341 CompileRun("var p = Object.prototype;"
22342 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22343 "f.call(friend, {});");
22344 CHECK_EQ(1, named_access_count);
22345 CompileRun("var p = Object.prototype;"
22346 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22347 "f.call(friend);");
22348 CHECK_EQ(2, named_access_count);
22350 // Test access using __proto__ as a hijacked function (B).
22351 named_access_count = 0;
22352 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22353 "f.call(friend, {});");
22354 CHECK_EQ(1, named_access_count);
22355 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22356 "f.call(friend);");
22357 CHECK_EQ(2, named_access_count);
22359 // Test access using Object.setPrototypeOf reflective method.
22360 named_access_count = 0;
22361 CompileRun("Object.setPrototypeOf(friend, {});");
22362 CHECK_EQ(1, named_access_count);
22363 CompileRun("Object.getPrototypeOf(friend);");
22364 CHECK_EQ(2, named_access_count);