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"
54 static const bool kLogThreading = false;
57 using ::v8::BooleanObject;
59 using ::v8::Extension;
61 using ::v8::FunctionTemplate;
63 using ::v8::HandleScope;
66 using ::v8::MessageCallback;
68 using ::v8::ObjectTemplate;
69 using ::v8::Persistent;
71 using ::v8::StackTrace;
74 using ::v8::Undefined;
80 #define THREADED_PROFILED_TEST(Name) \
81 static void Test##Name(); \
82 TEST(Name##WithProfiler) { \
83 RunWithProfiler(&Test##Name); \
88 void RunWithProfiler(void (*test)()) {
90 v8::HandleScope scope(env->GetIsolate());
91 v8::Local<v8::String> profile_name =
92 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
93 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95 cpu_profiler->StartCpuProfiling(profile_name);
97 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101 static void ExpectString(const char* code, const char* expected) {
102 Local<Value> result = CompileRun(code);
103 CHECK(result->IsString());
104 String::Utf8Value utf8(result);
105 CHECK_EQ(expected, *utf8);
109 static void ExpectInt32(const char* code, int expected) {
110 Local<Value> result = CompileRun(code);
111 CHECK(result->IsInt32());
112 CHECK_EQ(expected, result->Int32Value());
116 static void ExpectBoolean(const char* code, bool expected) {
117 Local<Value> result = CompileRun(code);
118 CHECK(result->IsBoolean());
119 CHECK_EQ(expected, result->BooleanValue());
123 static void ExpectTrue(const char* code) {
124 ExpectBoolean(code, true);
128 static void ExpectFalse(const char* code) {
129 ExpectBoolean(code, false);
133 static void ExpectObject(const char* code, Local<Value> expected) {
134 Local<Value> result = CompileRun(code);
135 CHECK(result->Equals(expected));
139 static void ExpectUndefined(const char* code) {
140 Local<Value> result = CompileRun(code);
141 CHECK(result->IsUndefined());
145 static int signature_callback_count;
146 static Local<Value> signature_expected_receiver;
147 static void IncrementingSignatureCallback(
148 const v8::FunctionCallbackInfo<v8::Value>& args) {
149 ApiTestFuzzer::Fuzz();
150 signature_callback_count++;
151 CHECK_EQ(signature_expected_receiver, args.Holder());
152 CHECK_EQ(signature_expected_receiver, args.This());
153 v8::Handle<v8::Array> result =
154 v8::Array::New(args.GetIsolate(), args.Length());
155 for (int i = 0; i < args.Length(); i++)
156 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
157 args.GetReturnValue().Set(result);
161 static void SignatureCallback(
162 const v8::FunctionCallbackInfo<v8::Value>& args) {
163 ApiTestFuzzer::Fuzz();
164 v8::Handle<v8::Array> result =
165 v8::Array::New(args.GetIsolate(), args.Length());
166 for (int i = 0; i < args.Length(); i++) {
167 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
169 args.GetReturnValue().Set(result);
173 // Tests that call v8::V8::Dispose() cannot be threaded.
174 TEST(InitializeAndDisposeOnce) {
175 CHECK(v8::V8::Initialize());
176 CHECK(v8::V8::Dispose());
180 // Tests that call v8::V8::Dispose() cannot be threaded.
181 TEST(InitializeAndDisposeMultiple) {
182 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
183 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
184 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
185 // TODO(mstarzinger): This should fail gracefully instead of asserting.
186 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
187 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
191 THREADED_TEST(Handles) {
192 v8::HandleScope scope(CcTest::isolate());
193 Local<Context> local_env;
196 local_env = env.local();
199 // Local context should still be live.
200 CHECK(!local_env.IsEmpty());
203 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
204 CHECK(!undef.IsEmpty());
205 CHECK(undef->IsUndefined());
207 const char* c_source = "1 + 2 + 3";
208 Local<String> source = String::NewFromUtf8(CcTest::isolate(), c_source);
209 Local<Script> script = Script::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* c_source = "1 + 2 + 3";
449 Local<String> source = String::NewFromUtf8(env->GetIsolate(), c_source);
450 Local<Script> script = Script::Compile(source);
451 CHECK_EQ(6, script->Run()->Int32Value());
455 static uint16_t* AsciiToTwoByteString(const char* source) {
456 int array_length = i::StrLength(source) + 1;
457 uint16_t* converted = i::NewArray<uint16_t>(array_length);
458 for (int i = 0; i < array_length; i++) converted[i] = source[i];
463 class TestResource: public String::ExternalStringResource {
465 TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
466 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
467 while (data[length_]) ++length_;
471 if (owning_data_) i::DeleteArray(data_);
472 if (counter_ != NULL) ++*counter_;
475 const uint16_t* data() const {
479 size_t length() const {
491 class TestAsciiResource: public String::ExternalAsciiStringResource {
493 TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
495 data_(data + offset),
496 length_(strlen(data) - offset),
497 counter_(counter) { }
499 ~TestAsciiResource() {
500 i::DeleteArray(orig_data_);
501 if (counter_ != NULL) ++*counter_;
504 const char* data() const {
508 size_t length() const {
513 const char* orig_data_;
520 THREADED_TEST(ScriptUsingStringResource) {
521 int dispose_count = 0;
522 const char* c_source = "1 + 2 * 3";
523 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
526 v8::HandleScope scope(env->GetIsolate());
527 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
528 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
529 Local<Script> script = Script::Compile(source);
530 Local<Value> value = script->Run();
531 CHECK(value->IsNumber());
532 CHECK_EQ(7, value->Int32Value());
533 CHECK(source->IsExternal());
535 static_cast<TestResource*>(source->GetExternalStringResource()));
536 String::Encoding encoding = String::UNKNOWN_ENCODING;
537 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
538 source->GetExternalStringResourceBase(&encoding));
539 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
540 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
541 CHECK_EQ(0, dispose_count);
543 CcTest::i_isolate()->compilation_cache()->Clear();
544 CcTest::heap()->CollectAllAvailableGarbage();
545 CHECK_EQ(1, dispose_count);
549 THREADED_TEST(ScriptUsingAsciiStringResource) {
550 int dispose_count = 0;
551 const char* c_source = "1 + 2 * 3";
554 v8::HandleScope scope(env->GetIsolate());
555 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
557 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
558 CHECK(source->IsExternalAscii());
559 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
560 source->GetExternalAsciiStringResource());
561 String::Encoding encoding = String::UNKNOWN_ENCODING;
562 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
563 source->GetExternalStringResourceBase(&encoding));
564 CHECK_EQ(String::ASCII_ENCODING, encoding);
565 Local<Script> script = Script::Compile(source);
566 Local<Value> value = script->Run();
567 CHECK(value->IsNumber());
568 CHECK_EQ(7, value->Int32Value());
569 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
570 CHECK_EQ(0, dispose_count);
572 CcTest::i_isolate()->compilation_cache()->Clear();
573 CcTest::heap()->CollectAllAvailableGarbage();
574 CHECK_EQ(1, dispose_count);
578 THREADED_TEST(ScriptMakingExternalString) {
579 int dispose_count = 0;
580 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
583 v8::HandleScope scope(env->GetIsolate());
584 Local<String> source =
585 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
586 // Trigger GCs so that the newly allocated string moves to old gen.
587 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
588 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
589 CHECK_EQ(source->IsExternal(), false);
590 CHECK_EQ(source->IsExternalAscii(), false);
591 String::Encoding encoding = String::UNKNOWN_ENCODING;
592 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
593 CHECK_EQ(String::ASCII_ENCODING, encoding);
594 bool success = source->MakeExternal(new TestResource(two_byte_source,
597 Local<Script> script = Script::Compile(source);
598 Local<Value> value = script->Run();
599 CHECK(value->IsNumber());
600 CHECK_EQ(7, value->Int32Value());
601 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
602 CHECK_EQ(0, dispose_count);
604 CcTest::i_isolate()->compilation_cache()->Clear();
605 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
606 CHECK_EQ(1, dispose_count);
610 THREADED_TEST(ScriptMakingExternalAsciiString) {
611 int dispose_count = 0;
612 const char* c_source = "1 + 2 * 3";
615 v8::HandleScope scope(env->GetIsolate());
616 Local<String> source = v8_str(c_source);
617 // Trigger GCs so that the newly allocated string moves to old gen.
618 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
619 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
620 bool success = source->MakeExternal(
621 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
623 Local<Script> script = Script::Compile(source);
624 Local<Value> value = script->Run();
625 CHECK(value->IsNumber());
626 CHECK_EQ(7, value->Int32Value());
627 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
628 CHECK_EQ(0, dispose_count);
630 CcTest::i_isolate()->compilation_cache()->Clear();
631 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
632 CHECK_EQ(1, dispose_count);
636 TEST(MakingExternalStringConditions) {
638 v8::HandleScope scope(env->GetIsolate());
640 // Free some space in the new space so that we can check freshness.
641 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
644 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
645 Local<String> small_string =
646 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
647 i::DeleteArray(two_byte_string);
649 // We should refuse to externalize newly created small string.
650 CHECK(!small_string->CanMakeExternal());
651 // Trigger GCs so that the newly allocated string moves to old gen.
652 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
653 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
654 // Old space strings should be accepted.
655 CHECK(small_string->CanMakeExternal());
657 two_byte_string = AsciiToTwoByteString("small string 2");
658 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
659 i::DeleteArray(two_byte_string);
661 // We should refuse externalizing newly created small string.
662 CHECK(!small_string->CanMakeExternal());
663 for (int i = 0; i < 100; i++) {
664 String::Value value(small_string);
666 // Frequently used strings should be accepted.
667 CHECK(small_string->CanMakeExternal());
669 const int buf_size = 10 * 1024;
670 char* buf = i::NewArray<char>(buf_size);
671 memset(buf, 'a', buf_size);
672 buf[buf_size - 1] = '\0';
674 two_byte_string = AsciiToTwoByteString(buf);
675 Local<String> large_string =
676 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
678 i::DeleteArray(two_byte_string);
679 // Large strings should be immediately accepted.
680 CHECK(large_string->CanMakeExternal());
684 TEST(MakingExternalAsciiStringConditions) {
686 v8::HandleScope scope(env->GetIsolate());
688 // Free some space in the new space so that we can check freshness.
689 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
690 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
692 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
693 // We should refuse to externalize newly created small string.
694 CHECK(!small_string->CanMakeExternal());
695 // Trigger GCs so that the newly allocated string moves to old gen.
696 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
697 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
698 // Old space strings should be accepted.
699 CHECK(small_string->CanMakeExternal());
701 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
702 // We should refuse externalizing newly created small string.
703 CHECK(!small_string->CanMakeExternal());
704 for (int i = 0; i < 100; i++) {
705 String::Value value(small_string);
707 // Frequently used strings should be accepted.
708 CHECK(small_string->CanMakeExternal());
710 const int buf_size = 10 * 1024;
711 char* buf = i::NewArray<char>(buf_size);
712 memset(buf, 'a', buf_size);
713 buf[buf_size - 1] = '\0';
714 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
716 // Large strings should be immediately accepted.
717 CHECK(large_string->CanMakeExternal());
721 TEST(MakingExternalUnalignedAsciiString) {
723 v8::HandleScope scope(env->GetIsolate());
725 CompileRun("function cons(a, b) { return a + b; }"
726 "function slice(a) { return a.substring(1); }");
727 // Create a cons string that will land in old pointer space.
728 Local<String> cons = Local<String>::Cast(CompileRun(
729 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
730 // Create a sliced string that will land in old pointer space.
731 Local<String> slice = Local<String>::Cast(CompileRun(
732 "slice('abcdefghijklmnopqrstuvwxyz');"));
734 // Trigger GCs so that the newly allocated string moves to old gen.
735 SimulateFullSpace(CcTest::heap()->old_pointer_space());
736 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
737 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
739 // Turn into external string with unaligned resource data.
740 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
741 bool success = cons->MakeExternal(
742 new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
744 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
745 success = slice->MakeExternal(
746 new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
749 // Trigger GCs and force evacuation.
750 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
751 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
755 THREADED_TEST(UsingExternalString) {
756 i::Factory* factory = CcTest::i_isolate()->factory();
758 v8::HandleScope scope(CcTest::isolate());
759 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
760 Local<String> string = String::NewExternal(
761 CcTest::isolate(), new TestResource(two_byte_string));
762 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
763 // Trigger GCs so that the newly allocated string moves to old gen.
764 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
765 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
766 i::Handle<i::String> isymbol =
767 factory->InternalizedStringFromString(istring);
768 CHECK(isymbol->IsInternalizedString());
770 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
775 THREADED_TEST(UsingExternalAsciiString) {
776 i::Factory* factory = CcTest::i_isolate()->factory();
778 v8::HandleScope scope(CcTest::isolate());
779 const char* one_byte_string = "test string";
780 Local<String> string = String::NewExternal(
781 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
782 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
783 // Trigger GCs so that the newly allocated string moves to old gen.
784 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
785 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
786 i::Handle<i::String> isymbol =
787 factory->InternalizedStringFromString(istring);
788 CHECK(isymbol->IsInternalizedString());
790 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
791 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
795 THREADED_TEST(ScavengeExternalString) {
796 i::FLAG_stress_compaction = false;
797 i::FLAG_gc_global = false;
798 int dispose_count = 0;
799 bool in_new_space = false;
801 v8::HandleScope scope(CcTest::isolate());
802 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
803 Local<String> string = String::NewExternal(
804 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
805 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
806 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
807 in_new_space = CcTest::heap()->InNewSpace(*istring);
808 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
809 CHECK_EQ(0, dispose_count);
811 CcTest::heap()->CollectGarbage(
812 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
813 CHECK_EQ(1, dispose_count);
817 THREADED_TEST(ScavengeExternalAsciiString) {
818 i::FLAG_stress_compaction = false;
819 i::FLAG_gc_global = false;
820 int dispose_count = 0;
821 bool in_new_space = false;
823 v8::HandleScope scope(CcTest::isolate());
824 const char* one_byte_string = "test string";
825 Local<String> string = String::NewExternal(
827 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
828 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
829 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
830 in_new_space = CcTest::heap()->InNewSpace(*istring);
831 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
832 CHECK_EQ(0, dispose_count);
834 CcTest::heap()->CollectGarbage(
835 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
836 CHECK_EQ(1, dispose_count);
840 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
842 // Only used by non-threaded tests, so it can use static fields.
843 static int dispose_calls;
844 static int dispose_count;
846 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
847 : TestAsciiResource(data, &dispose_count),
848 dispose_(dispose) { }
852 if (dispose_) delete this;
859 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
860 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
863 TEST(ExternalStringWithDisposeHandling) {
864 const char* c_source = "1 + 2 * 3";
866 // Use a stack allocated external string resource allocated object.
867 TestAsciiResourceWithDisposeControl::dispose_count = 0;
868 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
869 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
872 v8::HandleScope scope(env->GetIsolate());
873 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
874 Local<Script> script = Script::Compile(source);
875 Local<Value> value = script->Run();
876 CHECK(value->IsNumber());
877 CHECK_EQ(7, value->Int32Value());
878 CcTest::heap()->CollectAllAvailableGarbage();
879 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
881 CcTest::i_isolate()->compilation_cache()->Clear();
882 CcTest::heap()->CollectAllAvailableGarbage();
883 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
884 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
886 // Use a heap allocated external string resource allocated object.
887 TestAsciiResourceWithDisposeControl::dispose_count = 0;
888 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
889 TestAsciiResource* res_heap =
890 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
893 v8::HandleScope scope(env->GetIsolate());
894 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
895 Local<Script> script = Script::Compile(source);
896 Local<Value> value = script->Run();
897 CHECK(value->IsNumber());
898 CHECK_EQ(7, value->Int32Value());
899 CcTest::heap()->CollectAllAvailableGarbage();
900 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
902 CcTest::i_isolate()->compilation_cache()->Clear();
903 CcTest::heap()->CollectAllAvailableGarbage();
904 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
905 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
909 THREADED_TEST(StringConcat) {
912 v8::HandleScope scope(env->GetIsolate());
913 const char* one_byte_string_1 = "function a_times_t";
914 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
915 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
916 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
917 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
919 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
920 Local<String> left = v8_str(one_byte_string_1);
922 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
923 Local<String> right =
924 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
925 i::DeleteArray(two_byte_source);
927 Local<String> source = String::Concat(left, right);
928 right = String::NewExternal(
929 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
930 source = String::Concat(source, right);
931 right = String::NewExternal(
933 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
934 source = String::Concat(source, right);
935 right = v8_str(one_byte_string_2);
936 source = String::Concat(source, right);
938 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
939 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
940 i::DeleteArray(two_byte_source);
942 source = String::Concat(source, right);
943 right = String::NewExternal(
945 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
946 source = String::Concat(source, right);
947 Local<Script> script = Script::Compile(source);
948 Local<Value> value = script->Run();
949 CHECK(value->IsNumber());
950 CHECK_EQ(68, value->Int32Value());
952 CcTest::i_isolate()->compilation_cache()->Clear();
953 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
954 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
958 THREADED_TEST(GlobalProperties) {
960 v8::HandleScope scope(env->GetIsolate());
961 v8::Handle<v8::Object> global = env->Global();
962 global->Set(v8_str("pi"), v8_num(3.1415926));
963 Local<Value> pi = global->Get(v8_str("pi"));
964 CHECK_EQ(3.1415926, pi->NumberValue());
969 static void CheckReturnValue(const T& t, i::Address callback) {
970 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
971 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
972 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
973 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
974 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
976 bool is_runtime = (*o)->IsTheHole();
978 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
979 rv.Set(v8::Handle<v8::Object>());
980 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
981 CHECK_EQ(is_runtime, (*o)->IsTheHole());
983 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
984 // If CPU profiler is active check that when API callback is invoked
985 // VMState is set to EXTERNAL.
986 if (isolate->cpu_profiler()->is_profiling()) {
987 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
988 CHECK(isolate->external_callback_scope());
989 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
994 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
995 i::Address callback) {
996 ApiTestFuzzer::Fuzz();
997 CheckReturnValue(info, callback);
998 info.GetReturnValue().Set(v8_str("bad value"));
999 info.GetReturnValue().Set(v8_num(102));
1003 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1004 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1008 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1009 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1012 static void construct_callback(
1013 const v8::FunctionCallbackInfo<Value>& info) {
1014 ApiTestFuzzer::Fuzz();
1015 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1016 info.This()->Set(v8_str("x"), v8_num(1));
1017 info.This()->Set(v8_str("y"), v8_num(2));
1018 info.GetReturnValue().Set(v8_str("bad value"));
1019 info.GetReturnValue().Set(info.This());
1023 static void Return239Callback(
1024 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1025 ApiTestFuzzer::Fuzz();
1026 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1027 info.GetReturnValue().Set(v8_str("bad value"));
1028 info.GetReturnValue().Set(v8_num(239));
1032 template<typename Handler>
1033 static void TestFunctionTemplateInitializer(Handler handler,
1034 Handler handler_2) {
1035 // Test constructor calls.
1038 v8::Isolate* isolate = env->GetIsolate();
1039 v8::HandleScope scope(isolate);
1041 Local<v8::FunctionTemplate> fun_templ =
1042 v8::FunctionTemplate::New(isolate, handler);
1043 Local<Function> fun = fun_templ->GetFunction();
1044 env->Global()->Set(v8_str("obj"), fun);
1045 Local<Script> script = v8_compile("obj()");
1046 for (int i = 0; i < 30; i++) {
1047 CHECK_EQ(102, script->Run()->Int32Value());
1050 // Use SetCallHandler to initialize a function template, should work like
1051 // the previous one.
1054 v8::Isolate* isolate = env->GetIsolate();
1055 v8::HandleScope scope(isolate);
1057 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1058 fun_templ->SetCallHandler(handler_2);
1059 Local<Function> fun = fun_templ->GetFunction();
1060 env->Global()->Set(v8_str("obj"), fun);
1061 Local<Script> script = v8_compile("obj()");
1062 for (int i = 0; i < 30; i++) {
1063 CHECK_EQ(102, script->Run()->Int32Value());
1069 template<typename Constructor, typename Accessor>
1070 static void TestFunctionTemplateAccessor(Constructor constructor,
1071 Accessor accessor) {
1073 v8::HandleScope scope(env->GetIsolate());
1075 Local<v8::FunctionTemplate> fun_templ =
1076 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1077 fun_templ->SetClassName(v8_str("funky"));
1078 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1079 Local<Function> fun = fun_templ->GetFunction();
1080 env->Global()->Set(v8_str("obj"), fun);
1081 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1082 CHECK_EQ(v8_str("[object funky]"), result);
1083 CompileRun("var obj_instance = new obj();");
1084 Local<Script> script;
1085 script = v8_compile("obj_instance.x");
1086 for (int i = 0; i < 30; i++) {
1087 CHECK_EQ(1, script->Run()->Int32Value());
1089 script = v8_compile("obj_instance.m");
1090 for (int i = 0; i < 30; i++) {
1091 CHECK_EQ(239, script->Run()->Int32Value());
1096 THREADED_PROFILED_TEST(FunctionTemplate) {
1097 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1098 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1102 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1103 ApiTestFuzzer::Fuzz();
1104 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1105 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1109 template<typename Callback>
1110 static void TestSimpleCallback(Callback callback) {
1112 v8::Isolate* isolate = env->GetIsolate();
1113 v8::HandleScope scope(isolate);
1115 v8::Handle<v8::ObjectTemplate> object_template =
1116 v8::ObjectTemplate::New(isolate);
1117 object_template->Set(isolate, "callback",
1118 v8::FunctionTemplate::New(isolate, callback));
1119 v8::Local<v8::Object> object = object_template->NewInstance();
1120 (*env)->Global()->Set(v8_str("callback_object"), object);
1121 v8::Handle<v8::Script> script;
1122 script = v8_compile("callback_object.callback(17)");
1123 for (int i = 0; i < 30; i++) {
1124 CHECK_EQ(51424, script->Run()->Int32Value());
1126 script = v8_compile("callback_object.callback(17, 24)");
1127 for (int i = 0; i < 30; i++) {
1128 CHECK_EQ(51425, script->Run()->Int32Value());
1133 THREADED_PROFILED_TEST(SimpleCallback) {
1134 TestSimpleCallback(SimpleCallback);
1138 template<typename T>
1139 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1141 // constant return values
1142 static int32_t fast_return_value_int32 = 471;
1143 static uint32_t fast_return_value_uint32 = 571;
1144 static const double kFastReturnValueDouble = 2.7;
1145 // variable return values
1146 static bool fast_return_value_bool = false;
1147 enum ReturnValueOddball {
1149 kUndefinedReturnValue,
1150 kEmptyStringReturnValue
1152 static ReturnValueOddball fast_return_value_void;
1153 static bool fast_return_value_object_is_empty = false;
1155 // Helper function to avoid compiler error: insufficient contextual information
1156 // to determine type when applying FUNCTION_ADDR to a template function.
1157 static i::Address address_of(v8::FunctionCallback callback) {
1158 return FUNCTION_ADDR(callback);
1162 void FastReturnValueCallback<int32_t>(
1163 const v8::FunctionCallbackInfo<v8::Value>& info) {
1164 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1165 info.GetReturnValue().Set(fast_return_value_int32);
1169 void FastReturnValueCallback<uint32_t>(
1170 const v8::FunctionCallbackInfo<v8::Value>& info) {
1171 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1172 info.GetReturnValue().Set(fast_return_value_uint32);
1176 void FastReturnValueCallback<double>(
1177 const v8::FunctionCallbackInfo<v8::Value>& info) {
1178 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1179 info.GetReturnValue().Set(kFastReturnValueDouble);
1183 void FastReturnValueCallback<bool>(
1184 const v8::FunctionCallbackInfo<v8::Value>& info) {
1185 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1186 info.GetReturnValue().Set(fast_return_value_bool);
1190 void FastReturnValueCallback<void>(
1191 const v8::FunctionCallbackInfo<v8::Value>& info) {
1192 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1193 switch (fast_return_value_void) {
1194 case kNullReturnValue:
1195 info.GetReturnValue().SetNull();
1197 case kUndefinedReturnValue:
1198 info.GetReturnValue().SetUndefined();
1200 case kEmptyStringReturnValue:
1201 info.GetReturnValue().SetEmptyString();
1207 void FastReturnValueCallback<Object>(
1208 const v8::FunctionCallbackInfo<v8::Value>& info) {
1209 v8::Handle<v8::Object> object;
1210 if (!fast_return_value_object_is_empty) {
1211 object = Object::New(info.GetIsolate());
1213 info.GetReturnValue().Set(object);
1216 template<typename T>
1217 Handle<Value> TestFastReturnValues() {
1219 v8::Isolate* isolate = env->GetIsolate();
1220 v8::EscapableHandleScope scope(isolate);
1221 v8::Handle<v8::ObjectTemplate> object_template =
1222 v8::ObjectTemplate::New(isolate);
1223 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1224 object_template->Set(isolate, "callback",
1225 v8::FunctionTemplate::New(isolate, callback));
1226 v8::Local<v8::Object> object = object_template->NewInstance();
1227 (*env)->Global()->Set(v8_str("callback_object"), object);
1228 return scope.Escape(CompileRun("callback_object.callback()"));
1232 THREADED_PROFILED_TEST(FastReturnValues) {
1234 v8::HandleScope scope(CcTest::isolate());
1235 v8::Handle<v8::Value> value;
1236 // check int32_t and uint32_t
1237 int32_t int_values[] = {
1239 i::Smi::kMinValue, i::Smi::kMaxValue
1241 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1242 for (int modifier = -1; modifier <= 1; modifier++) {
1243 int int_value = int_values[i] + modifier;
1245 fast_return_value_int32 = int_value;
1246 value = TestFastReturnValues<int32_t>();
1247 CHECK(value->IsInt32());
1248 CHECK(fast_return_value_int32 == value->Int32Value());
1250 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1251 value = TestFastReturnValues<uint32_t>();
1252 CHECK(value->IsUint32());
1253 CHECK(fast_return_value_uint32 == value->Uint32Value());
1257 value = TestFastReturnValues<double>();
1258 CHECK(value->IsNumber());
1259 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1260 // check bool values
1261 for (int i = 0; i < 2; i++) {
1262 fast_return_value_bool = i == 0;
1263 value = TestFastReturnValues<bool>();
1264 CHECK(value->IsBoolean());
1265 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1268 ReturnValueOddball oddballs[] = {
1270 kUndefinedReturnValue,
1271 kEmptyStringReturnValue
1273 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1274 fast_return_value_void = oddballs[i];
1275 value = TestFastReturnValues<void>();
1276 switch (fast_return_value_void) {
1277 case kNullReturnValue:
1278 CHECK(value->IsNull());
1280 case kUndefinedReturnValue:
1281 CHECK(value->IsUndefined());
1283 case kEmptyStringReturnValue:
1284 CHECK(value->IsString());
1285 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1290 fast_return_value_object_is_empty = false;
1291 value = TestFastReturnValues<Object>();
1292 CHECK(value->IsObject());
1293 fast_return_value_object_is_empty = true;
1294 value = TestFastReturnValues<Object>();
1295 CHECK(value->IsUndefined());
1299 THREADED_TEST(FunctionTemplateSetLength) {
1301 v8::Isolate* isolate = env->GetIsolate();
1302 v8::HandleScope scope(isolate);
1304 Local<v8::FunctionTemplate> fun_templ =
1305 v8::FunctionTemplate::New(isolate,
1307 Handle<v8::Value>(),
1308 Handle<v8::Signature>(),
1310 Local<Function> fun = fun_templ->GetFunction();
1311 env->Global()->Set(v8_str("obj"), fun);
1312 Local<Script> script = v8_compile("obj.length");
1313 CHECK_EQ(23, script->Run()->Int32Value());
1316 Local<v8::FunctionTemplate> fun_templ =
1317 v8::FunctionTemplate::New(isolate, handle_callback);
1318 fun_templ->SetLength(22);
1319 Local<Function> fun = fun_templ->GetFunction();
1320 env->Global()->Set(v8_str("obj"), fun);
1321 Local<Script> script = v8_compile("obj.length");
1322 CHECK_EQ(22, script->Run()->Int32Value());
1325 // Without setting length it defaults to 0.
1326 Local<v8::FunctionTemplate> fun_templ =
1327 v8::FunctionTemplate::New(isolate, handle_callback);
1328 Local<Function> fun = fun_templ->GetFunction();
1329 env->Global()->Set(v8_str("obj"), fun);
1330 Local<Script> script = v8_compile("obj.length");
1331 CHECK_EQ(0, script->Run()->Int32Value());
1336 static void* expected_ptr;
1337 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1338 void* ptr = v8::External::Cast(*args.Data())->Value();
1339 CHECK_EQ(expected_ptr, ptr);
1340 args.GetReturnValue().Set(true);
1344 static void TestExternalPointerWrapping() {
1346 v8::Isolate* isolate = env->GetIsolate();
1347 v8::HandleScope scope(isolate);
1349 v8::Handle<v8::Value> data =
1350 v8::External::New(isolate, expected_ptr);
1352 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1353 obj->Set(v8_str("func"),
1354 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1355 env->Global()->Set(v8_str("obj"), obj);
1358 "function foo() {\n"
1359 " for (var i = 0; i < 13; i++) obj.func();\n"
1361 "foo(), true")->BooleanValue());
1365 THREADED_TEST(ExternalWrap) {
1366 // Check heap allocated object.
1369 TestExternalPointerWrapping();
1372 // Check stack allocated object.
1374 expected_ptr = &foo;
1375 TestExternalPointerWrapping();
1377 // Check not aligned addresses.
1379 char* s = new char[n];
1380 for (int i = 0; i < n; i++) {
1381 expected_ptr = s + i;
1382 TestExternalPointerWrapping();
1387 // Check several invalid addresses.
1388 expected_ptr = reinterpret_cast<void*>(1);
1389 TestExternalPointerWrapping();
1391 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1392 TestExternalPointerWrapping();
1394 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1395 TestExternalPointerWrapping();
1397 #if defined(V8_HOST_ARCH_X64)
1398 // Check a value with a leading 1 bit in x64 Smi encoding.
1399 expected_ptr = reinterpret_cast<void*>(0x400000000);
1400 TestExternalPointerWrapping();
1402 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1403 TestExternalPointerWrapping();
1405 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1406 TestExternalPointerWrapping();
1411 THREADED_TEST(FindInstanceInPrototypeChain) {
1413 v8::Isolate* isolate = env->GetIsolate();
1414 v8::HandleScope scope(isolate);
1416 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1417 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1418 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1419 derived->Inherit(base);
1421 Local<v8::Function> base_function = base->GetFunction();
1422 Local<v8::Function> derived_function = derived->GetFunction();
1423 Local<v8::Function> other_function = other->GetFunction();
1425 Local<v8::Object> base_instance = base_function->NewInstance();
1426 Local<v8::Object> derived_instance = derived_function->NewInstance();
1427 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1428 Local<v8::Object> other_instance = other_function->NewInstance();
1429 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1430 other_instance->Set(v8_str("__proto__"), derived_instance2);
1432 // base_instance is only an instance of base.
1433 CHECK_EQ(base_instance,
1434 base_instance->FindInstanceInPrototypeChain(base));
1435 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1436 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1438 // derived_instance is an instance of base and derived.
1439 CHECK_EQ(derived_instance,
1440 derived_instance->FindInstanceInPrototypeChain(base));
1441 CHECK_EQ(derived_instance,
1442 derived_instance->FindInstanceInPrototypeChain(derived));
1443 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1445 // other_instance is an instance of other and its immediate
1446 // prototype derived_instance2 is an instance of base and derived.
1447 // Note, derived_instance is an instance of base and derived too,
1448 // but it comes after derived_instance2 in the prototype chain of
1450 CHECK_EQ(derived_instance2,
1451 other_instance->FindInstanceInPrototypeChain(base));
1452 CHECK_EQ(derived_instance2,
1453 other_instance->FindInstanceInPrototypeChain(derived));
1454 CHECK_EQ(other_instance,
1455 other_instance->FindInstanceInPrototypeChain(other));
1459 THREADED_TEST(TinyInteger) {
1461 v8::Isolate* isolate = env->GetIsolate();
1462 v8::HandleScope scope(isolate);
1464 int32_t value = 239;
1465 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1466 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1468 value_obj = v8::Integer::New(isolate, value);
1469 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1473 THREADED_TEST(BigSmiInteger) {
1475 v8::HandleScope scope(env->GetIsolate());
1476 v8::Isolate* isolate = CcTest::isolate();
1478 int32_t value = i::Smi::kMaxValue;
1479 // We cannot add one to a Smi::kMaxValue without wrapping.
1480 if (i::SmiValuesAre31Bits()) {
1481 CHECK(i::Smi::IsValid(value));
1482 CHECK(!i::Smi::IsValid(value + 1));
1484 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1485 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1487 value_obj = v8::Integer::New(isolate, value);
1488 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1493 THREADED_TEST(BigInteger) {
1495 v8::HandleScope scope(env->GetIsolate());
1496 v8::Isolate* isolate = CcTest::isolate();
1498 // We cannot add one to a Smi::kMaxValue without wrapping.
1499 if (i::SmiValuesAre31Bits()) {
1500 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1501 // The code will not be run in that case, due to the "if" guard.
1503 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1504 CHECK(value > i::Smi::kMaxValue);
1505 CHECK(!i::Smi::IsValid(value));
1507 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1510 value_obj = v8::Integer::New(isolate, value);
1511 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1516 THREADED_TEST(TinyUnsignedInteger) {
1518 v8::HandleScope scope(env->GetIsolate());
1519 v8::Isolate* isolate = CcTest::isolate();
1521 uint32_t value = 239;
1523 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1526 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1527 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1531 THREADED_TEST(BigUnsignedSmiInteger) {
1533 v8::HandleScope scope(env->GetIsolate());
1534 v8::Isolate* isolate = CcTest::isolate();
1536 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1537 CHECK(i::Smi::IsValid(value));
1538 CHECK(!i::Smi::IsValid(value + 1));
1540 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1541 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1543 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1544 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1548 THREADED_TEST(BigUnsignedInteger) {
1550 v8::HandleScope scope(env->GetIsolate());
1551 v8::Isolate* isolate = CcTest::isolate();
1553 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1554 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1555 CHECK(!i::Smi::IsValid(value));
1557 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1558 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1560 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1561 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1565 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1567 v8::HandleScope scope(env->GetIsolate());
1568 v8::Isolate* isolate = CcTest::isolate();
1570 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1571 uint32_t value = INT32_MAX_AS_UINT + 1;
1572 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1574 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1577 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1578 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1582 THREADED_TEST(IsNativeError) {
1584 v8::HandleScope scope(env->GetIsolate());
1585 v8::Handle<Value> syntax_error = CompileRun(
1586 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1587 CHECK(syntax_error->IsNativeError());
1588 v8::Handle<Value> not_error = CompileRun("{a:42}");
1589 CHECK(!not_error->IsNativeError());
1590 v8::Handle<Value> not_object = CompileRun("42");
1591 CHECK(!not_object->IsNativeError());
1595 THREADED_TEST(StringObject) {
1597 v8::HandleScope scope(env->GetIsolate());
1598 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1599 CHECK(boxed_string->IsStringObject());
1600 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1601 CHECK(!unboxed_string->IsStringObject());
1602 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1603 CHECK(!boxed_not_string->IsStringObject());
1604 v8::Handle<Value> not_object = CompileRun("0");
1605 CHECK(!not_object->IsStringObject());
1606 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1607 CHECK(!as_boxed.IsEmpty());
1608 Local<v8::String> the_string = as_boxed->ValueOf();
1609 CHECK(!the_string.IsEmpty());
1610 ExpectObject("\"test\"", the_string);
1611 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1612 CHECK(new_boxed_string->IsStringObject());
1613 as_boxed = new_boxed_string.As<v8::StringObject>();
1614 the_string = as_boxed->ValueOf();
1615 CHECK(!the_string.IsEmpty());
1616 ExpectObject("\"test\"", the_string);
1620 THREADED_TEST(NumberObject) {
1622 v8::HandleScope scope(env->GetIsolate());
1623 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1624 CHECK(boxed_number->IsNumberObject());
1625 v8::Handle<Value> unboxed_number = CompileRun("42");
1626 CHECK(!unboxed_number->IsNumberObject());
1627 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1628 CHECK(!boxed_not_number->IsNumberObject());
1629 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1630 CHECK(!as_boxed.IsEmpty());
1631 double the_number = as_boxed->ValueOf();
1632 CHECK_EQ(42.0, the_number);
1633 v8::Handle<v8::Value> new_boxed_number =
1634 v8::NumberObject::New(env->GetIsolate(), 43);
1635 CHECK(new_boxed_number->IsNumberObject());
1636 as_boxed = new_boxed_number.As<v8::NumberObject>();
1637 the_number = as_boxed->ValueOf();
1638 CHECK_EQ(43.0, the_number);
1642 THREADED_TEST(BooleanObject) {
1644 v8::HandleScope scope(env->GetIsolate());
1645 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1646 CHECK(boxed_boolean->IsBooleanObject());
1647 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1648 CHECK(!unboxed_boolean->IsBooleanObject());
1649 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1650 CHECK(!boxed_not_boolean->IsBooleanObject());
1651 v8::Handle<v8::BooleanObject> as_boxed =
1652 boxed_boolean.As<v8::BooleanObject>();
1653 CHECK(!as_boxed.IsEmpty());
1654 bool the_boolean = as_boxed->ValueOf();
1655 CHECK_EQ(true, the_boolean);
1656 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1657 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1658 CHECK(boxed_true->IsBooleanObject());
1659 CHECK(boxed_false->IsBooleanObject());
1660 as_boxed = boxed_true.As<v8::BooleanObject>();
1661 CHECK_EQ(true, as_boxed->ValueOf());
1662 as_boxed = boxed_false.As<v8::BooleanObject>();
1663 CHECK_EQ(false, as_boxed->ValueOf());
1667 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1669 v8::HandleScope scope(env->GetIsolate());
1671 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1672 CHECK(primitive_false->IsBoolean());
1673 CHECK(!primitive_false->IsBooleanObject());
1674 CHECK(!primitive_false->BooleanValue());
1675 CHECK(!primitive_false->IsTrue());
1676 CHECK(primitive_false->IsFalse());
1678 Local<Value> false_value = BooleanObject::New(false);
1679 CHECK(!false_value->IsBoolean());
1680 CHECK(false_value->IsBooleanObject());
1681 CHECK(false_value->BooleanValue());
1682 CHECK(!false_value->IsTrue());
1683 CHECK(!false_value->IsFalse());
1685 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1686 CHECK(!false_boolean_object->IsBoolean());
1687 CHECK(false_boolean_object->IsBooleanObject());
1688 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1689 // CHECK(false_boolean_object->BooleanValue());
1690 CHECK(!false_boolean_object->ValueOf());
1691 CHECK(!false_boolean_object->IsTrue());
1692 CHECK(!false_boolean_object->IsFalse());
1694 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1695 CHECK(primitive_true->IsBoolean());
1696 CHECK(!primitive_true->IsBooleanObject());
1697 CHECK(primitive_true->BooleanValue());
1698 CHECK(primitive_true->IsTrue());
1699 CHECK(!primitive_true->IsFalse());
1701 Local<Value> true_value = BooleanObject::New(true);
1702 CHECK(!true_value->IsBoolean());
1703 CHECK(true_value->IsBooleanObject());
1704 CHECK(true_value->BooleanValue());
1705 CHECK(!true_value->IsTrue());
1706 CHECK(!true_value->IsFalse());
1708 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1709 CHECK(!true_boolean_object->IsBoolean());
1710 CHECK(true_boolean_object->IsBooleanObject());
1711 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1712 // CHECK(true_boolean_object->BooleanValue());
1713 CHECK(true_boolean_object->ValueOf());
1714 CHECK(!true_boolean_object->IsTrue());
1715 CHECK(!true_boolean_object->IsFalse());
1719 THREADED_TEST(Number) {
1721 v8::HandleScope scope(env->GetIsolate());
1722 double PI = 3.1415926;
1723 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1724 CHECK_EQ(PI, pi_obj->NumberValue());
1728 THREADED_TEST(ToNumber) {
1730 v8::Isolate* isolate = CcTest::isolate();
1731 v8::HandleScope scope(isolate);
1732 Local<String> str = v8_str("3.1415926");
1733 CHECK_EQ(3.1415926, str->NumberValue());
1734 v8::Handle<v8::Boolean> t = v8::True(isolate);
1735 CHECK_EQ(1.0, t->NumberValue());
1736 v8::Handle<v8::Boolean> f = v8::False(isolate);
1737 CHECK_EQ(0.0, f->NumberValue());
1741 THREADED_TEST(Date) {
1743 v8::HandleScope scope(env->GetIsolate());
1744 double PI = 3.1415926;
1745 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1746 CHECK_EQ(3.0, date->NumberValue());
1747 date.As<v8::Date>()->Set(v8_str("property"),
1748 v8::Integer::New(env->GetIsolate(), 42));
1749 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1753 THREADED_TEST(Boolean) {
1755 v8::Isolate* isolate = env->GetIsolate();
1756 v8::HandleScope scope(isolate);
1757 v8::Handle<v8::Boolean> t = v8::True(isolate);
1759 v8::Handle<v8::Boolean> f = v8::False(isolate);
1761 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1762 CHECK(!u->BooleanValue());
1763 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1764 CHECK(!n->BooleanValue());
1765 v8::Handle<String> str1 = v8_str("");
1766 CHECK(!str1->BooleanValue());
1767 v8::Handle<String> str2 = v8_str("x");
1768 CHECK(str2->BooleanValue());
1769 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1770 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1771 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1772 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1773 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1777 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1778 ApiTestFuzzer::Fuzz();
1779 args.GetReturnValue().Set(v8_num(13.4));
1783 static void GetM(Local<String> name,
1784 const v8::PropertyCallbackInfo<v8::Value>& info) {
1785 ApiTestFuzzer::Fuzz();
1786 info.GetReturnValue().Set(v8_num(876));
1790 THREADED_TEST(GlobalPrototype) {
1791 v8::Isolate* isolate = CcTest::isolate();
1792 v8::HandleScope scope(isolate);
1793 v8::Handle<v8::FunctionTemplate> func_templ =
1794 v8::FunctionTemplate::New(isolate);
1795 func_templ->PrototypeTemplate()->Set(
1796 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1797 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1798 templ->Set(isolate, "x", v8_num(200));
1799 templ->SetAccessor(v8_str("m"), GetM);
1800 LocalContext env(0, templ);
1801 v8::Handle<Script> script(v8_compile("dummy()"));
1802 v8::Handle<Value> result(script->Run());
1803 CHECK_EQ(13.4, result->NumberValue());
1804 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1805 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1809 THREADED_TEST(ObjectTemplate) {
1810 v8::Isolate* isolate = CcTest::isolate();
1811 v8::HandleScope scope(isolate);
1812 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1813 templ1->Set(isolate, "x", v8_num(10));
1814 templ1->Set(isolate, "y", v8_num(13));
1816 Local<v8::Object> instance1 = templ1->NewInstance();
1817 env->Global()->Set(v8_str("p"), instance1);
1818 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1819 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1820 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1821 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1822 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1823 templ2->Set(isolate, "a", v8_num(12));
1824 templ2->Set(isolate, "b", templ1);
1825 Local<v8::Object> instance2 = templ2->NewInstance();
1826 env->Global()->Set(v8_str("q"), instance2);
1827 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1828 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1829 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1830 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1834 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1835 ApiTestFuzzer::Fuzz();
1836 args.GetReturnValue().Set(v8_num(17.2));
1840 static void GetKnurd(Local<String> property,
1841 const v8::PropertyCallbackInfo<v8::Value>& info) {
1842 ApiTestFuzzer::Fuzz();
1843 info.GetReturnValue().Set(v8_num(15.2));
1847 THREADED_TEST(DescriptorInheritance) {
1848 v8::Isolate* isolate = CcTest::isolate();
1849 v8::HandleScope scope(isolate);
1850 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1851 super->PrototypeTemplate()->Set(isolate, "flabby",
1852 v8::FunctionTemplate::New(isolate,
1854 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1856 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1858 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1859 base1->Inherit(super);
1860 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1862 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1863 base2->Inherit(super);
1864 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1868 env->Global()->Set(v8_str("s"), super->GetFunction());
1869 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1870 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1872 // Checks right __proto__ chain.
1873 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1874 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1876 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1878 // Instance accessor should not be visible on function object or its prototype
1879 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1880 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1881 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1883 env->Global()->Set(v8_str("obj"),
1884 base1->GetFunction()->NewInstance());
1885 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1886 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1887 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1888 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1889 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1891 env->Global()->Set(v8_str("obj2"),
1892 base2->GetFunction()->NewInstance());
1893 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1894 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1895 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1896 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1897 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1899 // base1 and base2 cannot cross reference to each's prototype
1900 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1901 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1905 int echo_named_call_count;
1908 static void EchoNamedProperty(Local<String> name,
1909 const v8::PropertyCallbackInfo<v8::Value>& info) {
1910 ApiTestFuzzer::Fuzz();
1911 CHECK_EQ(v8_str("data"), info.Data());
1912 echo_named_call_count++;
1913 info.GetReturnValue().Set(name);
1917 // Helper functions for Interceptor/Accessor interaction tests
1919 void SimpleAccessorGetter(Local<String> name,
1920 const v8::PropertyCallbackInfo<v8::Value>& info) {
1921 Handle<Object> self = info.This();
1922 info.GetReturnValue().Set(
1923 self->Get(String::Concat(v8_str("accessor_"), name)));
1926 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1927 const v8::PropertyCallbackInfo<void>& info) {
1928 Handle<Object> self = info.This();
1929 self->Set(String::Concat(v8_str("accessor_"), name), value);
1932 void EmptyInterceptorGetter(Local<String> name,
1933 const v8::PropertyCallbackInfo<v8::Value>& info) {
1936 void EmptyInterceptorSetter(Local<String> name,
1938 const v8::PropertyCallbackInfo<v8::Value>& info) {
1941 void InterceptorGetter(Local<String> name,
1942 const v8::PropertyCallbackInfo<v8::Value>& info) {
1943 // Intercept names that start with 'interceptor_'.
1944 String::Utf8Value utf8(name);
1945 char* name_str = *utf8;
1946 char prefix[] = "interceptor_";
1948 for (i = 0; name_str[i] && prefix[i]; ++i) {
1949 if (name_str[i] != prefix[i]) return;
1951 Handle<Object> self = info.This();
1952 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1955 void InterceptorSetter(Local<String> name,
1957 const v8::PropertyCallbackInfo<v8::Value>& info) {
1958 // Intercept accesses that set certain integer values, for which the name does
1959 // not start with 'accessor_'.
1960 String::Utf8Value utf8(name);
1961 char* name_str = *utf8;
1962 char prefix[] = "accessor_";
1964 for (i = 0; name_str[i] && prefix[i]; ++i) {
1965 if (name_str[i] != prefix[i]) break;
1967 if (!prefix[i]) return;
1969 if (value->IsInt32() && value->Int32Value() < 10000) {
1970 Handle<Object> self = info.This();
1971 self->SetHiddenValue(name, value);
1972 info.GetReturnValue().Set(value);
1976 void AddAccessor(Handle<FunctionTemplate> templ,
1977 Handle<String> name,
1978 v8::AccessorGetterCallback getter,
1979 v8::AccessorSetterCallback setter) {
1980 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1983 void AddInterceptor(Handle<FunctionTemplate> templ,
1984 v8::NamedPropertyGetterCallback getter,
1985 v8::NamedPropertySetterCallback setter) {
1986 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1990 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1991 v8::HandleScope scope(CcTest::isolate());
1992 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1993 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1994 child->Inherit(parent);
1995 AddAccessor(parent, v8_str("age"),
1996 SimpleAccessorGetter, SimpleAccessorSetter);
1997 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1999 env->Global()->Set(v8_str("Child"), child->GetFunction());
2000 CompileRun("var child = new Child;"
2002 ExpectBoolean("child.hasOwnProperty('age')", false);
2003 ExpectInt32("child.age", 10);
2004 ExpectInt32("child.accessor_age", 10);
2008 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2009 v8::HandleScope scope(CcTest::isolate());
2010 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2011 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2013 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2014 CompileRun("var o1 = new Constructor;"
2015 "o1.a = 1;" // Ensure a and x share the descriptor array.
2016 "Object.defineProperty(o1, 'x', {value: 10});");
2017 CompileRun("var o2 = new Constructor;"
2019 "Object.defineProperty(o2, 'x', {value: 10});");
2023 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2024 v8::Isolate* isolate = CcTest::isolate();
2025 v8::HandleScope scope(isolate);
2026 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2027 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2028 child->Inherit(parent);
2029 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2031 env->Global()->Set(v8_str("Child"), child->GetFunction());
2032 CompileRun("var child = new Child;"
2033 "var parent = child.__proto__;"
2034 "Object.defineProperty(parent, 'age', "
2035 " {get: function(){ return this.accessor_age; }, "
2036 " set: function(v){ this.accessor_age = v; }, "
2037 " enumerable: true, configurable: true});"
2039 ExpectBoolean("child.hasOwnProperty('age')", false);
2040 ExpectInt32("child.age", 10);
2041 ExpectInt32("child.accessor_age", 10);
2045 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2046 v8::Isolate* isolate = CcTest::isolate();
2047 v8::HandleScope scope(isolate);
2048 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2049 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2050 child->Inherit(parent);
2051 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2053 env->Global()->Set(v8_str("Child"), child->GetFunction());
2054 CompileRun("var child = new Child;"
2055 "var parent = child.__proto__;"
2056 "parent.name = 'Alice';");
2057 ExpectBoolean("child.hasOwnProperty('name')", false);
2058 ExpectString("child.name", "Alice");
2059 CompileRun("child.name = 'Bob';");
2060 ExpectString("child.name", "Bob");
2061 ExpectBoolean("child.hasOwnProperty('name')", true);
2062 ExpectString("parent.name", "Alice");
2066 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2067 v8::HandleScope scope(CcTest::isolate());
2068 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2069 AddAccessor(templ, v8_str("age"),
2070 SimpleAccessorGetter, SimpleAccessorSetter);
2071 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2073 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2074 CompileRun("var obj = new Obj;"
2075 "function setAge(i){ obj.age = i; };"
2076 "for(var i = 0; i <= 10000; i++) setAge(i);");
2077 // All i < 10000 go to the interceptor.
2078 ExpectInt32("obj.interceptor_age", 9999);
2079 // The last i goes to the accessor.
2080 ExpectInt32("obj.accessor_age", 10000);
2084 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2085 v8::HandleScope scope(CcTest::isolate());
2086 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2087 AddAccessor(templ, v8_str("age"),
2088 SimpleAccessorGetter, SimpleAccessorSetter);
2089 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2091 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2092 CompileRun("var obj = new Obj;"
2093 "function setAge(i){ obj.age = i; };"
2094 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2095 // All i >= 10000 go to the accessor.
2096 ExpectInt32("obj.accessor_age", 10000);
2097 // The last i goes to the interceptor.
2098 ExpectInt32("obj.interceptor_age", 9999);
2102 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2103 v8::HandleScope scope(CcTest::isolate());
2104 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2105 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2106 child->Inherit(parent);
2107 AddAccessor(parent, v8_str("age"),
2108 SimpleAccessorGetter, SimpleAccessorSetter);
2109 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2111 env->Global()->Set(v8_str("Child"), child->GetFunction());
2112 CompileRun("var child = new Child;"
2113 "function setAge(i){ child.age = i; };"
2114 "for(var i = 0; i <= 10000; i++) setAge(i);");
2115 // All i < 10000 go to the interceptor.
2116 ExpectInt32("child.interceptor_age", 9999);
2117 // The last i goes to the accessor.
2118 ExpectInt32("child.accessor_age", 10000);
2122 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2123 v8::HandleScope scope(CcTest::isolate());
2124 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2125 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2126 child->Inherit(parent);
2127 AddAccessor(parent, v8_str("age"),
2128 SimpleAccessorGetter, SimpleAccessorSetter);
2129 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2131 env->Global()->Set(v8_str("Child"), child->GetFunction());
2132 CompileRun("var child = new Child;"
2133 "function setAge(i){ child.age = i; };"
2134 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2135 // All i >= 10000 go to the accessor.
2136 ExpectInt32("child.accessor_age", 10000);
2137 // The last i goes to the interceptor.
2138 ExpectInt32("child.interceptor_age", 9999);
2142 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2143 v8::HandleScope scope(CcTest::isolate());
2144 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2145 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2147 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2148 CompileRun("var obj = new Obj;"
2149 "function setter(i) { this.accessor_age = i; };"
2150 "function getter() { return this.accessor_age; };"
2151 "function setAge(i) { obj.age = i; };"
2152 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2153 "for(var i = 0; i <= 10000; i++) setAge(i);");
2154 // All i < 10000 go to the interceptor.
2155 ExpectInt32("obj.interceptor_age", 9999);
2156 // The last i goes to the JavaScript accessor.
2157 ExpectInt32("obj.accessor_age", 10000);
2158 // The installed JavaScript getter is still intact.
2159 // This last part is a regression test for issue 1651 and relies on the fact
2160 // that both interceptor and accessor are being installed on the same object.
2161 ExpectInt32("obj.age", 10000);
2162 ExpectBoolean("obj.hasOwnProperty('age')", true);
2163 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2167 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2168 v8::HandleScope scope(CcTest::isolate());
2169 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2170 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2172 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2173 CompileRun("var obj = new Obj;"
2174 "function setter(i) { this.accessor_age = i; };"
2175 "function getter() { return this.accessor_age; };"
2176 "function setAge(i) { obj.age = i; };"
2177 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2178 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2179 // All i >= 10000 go to the accessor.
2180 ExpectInt32("obj.accessor_age", 10000);
2181 // The last i goes to the interceptor.
2182 ExpectInt32("obj.interceptor_age", 9999);
2183 // The installed JavaScript getter is still intact.
2184 // This last part is a regression test for issue 1651 and relies on the fact
2185 // that both interceptor and accessor are being installed on the same object.
2186 ExpectInt32("obj.age", 10000);
2187 ExpectBoolean("obj.hasOwnProperty('age')", true);
2188 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2192 THREADED_TEST(SwitchFromInterceptorToProperty) {
2193 v8::HandleScope scope(CcTest::isolate());
2194 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2195 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2196 child->Inherit(parent);
2197 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2199 env->Global()->Set(v8_str("Child"), child->GetFunction());
2200 CompileRun("var child = new Child;"
2201 "function setAge(i){ child.age = i; };"
2202 "for(var i = 0; i <= 10000; i++) setAge(i);");
2203 // All i < 10000 go to the interceptor.
2204 ExpectInt32("child.interceptor_age", 9999);
2205 // The last i goes to child's own property.
2206 ExpectInt32("child.age", 10000);
2210 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2211 v8::HandleScope scope(CcTest::isolate());
2212 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2213 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2214 child->Inherit(parent);
2215 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2217 env->Global()->Set(v8_str("Child"), child->GetFunction());
2218 CompileRun("var child = new Child;"
2219 "function setAge(i){ child.age = i; };"
2220 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2221 // All i >= 10000 go to child's own property.
2222 ExpectInt32("child.age", 10000);
2223 // The last i goes to the interceptor.
2224 ExpectInt32("child.interceptor_age", 9999);
2228 THREADED_TEST(NamedPropertyHandlerGetter) {
2229 echo_named_call_count = 0;
2230 v8::HandleScope scope(CcTest::isolate());
2231 v8::Handle<v8::FunctionTemplate> templ =
2232 v8::FunctionTemplate::New(CcTest::isolate());
2233 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2237 env->Global()->Set(v8_str("obj"),
2238 templ->GetFunction()->NewInstance());
2239 CHECK_EQ(echo_named_call_count, 0);
2240 v8_compile("obj.x")->Run();
2241 CHECK_EQ(echo_named_call_count, 1);
2242 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2243 v8::Handle<Value> str = CompileRun(code);
2244 String::Utf8Value value(str);
2245 CHECK_EQ(*value, "oddlepoddle");
2246 // Check default behavior
2247 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2248 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2249 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2253 int echo_indexed_call_count = 0;
2256 static void EchoIndexedProperty(
2258 const v8::PropertyCallbackInfo<v8::Value>& info) {
2259 ApiTestFuzzer::Fuzz();
2260 CHECK_EQ(v8_num(637), info.Data());
2261 echo_indexed_call_count++;
2262 info.GetReturnValue().Set(v8_num(index));
2266 THREADED_TEST(IndexedPropertyHandlerGetter) {
2267 v8::Isolate* isolate = CcTest::isolate();
2268 v8::HandleScope scope(isolate);
2269 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2270 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2274 env->Global()->Set(v8_str("obj"),
2275 templ->GetFunction()->NewInstance());
2276 Local<Script> script = v8_compile("obj[900]");
2277 CHECK_EQ(script->Run()->Int32Value(), 900);
2281 v8::Handle<v8::Object> bottom;
2283 static void CheckThisIndexedPropertyHandler(
2285 const v8::PropertyCallbackInfo<v8::Value>& info) {
2286 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2287 ApiTestFuzzer::Fuzz();
2288 CHECK(info.This()->Equals(bottom));
2291 static void CheckThisNamedPropertyHandler(
2293 const v8::PropertyCallbackInfo<v8::Value>& info) {
2294 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2295 ApiTestFuzzer::Fuzz();
2296 CHECK(info.This()->Equals(bottom));
2299 void CheckThisIndexedPropertySetter(
2302 const v8::PropertyCallbackInfo<v8::Value>& info) {
2303 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2304 ApiTestFuzzer::Fuzz();
2305 CHECK(info.This()->Equals(bottom));
2309 void CheckThisNamedPropertySetter(
2310 Local<String> property,
2312 const v8::PropertyCallbackInfo<v8::Value>& info) {
2313 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2314 ApiTestFuzzer::Fuzz();
2315 CHECK(info.This()->Equals(bottom));
2318 void CheckThisIndexedPropertyQuery(
2320 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2321 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2322 ApiTestFuzzer::Fuzz();
2323 CHECK(info.This()->Equals(bottom));
2327 void CheckThisNamedPropertyQuery(
2328 Local<String> property,
2329 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2330 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2331 ApiTestFuzzer::Fuzz();
2332 CHECK(info.This()->Equals(bottom));
2336 void CheckThisIndexedPropertyDeleter(
2338 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2339 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2340 ApiTestFuzzer::Fuzz();
2341 CHECK(info.This()->Equals(bottom));
2345 void CheckThisNamedPropertyDeleter(
2346 Local<String> property,
2347 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2348 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2349 ApiTestFuzzer::Fuzz();
2350 CHECK(info.This()->Equals(bottom));
2354 void CheckThisIndexedPropertyEnumerator(
2355 const v8::PropertyCallbackInfo<v8::Array>& info) {
2356 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2357 ApiTestFuzzer::Fuzz();
2358 CHECK(info.This()->Equals(bottom));
2362 void CheckThisNamedPropertyEnumerator(
2363 const v8::PropertyCallbackInfo<v8::Array>& info) {
2364 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2365 ApiTestFuzzer::Fuzz();
2366 CHECK(info.This()->Equals(bottom));
2370 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2372 v8::Isolate* isolate = env->GetIsolate();
2373 v8::HandleScope scope(isolate);
2375 // Set up a prototype chain with three interceptors.
2376 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2377 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2378 CheckThisIndexedPropertyHandler,
2379 CheckThisIndexedPropertySetter,
2380 CheckThisIndexedPropertyQuery,
2381 CheckThisIndexedPropertyDeleter,
2382 CheckThisIndexedPropertyEnumerator);
2384 templ->InstanceTemplate()->SetNamedPropertyHandler(
2385 CheckThisNamedPropertyHandler,
2386 CheckThisNamedPropertySetter,
2387 CheckThisNamedPropertyQuery,
2388 CheckThisNamedPropertyDeleter,
2389 CheckThisNamedPropertyEnumerator);
2391 bottom = templ->GetFunction()->NewInstance();
2392 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2393 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2395 bottom->SetPrototype(middle);
2396 middle->SetPrototype(top);
2397 env->Global()->Set(v8_str("obj"), bottom);
2399 // Indexed and named get.
2400 Script::Compile(v8_str("obj[0]"))->Run();
2401 Script::Compile(v8_str("obj.x"))->Run();
2403 // Indexed and named set.
2404 Script::Compile(v8_str("obj[1] = 42"))->Run();
2405 Script::Compile(v8_str("obj.y = 42"))->Run();
2407 // Indexed and named query.
2408 Script::Compile(v8_str("0 in obj"))->Run();
2409 Script::Compile(v8_str("'x' in obj"))->Run();
2411 // Indexed and named deleter.
2412 Script::Compile(v8_str("delete obj[0]"))->Run();
2413 Script::Compile(v8_str("delete obj.x"))->Run();
2416 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2420 static void PrePropertyHandlerGet(
2422 const v8::PropertyCallbackInfo<v8::Value>& info) {
2423 ApiTestFuzzer::Fuzz();
2424 if (v8_str("pre")->Equals(key)) {
2425 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2430 static void PrePropertyHandlerQuery(
2432 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2433 if (v8_str("pre")->Equals(key)) {
2434 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2439 THREADED_TEST(PrePropertyHandler) {
2440 v8::Isolate* isolate = CcTest::isolate();
2441 v8::HandleScope scope(isolate);
2442 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2443 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2445 PrePropertyHandlerQuery);
2446 LocalContext env(NULL, desc->InstanceTemplate());
2447 Script::Compile(v8_str(
2448 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2449 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2450 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2451 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2452 CHECK_EQ(v8_str("Object: on"), result_on);
2453 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2454 CHECK(result_post.IsEmpty());
2458 THREADED_TEST(UndefinedIsNotEnumerable) {
2460 v8::HandleScope scope(env->GetIsolate());
2461 v8::Handle<Value> result = Script::Compile(v8_str(
2462 "this.propertyIsEnumerable(undefined)"))->Run();
2463 CHECK(result->IsFalse());
2467 v8::Handle<Script> call_recursively_script;
2468 static const int kTargetRecursionDepth = 200; // near maximum
2471 static void CallScriptRecursivelyCall(
2472 const v8::FunctionCallbackInfo<v8::Value>& args) {
2473 ApiTestFuzzer::Fuzz();
2474 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2475 if (depth == kTargetRecursionDepth) return;
2476 args.This()->Set(v8_str("depth"),
2477 v8::Integer::New(args.GetIsolate(), depth + 1));
2478 args.GetReturnValue().Set(call_recursively_script->Run());
2482 static void CallFunctionRecursivelyCall(
2483 const v8::FunctionCallbackInfo<v8::Value>& args) {
2484 ApiTestFuzzer::Fuzz();
2485 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2486 if (depth == kTargetRecursionDepth) {
2487 printf("[depth = %d]\n", depth);
2490 args.This()->Set(v8_str("depth"),
2491 v8::Integer::New(args.GetIsolate(), depth + 1));
2492 v8::Handle<Value> function =
2493 args.This()->Get(v8_str("callFunctionRecursively"));
2494 args.GetReturnValue().Set(
2495 function.As<Function>()->Call(args.This(), 0, NULL));
2499 THREADED_TEST(DeepCrossLanguageRecursion) {
2500 v8::Isolate* isolate = CcTest::isolate();
2501 v8::HandleScope scope(isolate);
2502 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2503 global->Set(v8_str("callScriptRecursively"),
2504 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2505 global->Set(v8_str("callFunctionRecursively"),
2506 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2507 LocalContext env(NULL, global);
2509 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2510 call_recursively_script = v8_compile("callScriptRecursively()");
2511 call_recursively_script->Run();
2512 call_recursively_script = v8::Handle<Script>();
2514 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2515 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2519 static void ThrowingPropertyHandlerGet(
2521 const v8::PropertyCallbackInfo<v8::Value>& info) {
2522 ApiTestFuzzer::Fuzz();
2523 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2527 static void ThrowingPropertyHandlerSet(
2530 const v8::PropertyCallbackInfo<v8::Value>& info) {
2531 info.GetIsolate()->ThrowException(key);
2532 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2536 THREADED_TEST(CallbackExceptionRegression) {
2537 v8::Isolate* isolate = CcTest::isolate();
2538 v8::HandleScope scope(isolate);
2539 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2540 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2541 ThrowingPropertyHandlerSet);
2543 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2544 v8::Handle<Value> otto = Script::Compile(v8_str(
2545 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2546 CHECK_EQ(v8_str("otto"), otto);
2547 v8::Handle<Value> netto = Script::Compile(v8_str(
2548 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2549 CHECK_EQ(v8_str("netto"), netto);
2553 THREADED_TEST(FunctionPrototype) {
2554 v8::Isolate* isolate = CcTest::isolate();
2555 v8::HandleScope scope(isolate);
2556 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2557 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2559 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2560 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2561 CHECK_EQ(script->Run()->Int32Value(), 321);
2565 THREADED_TEST(InternalFields) {
2567 v8::Isolate* isolate = env->GetIsolate();
2568 v8::HandleScope scope(isolate);
2570 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2571 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2572 instance_templ->SetInternalFieldCount(1);
2573 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2574 CHECK_EQ(1, obj->InternalFieldCount());
2575 CHECK(obj->GetInternalField(0)->IsUndefined());
2576 obj->SetInternalField(0, v8_num(17));
2577 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2581 THREADED_TEST(GlobalObjectInternalFields) {
2582 v8::Isolate* isolate = CcTest::isolate();
2583 v8::HandleScope scope(isolate);
2584 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2585 global_template->SetInternalFieldCount(1);
2586 LocalContext env(NULL, global_template);
2587 v8::Handle<v8::Object> global_proxy = env->Global();
2588 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2589 CHECK_EQ(1, global->InternalFieldCount());
2590 CHECK(global->GetInternalField(0)->IsUndefined());
2591 global->SetInternalField(0, v8_num(17));
2592 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2596 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2598 v8::HandleScope scope(CcTest::isolate());
2600 v8::Local<v8::Object> global = env->Global();
2601 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2602 CHECK(global->HasRealIndexedProperty(0));
2606 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2608 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2609 obj->SetAlignedPointerInInternalField(0, value);
2610 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2611 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2615 THREADED_TEST(InternalFieldsAlignedPointers) {
2617 v8::Isolate* isolate = env->GetIsolate();
2618 v8::HandleScope scope(isolate);
2620 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2621 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2622 instance_templ->SetInternalFieldCount(1);
2623 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2624 CHECK_EQ(1, obj->InternalFieldCount());
2626 CheckAlignedPointerInInternalField(obj, NULL);
2628 int* heap_allocated = new int[100];
2629 CheckAlignedPointerInInternalField(obj, heap_allocated);
2630 delete[] heap_allocated;
2632 int stack_allocated[100];
2633 CheckAlignedPointerInInternalField(obj, stack_allocated);
2635 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2636 CheckAlignedPointerInInternalField(obj, huge);
2640 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2643 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2644 (*env)->SetAlignedPointerInEmbedderData(index, value);
2645 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2646 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2650 static void* AlignedTestPointer(int i) {
2651 return reinterpret_cast<void*>(i * 1234);
2655 THREADED_TEST(EmbedderDataAlignedPointers) {
2657 v8::HandleScope scope(env->GetIsolate());
2659 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2661 int* heap_allocated = new int[100];
2662 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2663 delete[] heap_allocated;
2665 int stack_allocated[100];
2666 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2668 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2669 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2671 // Test growing of the embedder data's backing store.
2672 for (int i = 0; i < 100; i++) {
2673 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2675 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2676 for (int i = 0; i < 100; i++) {
2677 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2682 static void CheckEmbedderData(LocalContext* env,
2684 v8::Handle<Value> data) {
2685 (*env)->SetEmbedderData(index, data);
2686 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2690 THREADED_TEST(EmbedderData) {
2692 v8::Isolate* isolate = env->GetIsolate();
2693 v8::HandleScope scope(isolate);
2697 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2698 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2699 "over the lazy dog."));
2700 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2701 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2705 THREADED_TEST(IdentityHash) {
2707 v8::Isolate* isolate = env->GetIsolate();
2708 v8::HandleScope scope(isolate);
2710 // Ensure that the test starts with an fresh heap to test whether the hash
2711 // code is based on the address.
2712 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2713 Local<v8::Object> obj = v8::Object::New(isolate);
2714 int hash = obj->GetIdentityHash();
2715 int hash1 = obj->GetIdentityHash();
2716 CHECK_EQ(hash, hash1);
2717 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2718 // Since the identity hash is essentially a random number two consecutive
2719 // objects should not be assigned the same hash code. If the test below fails
2720 // the random number generator should be evaluated.
2721 CHECK_NE(hash, hash2);
2722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2723 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2724 // Make sure that the identity hash is not based on the initial address of
2725 // the object alone. If the test below fails the random number generator
2726 // should be evaluated.
2727 CHECK_NE(hash, hash3);
2728 int hash4 = obj->GetIdentityHash();
2729 CHECK_EQ(hash, hash4);
2731 // Check identity hashes behaviour in the presence of JS accessors.
2732 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2734 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2735 Local<v8::Object> o1 = v8::Object::New(isolate);
2736 Local<v8::Object> o2 = v8::Object::New(isolate);
2737 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2741 "function cnst() { return 42; };\n"
2742 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2743 Local<v8::Object> o1 = v8::Object::New(isolate);
2744 Local<v8::Object> o2 = v8::Object::New(isolate);
2745 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2750 THREADED_TEST(SymbolProperties) {
2751 i::FLAG_harmony_symbols = true;
2754 v8::Isolate* isolate = env->GetIsolate();
2755 v8::HandleScope scope(isolate);
2757 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2758 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2759 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2761 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2763 // Check basic symbol functionality.
2764 CHECK(sym1->IsSymbol());
2765 CHECK(sym2->IsSymbol());
2766 CHECK(!obj->IsSymbol());
2768 CHECK(sym1->Equals(sym1));
2769 CHECK(sym2->Equals(sym2));
2770 CHECK(!sym1->Equals(sym2));
2771 CHECK(!sym2->Equals(sym1));
2772 CHECK(sym1->StrictEquals(sym1));
2773 CHECK(sym2->StrictEquals(sym2));
2774 CHECK(!sym1->StrictEquals(sym2));
2775 CHECK(!sym2->StrictEquals(sym1));
2777 CHECK(sym2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-symbol")));
2779 v8::Local<v8::Value> sym_val = sym2;
2780 CHECK(sym_val->IsSymbol());
2781 CHECK(sym_val->Equals(sym2));
2782 CHECK(sym_val->StrictEquals(sym2));
2783 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2785 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2786 CHECK(sym_obj->IsSymbolObject());
2787 CHECK(!sym2->IsSymbolObject());
2788 CHECK(!obj->IsSymbolObject());
2789 CHECK(sym_obj->Equals(sym2));
2790 CHECK(!sym_obj->StrictEquals(sym2));
2791 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2792 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2794 // Make sure delete of a non-existent symbol property works.
2795 CHECK(obj->Delete(sym1));
2796 CHECK(!obj->Has(sym1));
2798 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2799 CHECK(obj->Has(sym1));
2800 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2801 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2802 CHECK(obj->Has(sym1));
2803 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2804 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2806 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2807 int num_props = obj->GetPropertyNames()->Length();
2808 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2809 v8::Integer::New(isolate, 20)));
2810 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2811 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2813 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2815 // Add another property and delete it afterwards to force the object in
2817 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2818 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2820 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2821 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2823 CHECK(obj->Has(sym1));
2824 CHECK(obj->Has(sym2));
2825 CHECK(obj->Delete(sym2));
2826 CHECK(obj->Has(sym1));
2827 CHECK(!obj->Has(sym2));
2828 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2829 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2831 // Symbol properties are inherited.
2832 v8::Local<v8::Object> child = v8::Object::New(isolate);
2833 child->SetPrototype(obj);
2834 CHECK(child->Has(sym1));
2835 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2836 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2840 THREADED_TEST(PrivateProperties) {
2842 v8::Isolate* isolate = env->GetIsolate();
2843 v8::HandleScope scope(isolate);
2845 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2846 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2847 v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private");
2849 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2851 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2853 // Make sure delete of a non-existent private symbol property works.
2854 CHECK(obj->DeletePrivate(priv1));
2855 CHECK(!obj->HasPrivate(priv1));
2857 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2858 CHECK(obj->HasPrivate(priv1));
2859 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2860 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2861 CHECK(obj->HasPrivate(priv1));
2862 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2864 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2865 int num_props = obj->GetPropertyNames()->Length();
2866 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2867 v8::Integer::New(isolate, 20)));
2868 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2869 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2871 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2873 // Add another property and delete it afterwards to force the object in
2875 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2876 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2877 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2878 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2879 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2881 CHECK(obj->HasPrivate(priv1));
2882 CHECK(obj->HasPrivate(priv2));
2883 CHECK(obj->DeletePrivate(priv2));
2884 CHECK(obj->HasPrivate(priv1));
2885 CHECK(!obj->HasPrivate(priv2));
2886 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2887 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2889 // Private properties are inherited (for the time being).
2890 v8::Local<v8::Object> child = v8::Object::New(isolate);
2891 child->SetPrototype(obj);
2892 CHECK(child->HasPrivate(priv1));
2893 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2894 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2898 class ScopedArrayBufferContents {
2900 explicit ScopedArrayBufferContents(
2901 const v8::ArrayBuffer::Contents& contents)
2902 : contents_(contents) {}
2903 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2904 void* Data() const { return contents_.Data(); }
2905 size_t ByteLength() const { return contents_.ByteLength(); }
2907 const v8::ArrayBuffer::Contents contents_;
2910 template <typename T>
2911 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2912 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2913 for (int i = 0; i < value->InternalFieldCount(); i++) {
2914 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2919 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2921 v8::Isolate* isolate = env->GetIsolate();
2922 v8::HandleScope handle_scope(isolate);
2924 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2925 CheckInternalFieldsAreZero(ab);
2926 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2927 CHECK(!ab->IsExternal());
2928 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2930 ScopedArrayBufferContents ab_contents(ab->Externalize());
2931 CHECK(ab->IsExternal());
2933 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2934 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2935 ASSERT(data != NULL);
2936 env->Global()->Set(v8_str("ab"), ab);
2938 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2939 CHECK_EQ(1024, result->Int32Value());
2941 result = CompileRun("var u8 = new Uint8Array(ab);"
2945 CHECK_EQ(1024, result->Int32Value());
2946 CHECK_EQ(0xFF, data[0]);
2947 CHECK_EQ(0xAA, data[1]);
2950 result = CompileRun("u8[0] + u8[1]");
2951 CHECK_EQ(0xDD, result->Int32Value());
2955 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2957 v8::Isolate* isolate = env->GetIsolate();
2958 v8::HandleScope handle_scope(isolate);
2961 v8::Local<v8::Value> result =
2962 CompileRun("var ab1 = new ArrayBuffer(2);"
2963 "var u8_a = new Uint8Array(ab1);"
2965 "u8_a[1] = 0xFF; u8_a.buffer");
2966 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2967 CheckInternalFieldsAreZero(ab1);
2968 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2969 CHECK(!ab1->IsExternal());
2970 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2971 CHECK(ab1->IsExternal());
2973 result = CompileRun("ab1.byteLength");
2974 CHECK_EQ(2, result->Int32Value());
2975 result = CompileRun("u8_a[0]");
2976 CHECK_EQ(0xAA, result->Int32Value());
2977 result = CompileRun("u8_a[1]");
2978 CHECK_EQ(0xFF, result->Int32Value());
2979 result = CompileRun("var u8_b = new Uint8Array(ab1);"
2982 CHECK_EQ(0xBB, result->Int32Value());
2983 result = CompileRun("u8_b[1]");
2984 CHECK_EQ(0xFF, result->Int32Value());
2986 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2987 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2988 CHECK_EQ(0xBB, ab1_data[0]);
2989 CHECK_EQ(0xFF, ab1_data[1]);
2992 result = CompileRun("u8_a[0] + u8_a[1]");
2993 CHECK_EQ(0xDD, result->Int32Value());
2997 THREADED_TEST(ArrayBuffer_External) {
2999 v8::Isolate* isolate = env->GetIsolate();
3000 v8::HandleScope handle_scope(isolate);
3002 i::ScopedVector<uint8_t> my_data(100);
3003 memset(my_data.start(), 0, 100);
3004 Local<v8::ArrayBuffer> ab3 =
3005 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3006 CheckInternalFieldsAreZero(ab3);
3007 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3008 CHECK(ab3->IsExternal());
3010 env->Global()->Set(v8_str("ab3"), ab3);
3012 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3013 CHECK_EQ(100, result->Int32Value());
3015 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3019 CHECK_EQ(100, result->Int32Value());
3020 CHECK_EQ(0xBB, my_data[0]);
3021 CHECK_EQ(0xCC, my_data[1]);
3024 result = CompileRun("u8_b[0] + u8_b[1]");
3025 CHECK_EQ(0xDD, result->Int32Value());
3029 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3030 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3031 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3035 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3036 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3037 CHECK_EQ(0, static_cast<int>(ta->Length()));
3038 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3042 static void CheckIsTypedArrayVarNeutered(const char* name) {
3043 i::ScopedVector<char> source(1024);
3044 i::OS::SNPrintF(source,
3045 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3047 CHECK(CompileRun(source.start())->IsTrue());
3048 v8::Handle<v8::TypedArray> ta =
3049 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3050 CheckIsNeutered(ta);
3054 template <typename TypedArray, int kElementSize>
3055 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3058 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3059 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3060 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3061 CHECK_EQ(length, static_cast<int>(ta->Length()));
3062 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3067 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3069 v8::Isolate* isolate = env->GetIsolate();
3070 v8::HandleScope handle_scope(isolate);
3072 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3074 v8::Handle<v8::Uint8Array> u8a =
3075 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3076 v8::Handle<v8::Uint8ClampedArray> u8c =
3077 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3078 v8::Handle<v8::Int8Array> i8a =
3079 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3081 v8::Handle<v8::Uint16Array> u16a =
3082 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3083 v8::Handle<v8::Int16Array> i16a =
3084 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3086 v8::Handle<v8::Uint32Array> u32a =
3087 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3088 v8::Handle<v8::Int32Array> i32a =
3089 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3091 v8::Handle<v8::Float32Array> f32a =
3092 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3093 v8::Handle<v8::Float64Array> f64a =
3094 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3096 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3097 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3098 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3099 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3101 ScopedArrayBufferContents contents(buffer->Externalize());
3103 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3104 CheckIsNeutered(u8a);
3105 CheckIsNeutered(u8c);
3106 CheckIsNeutered(i8a);
3107 CheckIsNeutered(u16a);
3108 CheckIsNeutered(i16a);
3109 CheckIsNeutered(u32a);
3110 CheckIsNeutered(i32a);
3111 CheckIsNeutered(f32a);
3112 CheckIsNeutered(f64a);
3113 CheckDataViewIsNeutered(dv);
3117 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3119 v8::Isolate* isolate = env->GetIsolate();
3120 v8::HandleScope handle_scope(isolate);
3123 "var ab = new ArrayBuffer(1024);"
3124 "var u8a = new Uint8Array(ab, 1, 1023);"
3125 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3126 "var i8a = new Int8Array(ab, 1, 1023);"
3127 "var u16a = new Uint16Array(ab, 2, 511);"
3128 "var i16a = new Int16Array(ab, 2, 511);"
3129 "var u32a = new Uint32Array(ab, 4, 255);"
3130 "var i32a = new Int32Array(ab, 4, 255);"
3131 "var f32a = new Float32Array(ab, 4, 255);"
3132 "var f64a = new Float64Array(ab, 8, 127);"
3133 "var dv = new DataView(ab, 1, 1023);");
3135 v8::Handle<v8::ArrayBuffer> ab =
3136 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3138 v8::Handle<v8::DataView> dv =
3139 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3141 ScopedArrayBufferContents contents(ab->Externalize());
3143 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3144 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3146 CheckIsTypedArrayVarNeutered("u8a");
3147 CheckIsTypedArrayVarNeutered("u8c");
3148 CheckIsTypedArrayVarNeutered("i8a");
3149 CheckIsTypedArrayVarNeutered("u16a");
3150 CheckIsTypedArrayVarNeutered("i16a");
3151 CheckIsTypedArrayVarNeutered("u32a");
3152 CheckIsTypedArrayVarNeutered("i32a");
3153 CheckIsTypedArrayVarNeutered("f32a");
3154 CheckIsTypedArrayVarNeutered("f64a");
3156 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3157 CheckDataViewIsNeutered(dv);
3162 THREADED_TEST(HiddenProperties) {
3164 v8::Isolate* isolate = env->GetIsolate();
3165 v8::HandleScope scope(isolate);
3167 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3168 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3169 v8::Local<v8::String> empty = v8_str("");
3170 v8::Local<v8::String> prop_name = v8_str("prop_name");
3172 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3174 // Make sure delete of a non-existent hidden value works
3175 CHECK(obj->DeleteHiddenValue(key));
3177 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3178 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3179 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3180 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3182 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3184 // Make sure we do not find the hidden property.
3185 CHECK(!obj->Has(empty));
3186 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3187 CHECK(obj->Get(empty)->IsUndefined());
3188 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3189 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3190 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3191 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3193 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3195 // Add another property and delete it afterwards to force the object in
3197 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3198 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3199 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3200 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3201 CHECK(obj->Delete(prop_name));
3202 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3204 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3206 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3207 CHECK(obj->GetHiddenValue(key).IsEmpty());
3209 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3210 CHECK(obj->DeleteHiddenValue(key));
3211 CHECK(obj->GetHiddenValue(key).IsEmpty());
3215 THREADED_TEST(Regress97784) {
3216 // Regression test for crbug.com/97784
3217 // Messing with the Object.prototype should not have effect on
3218 // hidden properties.
3220 v8::HandleScope scope(env->GetIsolate());
3222 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3223 v8::Local<v8::String> key = v8_str("hidden");
3226 "set_called = false;"
3227 "Object.defineProperty("
3228 " Object.prototype,"
3230 " {get: function() { return 45; },"
3231 " set: function() { set_called = true; }})");
3233 CHECK(obj->GetHiddenValue(key).IsEmpty());
3234 // Make sure that the getter and setter from Object.prototype is not invoked.
3235 // If it did we would have full access to the hidden properties in
3237 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3238 ExpectFalse("set_called");
3239 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3243 static bool interceptor_for_hidden_properties_called;
3244 static void InterceptorForHiddenProperties(
3245 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3246 interceptor_for_hidden_properties_called = true;
3250 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3251 LocalContext context;
3252 v8::Isolate* isolate = context->GetIsolate();
3253 v8::HandleScope scope(isolate);
3255 interceptor_for_hidden_properties_called = false;
3257 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3259 // Associate an interceptor with an object and start setting hidden values.
3260 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3261 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3262 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3263 Local<v8::Function> function = fun_templ->GetFunction();
3264 Local<v8::Object> obj = function->NewInstance();
3265 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3266 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3267 CHECK(!interceptor_for_hidden_properties_called);
3271 THREADED_TEST(External) {
3272 v8::HandleScope scope(CcTest::isolate());
3274 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3276 env->Global()->Set(v8_str("ext"), ext);
3277 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3278 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3279 int* ptr = static_cast<int*>(reext->Value());
3284 // Make sure unaligned pointers are wrapped properly.
3285 char* data = i::StrDup("0123456789");
3286 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3287 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3288 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3289 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3291 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3292 CHECK_EQ('0', *char_ptr);
3293 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3294 CHECK_EQ('1', *char_ptr);
3295 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3296 CHECK_EQ('2', *char_ptr);
3297 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3298 CHECK_EQ('3', *char_ptr);
3299 i::DeleteArray(data);
3303 THREADED_TEST(GlobalHandle) {
3304 v8::Isolate* isolate = CcTest::isolate();
3305 v8::Persistent<String> global;
3307 v8::HandleScope scope(isolate);
3308 global.Reset(isolate, v8_str("str"));
3311 v8::HandleScope scope(isolate);
3312 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3316 v8::HandleScope scope(isolate);
3317 global.Reset(isolate, v8_str("str"));
3320 v8::HandleScope scope(isolate);
3321 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3327 THREADED_TEST(ResettingGlobalHandle) {
3328 v8::Isolate* isolate = CcTest::isolate();
3329 v8::Persistent<String> global;
3331 v8::HandleScope scope(isolate);
3332 global.Reset(isolate, v8_str("str"));
3334 v8::internal::GlobalHandles* global_handles =
3335 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3336 int initial_handle_count = global_handles->global_handles_count();
3338 v8::HandleScope scope(isolate);
3339 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3342 v8::HandleScope scope(isolate);
3343 global.Reset(isolate, v8_str("longer"));
3345 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3347 v8::HandleScope scope(isolate);
3348 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3351 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3355 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3356 v8::Isolate* isolate = CcTest::isolate();
3357 v8::Persistent<String> global;
3359 v8::HandleScope scope(isolate);
3360 global.Reset(isolate, v8_str("str"));
3362 v8::internal::GlobalHandles* global_handles =
3363 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3364 int initial_handle_count = global_handles->global_handles_count();
3366 v8::HandleScope scope(isolate);
3367 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3370 v8::HandleScope scope(isolate);
3371 Local<String> empty;
3372 global.Reset(isolate, empty);
3374 CHECK(global.IsEmpty());
3375 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3380 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3381 return unique.Pass();
3386 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3387 const v8::Persistent<T> & global) {
3388 v8::UniquePersistent<String> unique(isolate, global);
3389 return unique.Pass();
3393 THREADED_TEST(UniquePersistent) {
3394 v8::Isolate* isolate = CcTest::isolate();
3395 v8::Persistent<String> global;
3397 v8::HandleScope scope(isolate);
3398 global.Reset(isolate, v8_str("str"));
3400 v8::internal::GlobalHandles* global_handles =
3401 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3402 int initial_handle_count = global_handles->global_handles_count();
3404 v8::UniquePersistent<String> unique(isolate, global);
3405 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3406 // Test assignment via Pass
3408 v8::UniquePersistent<String> copy = unique.Pass();
3409 CHECK(unique.IsEmpty());
3410 CHECK(copy == global);
3411 CHECK_EQ(initial_handle_count + 1,
3412 global_handles->global_handles_count());
3413 unique = copy.Pass();
3415 // Test ctor via Pass
3417 v8::UniquePersistent<String> copy(unique.Pass());
3418 CHECK(unique.IsEmpty());
3419 CHECK(copy == global);
3420 CHECK_EQ(initial_handle_count + 1,
3421 global_handles->global_handles_count());
3422 unique = copy.Pass();
3424 // Test pass through function call
3426 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3427 CHECK(unique.IsEmpty());
3428 CHECK(copy == global);
3429 CHECK_EQ(initial_handle_count + 1,
3430 global_handles->global_handles_count());
3431 unique = copy.Pass();
3433 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3435 // Test pass from function call
3437 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3438 CHECK(unique == global);
3439 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3441 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3446 THREADED_TEST(GlobalHandleUpcast) {
3447 v8::Isolate* isolate = CcTest::isolate();
3448 v8::HandleScope scope(isolate);
3449 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3450 v8::Persistent<String> global_string(isolate, local);
3451 v8::Persistent<Value>& global_value =
3452 v8::Persistent<Value>::Cast(global_string);
3453 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3454 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3455 global_string.Reset();
3459 THREADED_TEST(HandleEquality) {
3460 v8::Isolate* isolate = CcTest::isolate();
3461 v8::Persistent<String> global1;
3462 v8::Persistent<String> global2;
3464 v8::HandleScope scope(isolate);
3465 global1.Reset(isolate, v8_str("str"));
3466 global2.Reset(isolate, v8_str("str2"));
3468 CHECK_EQ(global1 == global1, true);
3469 CHECK_EQ(global1 != global1, false);
3471 v8::HandleScope scope(isolate);
3472 Local<String> local1 = Local<String>::New(isolate, global1);
3473 Local<String> local2 = Local<String>::New(isolate, global2);
3475 CHECK_EQ(global1 == local1, true);
3476 CHECK_EQ(global1 != local1, false);
3477 CHECK_EQ(local1 == global1, true);
3478 CHECK_EQ(local1 != global1, false);
3480 CHECK_EQ(global1 == local2, false);
3481 CHECK_EQ(global1 != local2, true);
3482 CHECK_EQ(local2 == global1, false);
3483 CHECK_EQ(local2 != global1, true);
3485 CHECK_EQ(local1 == local2, false);
3486 CHECK_EQ(local1 != local2, true);
3488 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3489 CHECK_EQ(local1 == anotherLocal1, true);
3490 CHECK_EQ(local1 != anotherLocal1, false);
3497 THREADED_TEST(LocalHandle) {
3498 v8::HandleScope scope(CcTest::isolate());
3499 v8::Local<String> local =
3500 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3501 CHECK_EQ(local->Length(), 3);
3505 class WeakCallCounter {
3507 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3508 int id() { return id_; }
3509 void increment() { number_of_weak_calls_++; }
3510 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3513 int number_of_weak_calls_;
3517 template<typename T>
3518 struct WeakCallCounterAndPersistent {
3519 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3520 : counter(counter) {}
3521 WeakCallCounter* counter;
3522 v8::Persistent<T> handle;
3526 template <typename T>
3527 static void WeakPointerCallback(
3528 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3529 CHECK_EQ(1234, data.GetParameter()->counter->id());
3530 data.GetParameter()->counter->increment();
3531 data.GetParameter()->handle.Reset();
3535 template<typename T>
3536 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3537 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3541 THREADED_TEST(ApiObjectGroups) {
3543 v8::Isolate* iso = env->GetIsolate();
3544 HandleScope scope(iso);
3546 WeakCallCounter counter(1234);
3548 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3549 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3550 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3551 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3552 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3553 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3556 HandleScope scope(iso);
3557 g1s1.handle.Reset(iso, Object::New(iso));
3558 g1s2.handle.Reset(iso, Object::New(iso));
3559 g1c1.handle.Reset(iso, Object::New(iso));
3560 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3561 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3562 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3564 g2s1.handle.Reset(iso, Object::New(iso));
3565 g2s2.handle.Reset(iso, Object::New(iso));
3566 g2c1.handle.Reset(iso, Object::New(iso));
3567 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3568 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3569 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3572 WeakCallCounterAndPersistent<Value> root(&counter);
3573 root.handle.Reset(iso, g1s1.handle); // make a root.
3575 // Connect group 1 and 2, make a cycle.
3577 HandleScope scope(iso);
3578 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3579 Set(0, Local<Value>::New(iso, g2s2.handle)));
3580 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3581 Set(0, Local<Value>::New(iso, g1s1.handle)));
3585 UniqueId id1 = MakeUniqueId(g1s1.handle);
3586 UniqueId id2 = MakeUniqueId(g2s2.handle);
3587 iso->SetObjectGroupId(g1s1.handle, id1);
3588 iso->SetObjectGroupId(g1s2.handle, id1);
3589 iso->SetReferenceFromGroup(id1, g1c1.handle);
3590 iso->SetObjectGroupId(g2s1.handle, id2);
3591 iso->SetObjectGroupId(g2s2.handle, id2);
3592 iso->SetReferenceFromGroup(id2, g2c1.handle);
3594 // Do a single full GC, ensure incremental marking is stopped.
3595 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3597 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3599 // All object should be alive.
3600 CHECK_EQ(0, counter.NumberOfWeakCalls());
3603 root.handle.SetWeak(&root, &WeakPointerCallback);
3604 // But make children strong roots---all the objects (except for children)
3605 // should be collectable now.
3606 g1c1.handle.ClearWeak();
3607 g2c1.handle.ClearWeak();
3609 // Groups are deleted, rebuild groups.
3611 UniqueId id1 = MakeUniqueId(g1s1.handle);
3612 UniqueId id2 = MakeUniqueId(g2s2.handle);
3613 iso->SetObjectGroupId(g1s1.handle, id1);
3614 iso->SetObjectGroupId(g1s2.handle, id1);
3615 iso->SetReferenceFromGroup(id1, g1c1.handle);
3616 iso->SetObjectGroupId(g2s1.handle, id2);
3617 iso->SetObjectGroupId(g2s2.handle, id2);
3618 iso->SetReferenceFromGroup(id2, g2c1.handle);
3621 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3623 // All objects should be gone. 5 global handles in total.
3624 CHECK_EQ(5, counter.NumberOfWeakCalls());
3626 // And now make children weak again and collect them.
3627 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3628 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3630 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3631 CHECK_EQ(7, counter.NumberOfWeakCalls());
3635 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3637 v8::Isolate* iso = env->GetIsolate();
3638 HandleScope scope(iso);
3640 WeakCallCounter counter(1234);
3642 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3643 WeakCallCounterAndPersistent<String> g1s2(&counter);
3644 WeakCallCounterAndPersistent<String> g1c1(&counter);
3645 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3646 WeakCallCounterAndPersistent<String> g2s2(&counter);
3647 WeakCallCounterAndPersistent<String> g2c1(&counter);
3650 HandleScope scope(iso);
3651 g1s1.handle.Reset(iso, Object::New(iso));
3652 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3653 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3654 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3655 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3656 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3658 g2s1.handle.Reset(iso, Object::New(iso));
3659 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3660 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3661 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3662 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3663 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3666 WeakCallCounterAndPersistent<Value> root(&counter);
3667 root.handle.Reset(iso, g1s1.handle); // make a root.
3669 // Connect group 1 and 2, make a cycle.
3671 HandleScope scope(iso);
3672 CHECK(Local<Object>::New(iso, g1s1.handle)
3673 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3674 CHECK(Local<Object>::New(iso, g2s1.handle)
3675 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3679 UniqueId id1 = MakeUniqueId(g1s1.handle);
3680 UniqueId id2 = MakeUniqueId(g2s2.handle);
3681 iso->SetObjectGroupId(g1s1.handle, id1);
3682 iso->SetObjectGroupId(g1s2.handle, id1);
3683 iso->SetReference(g1s1.handle, g1c1.handle);
3684 iso->SetObjectGroupId(g2s1.handle, id2);
3685 iso->SetObjectGroupId(g2s2.handle, id2);
3686 iso->SetReferenceFromGroup(id2, g2c1.handle);
3688 // Do a single full GC, ensure incremental marking is stopped.
3689 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3691 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3693 // All object should be alive.
3694 CHECK_EQ(0, counter.NumberOfWeakCalls());
3697 root.handle.SetWeak(&root, &WeakPointerCallback);
3698 // But make children strong roots---all the objects (except for children)
3699 // should be collectable now.
3700 g1c1.handle.ClearWeak();
3701 g2c1.handle.ClearWeak();
3703 // Groups are deleted, rebuild groups.
3705 UniqueId id1 = MakeUniqueId(g1s1.handle);
3706 UniqueId id2 = MakeUniqueId(g2s2.handle);
3707 iso->SetObjectGroupId(g1s1.handle, id1);
3708 iso->SetObjectGroupId(g1s2.handle, id1);
3709 iso->SetReference(g1s1.handle, g1c1.handle);
3710 iso->SetObjectGroupId(g2s1.handle, id2);
3711 iso->SetObjectGroupId(g2s2.handle, id2);
3712 iso->SetReferenceFromGroup(id2, g2c1.handle);
3715 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3717 // All objects should be gone. 5 global handles in total.
3718 CHECK_EQ(5, counter.NumberOfWeakCalls());
3720 // And now make children weak again and collect them.
3721 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3722 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3724 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3725 CHECK_EQ(7, counter.NumberOfWeakCalls());
3729 THREADED_TEST(ApiObjectGroupsCycle) {
3731 v8::Isolate* iso = env->GetIsolate();
3732 HandleScope scope(iso);
3734 WeakCallCounter counter(1234);
3736 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3737 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3738 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3739 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3740 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3741 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3742 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3743 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3746 HandleScope scope(iso);
3747 g1s1.handle.Reset(iso, Object::New(iso));
3748 g1s2.handle.Reset(iso, Object::New(iso));
3749 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3750 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3751 CHECK(g1s1.handle.IsWeak());
3752 CHECK(g1s2.handle.IsWeak());
3754 g2s1.handle.Reset(iso, Object::New(iso));
3755 g2s2.handle.Reset(iso, Object::New(iso));
3756 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3757 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3758 CHECK(g2s1.handle.IsWeak());
3759 CHECK(g2s2.handle.IsWeak());
3761 g3s1.handle.Reset(iso, Object::New(iso));
3762 g3s2.handle.Reset(iso, Object::New(iso));
3763 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3764 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3765 CHECK(g3s1.handle.IsWeak());
3766 CHECK(g3s2.handle.IsWeak());
3768 g4s1.handle.Reset(iso, Object::New(iso));
3769 g4s2.handle.Reset(iso, Object::New(iso));
3770 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3771 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3772 CHECK(g4s1.handle.IsWeak());
3773 CHECK(g4s2.handle.IsWeak());
3776 WeakCallCounterAndPersistent<Value> root(&counter);
3777 root.handle.Reset(iso, g1s1.handle); // make a root.
3779 // Connect groups. We're building the following cycle:
3780 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3783 UniqueId id1 = MakeUniqueId(g1s1.handle);
3784 UniqueId id2 = MakeUniqueId(g2s1.handle);
3785 UniqueId id3 = MakeUniqueId(g3s1.handle);
3786 UniqueId id4 = MakeUniqueId(g4s1.handle);
3787 iso->SetObjectGroupId(g1s1.handle, id1);
3788 iso->SetObjectGroupId(g1s2.handle, id1);
3789 iso->SetReferenceFromGroup(id1, g2s1.handle);
3790 iso->SetObjectGroupId(g2s1.handle, id2);
3791 iso->SetObjectGroupId(g2s2.handle, id2);
3792 iso->SetReferenceFromGroup(id2, g3s1.handle);
3793 iso->SetObjectGroupId(g3s1.handle, id3);
3794 iso->SetObjectGroupId(g3s2.handle, id3);
3795 iso->SetReferenceFromGroup(id3, g4s1.handle);
3796 iso->SetObjectGroupId(g4s1.handle, id4);
3797 iso->SetObjectGroupId(g4s2.handle, id4);
3798 iso->SetReferenceFromGroup(id4, g1s1.handle);
3800 // Do a single full GC
3801 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3803 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3805 // All object should be alive.
3806 CHECK_EQ(0, counter.NumberOfWeakCalls());
3809 root.handle.SetWeak(&root, &WeakPointerCallback);
3811 // Groups are deleted, rebuild groups.
3813 UniqueId id1 = MakeUniqueId(g1s1.handle);
3814 UniqueId id2 = MakeUniqueId(g2s1.handle);
3815 UniqueId id3 = MakeUniqueId(g3s1.handle);
3816 UniqueId id4 = MakeUniqueId(g4s1.handle);
3817 iso->SetObjectGroupId(g1s1.handle, id1);
3818 iso->SetObjectGroupId(g1s2.handle, id1);
3819 iso->SetReferenceFromGroup(id1, g2s1.handle);
3820 iso->SetObjectGroupId(g2s1.handle, id2);
3821 iso->SetObjectGroupId(g2s2.handle, id2);
3822 iso->SetReferenceFromGroup(id2, g3s1.handle);
3823 iso->SetObjectGroupId(g3s1.handle, id3);
3824 iso->SetObjectGroupId(g3s2.handle, id3);
3825 iso->SetReferenceFromGroup(id3, g4s1.handle);
3826 iso->SetObjectGroupId(g4s1.handle, id4);
3827 iso->SetObjectGroupId(g4s2.handle, id4);
3828 iso->SetReferenceFromGroup(id4, g1s1.handle);
3831 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3833 // All objects should be gone. 9 global handles in total.
3834 CHECK_EQ(9, counter.NumberOfWeakCalls());
3838 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3839 // on the buildbots, so was made non-threaded for the time being.
3840 TEST(ApiObjectGroupsCycleForScavenger) {
3841 i::FLAG_stress_compaction = false;
3842 i::FLAG_gc_global = false;
3844 v8::Isolate* iso = env->GetIsolate();
3845 HandleScope scope(iso);
3847 WeakCallCounter counter(1234);
3849 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3850 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3851 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3852 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3853 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3854 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3857 HandleScope scope(iso);
3858 g1s1.handle.Reset(iso, Object::New(iso));
3859 g1s2.handle.Reset(iso, Object::New(iso));
3860 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3861 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3863 g2s1.handle.Reset(iso, Object::New(iso));
3864 g2s2.handle.Reset(iso, Object::New(iso));
3865 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3866 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3868 g3s1.handle.Reset(iso, Object::New(iso));
3869 g3s2.handle.Reset(iso, Object::New(iso));
3870 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3871 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3875 WeakCallCounterAndPersistent<Value> root(&counter);
3876 root.handle.Reset(iso, g1s1.handle);
3877 root.handle.MarkPartiallyDependent();
3879 // Connect groups. We're building the following cycle:
3880 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3883 HandleScope handle_scope(iso);
3884 g1s1.handle.MarkPartiallyDependent();
3885 g1s2.handle.MarkPartiallyDependent();
3886 g2s1.handle.MarkPartiallyDependent();
3887 g2s2.handle.MarkPartiallyDependent();
3888 g3s1.handle.MarkPartiallyDependent();
3889 g3s2.handle.MarkPartiallyDependent();
3890 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3891 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3892 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3893 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3894 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3895 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3896 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3897 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3898 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3899 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3900 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3901 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3904 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3906 heap->CollectGarbage(i::NEW_SPACE);
3908 // All objects should be alive.
3909 CHECK_EQ(0, counter.NumberOfWeakCalls());
3912 root.handle.SetWeak(&root, &WeakPointerCallback);
3913 root.handle.MarkPartiallyDependent();
3915 // Groups are deleted, rebuild groups.
3917 HandleScope handle_scope(iso);
3918 g1s1.handle.MarkPartiallyDependent();
3919 g1s2.handle.MarkPartiallyDependent();
3920 g2s1.handle.MarkPartiallyDependent();
3921 g2s2.handle.MarkPartiallyDependent();
3922 g3s1.handle.MarkPartiallyDependent();
3923 g3s2.handle.MarkPartiallyDependent();
3924 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3925 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3926 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3927 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3928 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3929 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3930 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3931 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3932 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3933 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3934 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3935 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3938 heap->CollectGarbage(i::NEW_SPACE);
3940 // All objects should be gone. 7 global handles in total.
3941 CHECK_EQ(7, counter.NumberOfWeakCalls());
3945 THREADED_TEST(ScriptException) {
3947 v8::HandleScope scope(env->GetIsolate());
3948 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3949 v8::TryCatch try_catch;
3950 Local<Value> result = script->Run();
3951 CHECK(result.IsEmpty());
3952 CHECK(try_catch.HasCaught());
3953 String::Utf8Value exception_value(try_catch.Exception());
3954 CHECK_EQ(*exception_value, "panama!");
3958 TEST(TryCatchCustomException) {
3960 v8::HandleScope scope(env->GetIsolate());
3961 v8::TryCatch try_catch;
3962 CompileRun("function CustomError() { this.a = 'b'; }"
3963 "(function f() { throw new CustomError(); })();");
3964 CHECK(try_catch.HasCaught());
3965 CHECK(try_catch.Exception()->ToObject()->
3966 Get(v8_str("a"))->Equals(v8_str("b")));
3970 bool message_received;
3973 static void check_message_0(v8::Handle<v8::Message> message,
3974 v8::Handle<Value> data) {
3975 CHECK_EQ(5.76, data->NumberValue());
3976 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3977 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3978 CHECK(!message->IsSharedCrossOrigin());
3979 message_received = true;
3983 THREADED_TEST(MessageHandler0) {
3984 message_received = false;
3985 v8::HandleScope scope(CcTest::isolate());
3986 CHECK(!message_received);
3987 LocalContext context;
3988 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3989 v8::ScriptOrigin origin =
3990 v8::ScriptOrigin(v8_str("6.75"));
3991 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3993 script->SetData(v8_str("7.56"));
3995 CHECK(message_received);
3996 // clear out the message listener
3997 v8::V8::RemoveMessageListeners(check_message_0);
4001 static void check_message_1(v8::Handle<v8::Message> message,
4002 v8::Handle<Value> data) {
4003 CHECK(data->IsNumber());
4004 CHECK_EQ(1337, data->Int32Value());
4005 CHECK(!message->IsSharedCrossOrigin());
4006 message_received = true;
4010 TEST(MessageHandler1) {
4011 message_received = false;
4012 v8::HandleScope scope(CcTest::isolate());
4013 CHECK(!message_received);
4014 v8::V8::AddMessageListener(check_message_1);
4015 LocalContext context;
4016 CompileRun("throw 1337;");
4017 CHECK(message_received);
4018 // clear out the message listener
4019 v8::V8::RemoveMessageListeners(check_message_1);
4023 static void check_message_2(v8::Handle<v8::Message> message,
4024 v8::Handle<Value> data) {
4025 LocalContext context;
4026 CHECK(data->IsObject());
4027 v8::Local<v8::Value> hidden_property =
4028 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4029 CHECK(v8_str("hidden value")->Equals(hidden_property));
4030 CHECK(!message->IsSharedCrossOrigin());
4031 message_received = true;
4035 TEST(MessageHandler2) {
4036 message_received = false;
4037 v8::HandleScope scope(CcTest::isolate());
4038 CHECK(!message_received);
4039 v8::V8::AddMessageListener(check_message_2);
4040 LocalContext context;
4041 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4042 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4043 v8_str("hidden value"));
4044 context->Global()->Set(v8_str("error"), error);
4045 CompileRun("throw error;");
4046 CHECK(message_received);
4047 // clear out the message listener
4048 v8::V8::RemoveMessageListeners(check_message_2);
4052 static void check_message_3(v8::Handle<v8::Message> message,
4053 v8::Handle<Value> data) {
4054 CHECK(message->IsSharedCrossOrigin());
4055 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4056 message_received = true;
4060 TEST(MessageHandler3) {
4061 message_received = false;
4062 v8::Isolate* isolate = CcTest::isolate();
4063 v8::HandleScope scope(isolate);
4064 CHECK(!message_received);
4065 v8::V8::AddMessageListener(check_message_3);
4066 LocalContext context;
4067 v8::ScriptOrigin origin =
4068 v8::ScriptOrigin(v8_str("6.75"),
4069 v8::Integer::New(isolate, 1),
4070 v8::Integer::New(isolate, 2),
4072 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4075 CHECK(message_received);
4076 // clear out the message listener
4077 v8::V8::RemoveMessageListeners(check_message_3);
4081 static void check_message_4(v8::Handle<v8::Message> message,
4082 v8::Handle<Value> data) {
4083 CHECK(!message->IsSharedCrossOrigin());
4084 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4085 message_received = true;
4089 TEST(MessageHandler4) {
4090 message_received = false;
4091 v8::Isolate* isolate = CcTest::isolate();
4092 v8::HandleScope scope(isolate);
4093 CHECK(!message_received);
4094 v8::V8::AddMessageListener(check_message_4);
4095 LocalContext context;
4096 v8::ScriptOrigin origin =
4097 v8::ScriptOrigin(v8_str("6.75"),
4098 v8::Integer::New(isolate, 1),
4099 v8::Integer::New(isolate, 2),
4100 v8::False(isolate));
4101 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4104 CHECK(message_received);
4105 // clear out the message listener
4106 v8::V8::RemoveMessageListeners(check_message_4);
4110 static void check_message_5a(v8::Handle<v8::Message> message,
4111 v8::Handle<Value> data) {
4112 CHECK(message->IsSharedCrossOrigin());
4113 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4114 message_received = true;
4118 static void check_message_5b(v8::Handle<v8::Message> message,
4119 v8::Handle<Value> data) {
4120 CHECK(!message->IsSharedCrossOrigin());
4121 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4122 message_received = true;
4126 TEST(MessageHandler5) {
4127 message_received = false;
4128 v8::Isolate* isolate = CcTest::isolate();
4129 v8::HandleScope scope(isolate);
4130 CHECK(!message_received);
4131 v8::V8::AddMessageListener(check_message_5a);
4132 LocalContext context;
4133 v8::ScriptOrigin origin =
4134 v8::ScriptOrigin(v8_str("6.75"),
4135 v8::Integer::New(isolate, 1),
4136 v8::Integer::New(isolate, 2),
4138 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4141 CHECK(message_received);
4142 // clear out the message listener
4143 v8::V8::RemoveMessageListeners(check_message_5a);
4145 message_received = false;
4146 v8::V8::AddMessageListener(check_message_5b);
4148 v8::ScriptOrigin(v8_str("6.75"),
4149 v8::Integer::New(isolate, 1),
4150 v8::Integer::New(isolate, 2),
4151 v8::False(isolate));
4152 script = Script::Compile(v8_str("throw 'error'"),
4155 CHECK(message_received);
4156 // clear out the message listener
4157 v8::V8::RemoveMessageListeners(check_message_5b);
4161 THREADED_TEST(GetSetProperty) {
4162 LocalContext context;
4163 v8::Isolate* isolate = context->GetIsolate();
4164 v8::HandleScope scope(isolate);
4165 context->Global()->Set(v8_str("foo"), v8_num(14));
4166 context->Global()->Set(v8_str("12"), v8_num(92));
4167 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4168 context->Global()->Set(v8_num(13), v8_num(56));
4169 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
4170 CHECK_EQ(14, foo->Int32Value());
4171 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
4172 CHECK_EQ(92, twelve->Int32Value());
4173 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
4174 CHECK_EQ(32, sixteen->Int32Value());
4175 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
4176 CHECK_EQ(56, thirteen->Int32Value());
4178 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4179 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4180 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4182 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4183 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4184 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4186 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4187 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4188 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4192 THREADED_TEST(PropertyAttributes) {
4193 LocalContext context;
4194 v8::HandleScope scope(context->GetIsolate());
4196 Local<String> prop = v8_str("none");
4197 context->Global()->Set(prop, v8_num(7));
4198 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4200 prop = v8_str("read_only");
4201 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4202 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4203 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4204 Script::Compile(v8_str("read_only = 9"))->Run();
4205 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4206 context->Global()->Set(prop, v8_num(10));
4207 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4209 prop = v8_str("dont_delete");
4210 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4211 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4212 Script::Compile(v8_str("delete dont_delete"))->Run();
4213 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4214 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4216 prop = v8_str("dont_enum");
4217 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4218 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4220 prop = v8_str("absent");
4221 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4222 Local<Value> fake_prop = v8_num(1);
4223 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4226 Local<Value> exception =
4227 CompileRun("({ toString: function() { throw 'exception';} })");
4228 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4229 CHECK(try_catch.HasCaught());
4230 String::Utf8Value exception_value(try_catch.Exception());
4231 CHECK_EQ("exception", *exception_value);
4236 THREADED_TEST(Array) {
4237 LocalContext context;
4238 v8::HandleScope scope(context->GetIsolate());
4239 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4240 CHECK_EQ(0, array->Length());
4241 CHECK(array->Get(0)->IsUndefined());
4242 CHECK(!array->Has(0));
4243 CHECK(array->Get(100)->IsUndefined());
4244 CHECK(!array->Has(100));
4245 array->Set(2, v8_num(7));
4246 CHECK_EQ(3, array->Length());
4247 CHECK(!array->Has(0));
4248 CHECK(!array->Has(1));
4249 CHECK(array->Has(2));
4250 CHECK_EQ(7, array->Get(2)->Int32Value());
4251 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4252 Local<v8::Array> arr = obj.As<v8::Array>();
4253 CHECK_EQ(3, arr->Length());
4254 CHECK_EQ(1, arr->Get(0)->Int32Value());
4255 CHECK_EQ(2, arr->Get(1)->Int32Value());
4256 CHECK_EQ(3, arr->Get(2)->Int32Value());
4257 array = v8::Array::New(context->GetIsolate(), 27);
4258 CHECK_EQ(27, array->Length());
4259 array = v8::Array::New(context->GetIsolate(), -27);
4260 CHECK_EQ(0, array->Length());
4264 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4265 v8::EscapableHandleScope scope(args.GetIsolate());
4266 ApiTestFuzzer::Fuzz();
4267 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4268 for (int i = 0; i < args.Length(); i++)
4269 result->Set(i, args[i]);
4270 args.GetReturnValue().Set(scope.Escape(result));
4274 THREADED_TEST(Vector) {
4275 v8::Isolate* isolate = CcTest::isolate();
4276 v8::HandleScope scope(isolate);
4277 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4278 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4279 LocalContext context(0, global);
4281 const char* fun = "f()";
4282 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4283 CHECK_EQ(0, a0->Length());
4285 const char* fun2 = "f(11)";
4286 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4287 CHECK_EQ(1, a1->Length());
4288 CHECK_EQ(11, a1->Get(0)->Int32Value());
4290 const char* fun3 = "f(12, 13)";
4291 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4292 CHECK_EQ(2, a2->Length());
4293 CHECK_EQ(12, a2->Get(0)->Int32Value());
4294 CHECK_EQ(13, a2->Get(1)->Int32Value());
4296 const char* fun4 = "f(14, 15, 16)";
4297 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4298 CHECK_EQ(3, a3->Length());
4299 CHECK_EQ(14, a3->Get(0)->Int32Value());
4300 CHECK_EQ(15, a3->Get(1)->Int32Value());
4301 CHECK_EQ(16, a3->Get(2)->Int32Value());
4303 const char* fun5 = "f(17, 18, 19, 20)";
4304 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4305 CHECK_EQ(4, a4->Length());
4306 CHECK_EQ(17, a4->Get(0)->Int32Value());
4307 CHECK_EQ(18, a4->Get(1)->Int32Value());
4308 CHECK_EQ(19, a4->Get(2)->Int32Value());
4309 CHECK_EQ(20, a4->Get(3)->Int32Value());
4313 THREADED_TEST(FunctionCall) {
4314 LocalContext context;
4315 v8::Isolate* isolate = context->GetIsolate();
4316 v8::HandleScope scope(isolate);
4320 " for (var i = 0; i < arguments.length; i++) {"
4321 " result.push(arguments[i]);"
4325 "function ReturnThisSloppy() {"
4328 "function ReturnThisStrict() {"
4332 Local<Function> Foo =
4333 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4334 Local<Function> ReturnThisSloppy =
4335 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4336 Local<Function> ReturnThisStrict =
4337 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4339 v8::Handle<Value>* args0 = NULL;
4340 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4341 CHECK_EQ(0, a0->Length());
4343 v8::Handle<Value> args1[] = { v8_num(1.1) };
4344 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4345 CHECK_EQ(1, a1->Length());
4346 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4348 v8::Handle<Value> args2[] = { v8_num(2.2),
4350 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4351 CHECK_EQ(2, a2->Length());
4352 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4353 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4355 v8::Handle<Value> args3[] = { v8_num(4.4),
4358 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4359 CHECK_EQ(3, a3->Length());
4360 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4361 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4362 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4364 v8::Handle<Value> args4[] = { v8_num(7.7),
4368 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4369 CHECK_EQ(4, a4->Length());
4370 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4371 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4372 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4373 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4375 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4376 CHECK(r1->StrictEquals(context->Global()));
4377 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4378 CHECK(r2->StrictEquals(context->Global()));
4379 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4380 CHECK(r3->IsNumberObject());
4381 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4382 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4383 CHECK(r4->IsStringObject());
4384 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4385 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4386 CHECK(r5->IsBooleanObject());
4387 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4389 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4390 CHECK(r6->IsUndefined());
4391 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4392 CHECK(r7->IsNull());
4393 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4394 CHECK(r8->StrictEquals(v8_num(42)));
4395 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4396 CHECK(r9->StrictEquals(v8_str("hello")));
4397 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4398 CHECK(r10->StrictEquals(v8::True(isolate)));
4402 static const char* js_code_causing_out_of_memory =
4403 "var a = new Array(); while(true) a.push(a);";
4406 // These tests run for a long time and prevent us from running tests
4407 // that come after them so they cannot run in parallel.
4409 // It's not possible to read a snapshot into a heap with different dimensions.
4410 if (i::Snapshot::IsEnabled()) return;
4412 static const int K = 1024;
4413 v8::ResourceConstraints constraints;
4414 constraints.set_max_young_space_size(256 * K);
4415 constraints.set_max_old_space_size(5 * K * K);
4416 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4418 // Execute a script that causes out of memory.
4419 LocalContext context;
4420 v8::HandleScope scope(context->GetIsolate());
4421 v8::V8::IgnoreOutOfMemoryException();
4422 Local<Script> script = Script::Compile(String::NewFromUtf8(
4423 context->GetIsolate(), js_code_causing_out_of_memory));
4424 Local<Value> result = script->Run();
4426 // Check for out of memory state.
4427 CHECK(result.IsEmpty());
4428 CHECK(context->HasOutOfMemoryException());
4432 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4433 ApiTestFuzzer::Fuzz();
4435 LocalContext context;
4436 v8::HandleScope scope(context->GetIsolate());
4437 Local<Script> script = Script::Compile(String::NewFromUtf8(
4438 context->GetIsolate(), js_code_causing_out_of_memory));
4439 Local<Value> result = script->Run();
4441 // Check for out of memory state.
4442 CHECK(result.IsEmpty());
4443 CHECK(context->HasOutOfMemoryException());
4445 args.GetReturnValue().Set(result);
4449 TEST(OutOfMemoryNested) {
4450 // It's not possible to read a snapshot into a heap with different dimensions.
4451 if (i::Snapshot::IsEnabled()) return;
4453 static const int K = 1024;
4454 v8::ResourceConstraints constraints;
4455 constraints.set_max_young_space_size(256 * K);
4456 constraints.set_max_old_space_size(5 * K * K);
4457 v8::Isolate* isolate = CcTest::isolate();
4458 v8::SetResourceConstraints(isolate, &constraints);
4460 v8::HandleScope scope(isolate);
4461 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4462 templ->Set(v8_str("ProvokeOutOfMemory"),
4463 v8::FunctionTemplate::New(isolate, ProvokeOutOfMemory));
4464 LocalContext context(0, templ);
4465 v8::V8::IgnoreOutOfMemoryException();
4466 Local<Value> result = CompileRun(
4467 "var thrown = false;"
4469 " ProvokeOutOfMemory();"
4473 // Check for out of memory state.
4474 CHECK(result.IsEmpty());
4475 CHECK(context->HasOutOfMemoryException());
4479 void OOMCallback(const char* location, const char* message) {
4484 TEST(HugeConsStringOutOfMemory) {
4485 // It's not possible to read a snapshot into a heap with different dimensions.
4486 if (i::Snapshot::IsEnabled()) return;
4488 static const int K = 1024;
4489 v8::ResourceConstraints constraints;
4490 constraints.set_max_young_space_size(256 * K);
4491 constraints.set_max_old_space_size(4 * K * K);
4492 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4494 // Execute a script that causes out of memory.
4495 v8::V8::SetFatalErrorHandler(OOMCallback);
4497 LocalContext context;
4498 v8::HandleScope scope(context->GetIsolate());
4500 // Build huge string. This should fail with out of memory exception.
4502 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4503 "for (var i = 0; i < 22; i++) { str = str + str; }");
4505 CHECK(false); // Should not return.
4509 THREADED_TEST(ConstructCall) {
4510 LocalContext context;
4511 v8::Isolate* isolate = context->GetIsolate();
4512 v8::HandleScope scope(isolate);
4516 " for (var i = 0; i < arguments.length; i++) {"
4517 " result.push(arguments[i]);"
4521 Local<Function> Foo =
4522 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4524 v8::Handle<Value>* args0 = NULL;
4525 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4526 CHECK_EQ(0, a0->Length());
4528 v8::Handle<Value> args1[] = { v8_num(1.1) };
4529 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4530 CHECK_EQ(1, a1->Length());
4531 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4533 v8::Handle<Value> args2[] = { v8_num(2.2),
4535 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4536 CHECK_EQ(2, a2->Length());
4537 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4538 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4540 v8::Handle<Value> args3[] = { v8_num(4.4),
4543 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4544 CHECK_EQ(3, a3->Length());
4545 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4546 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4547 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4549 v8::Handle<Value> args4[] = { v8_num(7.7),
4553 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4554 CHECK_EQ(4, a4->Length());
4555 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4556 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4557 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4558 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4562 static void CheckUncle(v8::TryCatch* try_catch) {
4563 CHECK(try_catch->HasCaught());
4564 String::Utf8Value str_value(try_catch->Exception());
4565 CHECK_EQ(*str_value, "uncle?");
4570 THREADED_TEST(ConversionNumber) {
4572 v8::HandleScope scope(env->GetIsolate());
4573 // Very large number.
4574 CompileRun("var obj = Math.pow(2,32) * 1237;");
4575 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4576 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4577 CHECK_EQ(0, obj->ToInt32()->Value());
4578 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4580 CompileRun("var obj = -1234567890123;");
4581 obj = env->Global()->Get(v8_str("obj"));
4582 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4583 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4584 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4585 // Small positive integer.
4586 CompileRun("var obj = 42;");
4587 obj = env->Global()->Get(v8_str("obj"));
4588 CHECK_EQ(42.0, obj->ToNumber()->Value());
4589 CHECK_EQ(42, obj->ToInt32()->Value());
4590 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4591 // Negative integer.
4592 CompileRun("var obj = -37;");
4593 obj = env->Global()->Get(v8_str("obj"));
4594 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4595 CHECK_EQ(-37, obj->ToInt32()->Value());
4596 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4597 // Positive non-int32 integer.
4598 CompileRun("var obj = 0x81234567;");
4599 obj = env->Global()->Get(v8_str("obj"));
4600 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4601 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4602 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4604 CompileRun("var obj = 42.3;");
4605 obj = env->Global()->Get(v8_str("obj"));
4606 CHECK_EQ(42.3, obj->ToNumber()->Value());
4607 CHECK_EQ(42, obj->ToInt32()->Value());
4608 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4609 // Large negative fraction.
4610 CompileRun("var obj = -5726623061.75;");
4611 obj = env->Global()->Get(v8_str("obj"));
4612 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4613 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4614 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4618 THREADED_TEST(isNumberType) {
4620 v8::HandleScope scope(env->GetIsolate());
4621 // Very large number.
4622 CompileRun("var obj = Math.pow(2,32) * 1237;");
4623 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4624 CHECK(!obj->IsInt32());
4625 CHECK(!obj->IsUint32());
4626 // Large negative number.
4627 CompileRun("var obj = -1234567890123;");
4628 obj = env->Global()->Get(v8_str("obj"));
4629 CHECK(!obj->IsInt32());
4630 CHECK(!obj->IsUint32());
4631 // Small positive integer.
4632 CompileRun("var obj = 42;");
4633 obj = env->Global()->Get(v8_str("obj"));
4634 CHECK(obj->IsInt32());
4635 CHECK(obj->IsUint32());
4636 // Negative integer.
4637 CompileRun("var obj = -37;");
4638 obj = env->Global()->Get(v8_str("obj"));
4639 CHECK(obj->IsInt32());
4640 CHECK(!obj->IsUint32());
4641 // Positive non-int32 integer.
4642 CompileRun("var obj = 0x81234567;");
4643 obj = env->Global()->Get(v8_str("obj"));
4644 CHECK(!obj->IsInt32());
4645 CHECK(obj->IsUint32());
4647 CompileRun("var obj = 42.3;");
4648 obj = env->Global()->Get(v8_str("obj"));
4649 CHECK(!obj->IsInt32());
4650 CHECK(!obj->IsUint32());
4651 // Large negative fraction.
4652 CompileRun("var obj = -5726623061.75;");
4653 obj = env->Global()->Get(v8_str("obj"));
4654 CHECK(!obj->IsInt32());
4655 CHECK(!obj->IsUint32());
4657 CompileRun("var obj = 0.0;");
4658 obj = env->Global()->Get(v8_str("obj"));
4659 CHECK(obj->IsInt32());
4660 CHECK(obj->IsUint32());
4662 CompileRun("var obj = -0.0;");
4663 obj = env->Global()->Get(v8_str("obj"));
4664 CHECK(!obj->IsInt32());
4665 CHECK(!obj->IsUint32());
4669 THREADED_TEST(ConversionException) {
4671 v8::Isolate* isolate = env->GetIsolate();
4672 v8::HandleScope scope(isolate);
4674 "function TestClass() { };"
4675 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4676 "var obj = new TestClass();");
4677 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4679 v8::TryCatch try_catch;
4681 Local<Value> to_string_result = obj->ToString();
4682 CHECK(to_string_result.IsEmpty());
4683 CheckUncle(&try_catch);
4685 Local<Value> to_number_result = obj->ToNumber();
4686 CHECK(to_number_result.IsEmpty());
4687 CheckUncle(&try_catch);
4689 Local<Value> to_integer_result = obj->ToInteger();
4690 CHECK(to_integer_result.IsEmpty());
4691 CheckUncle(&try_catch);
4693 Local<Value> to_uint32_result = obj->ToUint32();
4694 CHECK(to_uint32_result.IsEmpty());
4695 CheckUncle(&try_catch);
4697 Local<Value> to_int32_result = obj->ToInt32();
4698 CHECK(to_int32_result.IsEmpty());
4699 CheckUncle(&try_catch);
4701 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4702 CHECK(to_object_result.IsEmpty());
4703 CHECK(try_catch.HasCaught());
4706 int32_t int32_value = obj->Int32Value();
4707 CHECK_EQ(0, int32_value);
4708 CheckUncle(&try_catch);
4710 uint32_t uint32_value = obj->Uint32Value();
4711 CHECK_EQ(0, uint32_value);
4712 CheckUncle(&try_catch);
4714 double number_value = obj->NumberValue();
4715 CHECK_NE(0, std::isnan(number_value));
4716 CheckUncle(&try_catch);
4718 int64_t integer_value = obj->IntegerValue();
4719 CHECK_EQ(0.0, static_cast<double>(integer_value));
4720 CheckUncle(&try_catch);
4724 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4725 ApiTestFuzzer::Fuzz();
4726 args.GetIsolate()->ThrowException(v8_str("konto"));
4730 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4731 if (args.Length() < 1) {
4732 args.GetReturnValue().Set(false);
4735 v8::HandleScope scope(args.GetIsolate());
4736 v8::TryCatch try_catch;
4737 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4738 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4739 args.GetReturnValue().Set(try_catch.HasCaught());
4743 THREADED_TEST(APICatch) {
4744 v8::Isolate* isolate = CcTest::isolate();
4745 v8::HandleScope scope(isolate);
4746 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4747 templ->Set(v8_str("ThrowFromC"),
4748 v8::FunctionTemplate::New(isolate, ThrowFromC));
4749 LocalContext context(0, templ);
4751 "var thrown = false;"
4757 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4758 CHECK(thrown->BooleanValue());
4762 THREADED_TEST(APIThrowTryCatch) {
4763 v8::Isolate* isolate = CcTest::isolate();
4764 v8::HandleScope scope(isolate);
4765 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4766 templ->Set(v8_str("ThrowFromC"),
4767 v8::FunctionTemplate::New(isolate, ThrowFromC));
4768 LocalContext context(0, templ);
4769 v8::TryCatch try_catch;
4770 CompileRun("ThrowFromC();");
4771 CHECK(try_catch.HasCaught());
4775 // Test that a try-finally block doesn't shadow a try-catch block
4776 // when setting up an external handler.
4778 // BUG(271): Some of the exception propagation does not work on the
4779 // ARM simulator because the simulator separates the C++ stack and the
4780 // JS stack. This test therefore fails on the simulator. The test is
4781 // not threaded to allow the threading tests to run on the simulator.
4782 TEST(TryCatchInTryFinally) {
4783 v8::Isolate* isolate = CcTest::isolate();
4784 v8::HandleScope scope(isolate);
4785 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4786 templ->Set(v8_str("CCatcher"),
4787 v8::FunctionTemplate::New(isolate, CCatcher));
4788 LocalContext context(0, templ);
4789 Local<Value> result = CompileRun("try {"
4791 " CCatcher('throw 7;');"
4796 CHECK(result->IsTrue());
4800 static void check_reference_error_message(
4801 v8::Handle<v8::Message> message,
4802 v8::Handle<v8::Value> data) {
4803 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4804 CHECK(message->Get()->Equals(v8_str(reference_error)));
4808 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4809 ApiTestFuzzer::Fuzz();
4814 // Test that overwritten methods are not invoked on uncaught exception
4815 // formatting. However, they are invoked when performing normal error
4816 // string conversions.
4817 TEST(APIThrowMessageOverwrittenToString) {
4818 v8::Isolate* isolate = CcTest::isolate();
4819 v8::HandleScope scope(isolate);
4820 v8::V8::AddMessageListener(check_reference_error_message);
4821 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4822 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4823 LocalContext context(NULL, templ);
4824 CompileRun("asdf;");
4825 CompileRun("var limit = {};"
4826 "limit.valueOf = fail;"
4827 "Error.stackTraceLimit = limit;");
4829 CompileRun("Array.prototype.pop = fail;");
4830 CompileRun("Object.prototype.hasOwnProperty = fail;");
4831 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4832 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4833 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4834 CompileRun("ReferenceError.prototype.toString ="
4835 " function() { return 'Whoops' }");
4836 CompileRun("asdf;");
4837 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4838 CompileRun("asdf;");
4839 CompileRun("ReferenceError.prototype.constructor = void 0;");
4840 CompileRun("asdf;");
4841 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4842 CompileRun("asdf;");
4843 CompileRun("ReferenceError.prototype = new Object();");
4844 CompileRun("asdf;");
4845 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4846 CHECK(string->Equals(v8_str("Whoops")));
4847 CompileRun("ReferenceError.prototype.constructor = new Object();"
4848 "ReferenceError.prototype.constructor.name = 1;"
4849 "Number.prototype.toString = function() { return 'Whoops'; };"
4850 "ReferenceError.prototype.toString = Object.prototype.toString;");
4851 CompileRun("asdf;");
4852 v8::V8::RemoveMessageListeners(check_reference_error_message);
4856 static void check_custom_error_tostring(
4857 v8::Handle<v8::Message> message,
4858 v8::Handle<v8::Value> data) {
4859 const char* uncaught_error = "Uncaught MyError toString";
4860 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4864 TEST(CustomErrorToString) {
4865 LocalContext context;
4866 v8::HandleScope scope(context->GetIsolate());
4867 v8::V8::AddMessageListener(check_custom_error_tostring);
4869 "function MyError(name, message) { "
4870 " this.name = name; "
4871 " this.message = message; "
4873 "MyError.prototype = Object.create(Error.prototype); "
4874 "MyError.prototype.toString = function() { "
4875 " return 'MyError toString'; "
4877 "throw new MyError('my name', 'my message'); ");
4878 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4882 static void check_custom_error_message(
4883 v8::Handle<v8::Message> message,
4884 v8::Handle<v8::Value> data) {
4885 const char* uncaught_error = "Uncaught MyError: my message";
4886 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4887 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4891 TEST(CustomErrorMessage) {
4892 LocalContext context;
4893 v8::HandleScope scope(context->GetIsolate());
4894 v8::V8::AddMessageListener(check_custom_error_message);
4898 "function MyError(msg) { "
4899 " this.name = 'MyError'; "
4900 " this.message = msg; "
4902 "MyError.prototype = new Error(); "
4903 "throw new MyError('my message'); ");
4907 "function MyError(msg) { "
4908 " this.name = 'MyError'; "
4909 " this.message = msg; "
4911 "inherits = function(childCtor, parentCtor) { "
4912 " function tempCtor() {}; "
4913 " tempCtor.prototype = parentCtor.prototype; "
4914 " childCtor.superClass_ = parentCtor.prototype; "
4915 " childCtor.prototype = new tempCtor(); "
4916 " childCtor.prototype.constructor = childCtor; "
4918 "inherits(MyError, Error); "
4919 "throw new MyError('my message'); ");
4923 "function MyError(msg) { "
4924 " this.name = 'MyError'; "
4925 " this.message = msg; "
4927 "MyError.prototype = Object.create(Error.prototype); "
4928 "throw new MyError('my message'); ");
4930 v8::V8::RemoveMessageListeners(check_custom_error_message);
4934 static void receive_message(v8::Handle<v8::Message> message,
4935 v8::Handle<v8::Value> data) {
4937 message_received = true;
4941 TEST(APIThrowMessage) {
4942 message_received = false;
4943 v8::Isolate* isolate = CcTest::isolate();
4944 v8::HandleScope scope(isolate);
4945 v8::V8::AddMessageListener(receive_message);
4946 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4947 templ->Set(v8_str("ThrowFromC"),
4948 v8::FunctionTemplate::New(isolate, ThrowFromC));
4949 LocalContext context(0, templ);
4950 CompileRun("ThrowFromC();");
4951 CHECK(message_received);
4952 v8::V8::RemoveMessageListeners(receive_message);
4956 TEST(APIThrowMessageAndVerboseTryCatch) {
4957 message_received = false;
4958 v8::Isolate* isolate = CcTest::isolate();
4959 v8::HandleScope scope(isolate);
4960 v8::V8::AddMessageListener(receive_message);
4961 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4962 templ->Set(v8_str("ThrowFromC"),
4963 v8::FunctionTemplate::New(isolate, ThrowFromC));
4964 LocalContext context(0, templ);
4965 v8::TryCatch try_catch;
4966 try_catch.SetVerbose(true);
4967 Local<Value> result = CompileRun("ThrowFromC();");
4968 CHECK(try_catch.HasCaught());
4969 CHECK(result.IsEmpty());
4970 CHECK(message_received);
4971 v8::V8::RemoveMessageListeners(receive_message);
4975 TEST(APIStackOverflowAndVerboseTryCatch) {
4976 message_received = false;
4977 LocalContext context;
4978 v8::HandleScope scope(context->GetIsolate());
4979 v8::V8::AddMessageListener(receive_message);
4980 v8::TryCatch try_catch;
4981 try_catch.SetVerbose(true);
4982 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4983 CHECK(try_catch.HasCaught());
4984 CHECK(result.IsEmpty());
4985 CHECK(message_received);
4986 v8::V8::RemoveMessageListeners(receive_message);
4990 THREADED_TEST(ExternalScriptException) {
4991 v8::Isolate* isolate = CcTest::isolate();
4992 v8::HandleScope scope(isolate);
4993 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4994 templ->Set(v8_str("ThrowFromC"),
4995 v8::FunctionTemplate::New(isolate, ThrowFromC));
4996 LocalContext context(0, templ);
4998 v8::TryCatch try_catch;
4999 Local<Script> script
5000 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
5001 Local<Value> result = script->Run();
5002 CHECK(result.IsEmpty());
5003 CHECK(try_catch.HasCaught());
5004 String::Utf8Value exception_value(try_catch.Exception());
5005 CHECK_EQ("konto", *exception_value);
5010 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5011 ApiTestFuzzer::Fuzz();
5012 CHECK_EQ(4, args.Length());
5013 int count = args[0]->Int32Value();
5014 int cInterval = args[2]->Int32Value();
5016 args.GetIsolate()->ThrowException(v8_str("FromC"));
5019 Local<v8::Object> global =
5020 args.GetIsolate()->GetCurrentContext()->Global();
5021 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5022 v8::Handle<Value> argv[] = { v8_num(count - 1),
5026 if (count % cInterval == 0) {
5027 v8::TryCatch try_catch;
5028 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5029 int expected = args[3]->Int32Value();
5030 if (try_catch.HasCaught()) {
5031 CHECK_EQ(expected, count);
5032 CHECK(result.IsEmpty());
5033 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5035 CHECK_NE(expected, count);
5037 args.GetReturnValue().Set(result);
5040 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5047 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5048 ApiTestFuzzer::Fuzz();
5049 CHECK_EQ(3, args.Length());
5050 bool equality = args[0]->BooleanValue();
5051 int count = args[1]->Int32Value();
5052 int expected = args[2]->Int32Value();
5054 CHECK_EQ(count, expected);
5056 CHECK_NE(count, expected);
5061 THREADED_TEST(EvalInTryFinally) {
5062 LocalContext context;
5063 v8::HandleScope scope(context->GetIsolate());
5064 v8::TryCatch try_catch;
5065 CompileRun("(function() {"
5067 " eval('asldkf (*&^&*^');"
5072 CHECK(!try_catch.HasCaught());
5076 // This test works by making a stack of alternating JavaScript and C
5077 // activations. These activations set up exception handlers with regular
5078 // intervals, one interval for C activations and another for JavaScript
5079 // activations. When enough activations have been created an exception is
5080 // thrown and we check that the right activation catches the exception and that
5081 // no other activations do. The right activation is always the topmost one with
5082 // a handler, regardless of whether it is in JavaScript or C.
5084 // The notation used to describe a test case looks like this:
5086 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5088 // Each entry is an activation, either JS or C. The index is the count at that
5089 // level. Stars identify activations with exception handlers, the @ identifies
5090 // the exception handler that should catch the exception.
5092 // BUG(271): Some of the exception propagation does not work on the
5093 // ARM simulator because the simulator separates the C++ stack and the
5094 // JS stack. This test therefore fails on the simulator. The test is
5095 // not threaded to allow the threading tests to run on the simulator.
5096 TEST(ExceptionOrder) {
5097 v8::Isolate* isolate = CcTest::isolate();
5098 v8::HandleScope scope(isolate);
5099 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5100 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5101 templ->Set(v8_str("CThrowCountDown"),
5102 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5103 LocalContext context(0, templ);
5105 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5106 " if (count == 0) throw 'FromJS';"
5107 " if (count % jsInterval == 0) {"
5109 " var value = CThrowCountDown(count - 1,"
5113 " check(false, count, expected);"
5116 " check(true, count, expected);"
5119 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5122 Local<Function> fun =
5123 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5126 // count jsInterval cInterval expected
5128 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5129 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5130 fun->Call(fun, argc, a0);
5132 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5133 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5134 fun->Call(fun, argc, a1);
5136 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5137 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5138 fun->Call(fun, argc, a2);
5140 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5141 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5142 fun->Call(fun, argc, a3);
5144 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5145 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5146 fun->Call(fun, argc, a4);
5148 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5149 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5150 fun->Call(fun, argc, a5);
5154 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5155 ApiTestFuzzer::Fuzz();
5156 CHECK_EQ(1, args.Length());
5157 args.GetIsolate()->ThrowException(args[0]);
5161 THREADED_TEST(ThrowValues) {
5162 v8::Isolate* isolate = CcTest::isolate();
5163 v8::HandleScope scope(isolate);
5164 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5165 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5166 LocalContext context(0, templ);
5167 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5168 "function Run(obj) {"
5174 " return 'no exception';"
5176 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5177 CHECK_EQ(5, result->Length());
5178 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5179 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5180 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5181 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5182 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5183 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5184 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5188 THREADED_TEST(CatchZero) {
5189 LocalContext context;
5190 v8::HandleScope scope(context->GetIsolate());
5191 v8::TryCatch try_catch;
5192 CHECK(!try_catch.HasCaught());
5193 Script::Compile(v8_str("throw 10"))->Run();
5194 CHECK(try_catch.HasCaught());
5195 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5197 CHECK(!try_catch.HasCaught());
5198 Script::Compile(v8_str("throw 0"))->Run();
5199 CHECK(try_catch.HasCaught());
5200 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5204 THREADED_TEST(CatchExceptionFromWith) {
5205 LocalContext context;
5206 v8::HandleScope scope(context->GetIsolate());
5207 v8::TryCatch try_catch;
5208 CHECK(!try_catch.HasCaught());
5209 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
5210 CHECK(try_catch.HasCaught());
5214 THREADED_TEST(TryCatchAndFinallyHidingException) {
5215 LocalContext context;
5216 v8::HandleScope scope(context->GetIsolate());
5217 v8::TryCatch try_catch;
5218 CHECK(!try_catch.HasCaught());
5219 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5220 CompileRun("f({toString: function() { throw 42; }});");
5221 CHECK(!try_catch.HasCaught());
5225 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5226 v8::TryCatch try_catch;
5230 THREADED_TEST(TryCatchAndFinally) {
5231 LocalContext context;
5232 v8::Isolate* isolate = context->GetIsolate();
5233 v8::HandleScope scope(isolate);
5234 context->Global()->Set(
5235 v8_str("native_with_try_catch"),
5236 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5237 v8::TryCatch try_catch;
5238 CHECK(!try_catch.HasCaught());
5241 " throw new Error('a');\n"
5243 " native_with_try_catch();\n"
5245 CHECK(try_catch.HasCaught());
5249 static void TryCatchNestedHelper(int depth) {
5251 v8::TryCatch try_catch;
5252 try_catch.SetVerbose(true);
5253 TryCatchNestedHelper(depth - 1);
5254 CHECK(try_catch.HasCaught());
5255 try_catch.ReThrow();
5257 CcTest::isolate()->ThrowException(v8_str("back"));
5262 TEST(TryCatchNested) {
5263 v8::V8::Initialize();
5264 LocalContext context;
5265 v8::HandleScope scope(context->GetIsolate());
5266 v8::TryCatch try_catch;
5267 TryCatchNestedHelper(5);
5268 CHECK(try_catch.HasCaught());
5269 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5273 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5274 CHECK(try_catch->HasCaught());
5275 Handle<Message> message = try_catch->Message();
5276 Handle<Value> resource = message->GetScriptResourceName();
5277 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5278 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5279 "Uncaught Error: a"));
5280 CHECK_EQ(1, message->GetLineNumber());
5281 CHECK_EQ(6, message->GetStartColumn());
5285 void TryCatchMixedNestingHelper(
5286 const v8::FunctionCallbackInfo<v8::Value>& args) {
5287 ApiTestFuzzer::Fuzz();
5288 v8::TryCatch try_catch;
5289 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5290 CHECK(try_catch.HasCaught());
5291 TryCatchMixedNestingCheck(&try_catch);
5292 try_catch.ReThrow();
5296 // This test ensures that an outer TryCatch in the following situation:
5297 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5298 // does not clobber the Message object generated for the inner TryCatch.
5299 // This exercises the ability of TryCatch.ReThrow() to restore the
5300 // inner pending Message before throwing the exception again.
5301 TEST(TryCatchMixedNesting) {
5302 v8::Isolate* isolate = CcTest::isolate();
5303 v8::HandleScope scope(isolate);
5304 v8::V8::Initialize();
5305 v8::TryCatch try_catch;
5306 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5307 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5308 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5309 LocalContext context(0, templ);
5310 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5311 TryCatchMixedNestingCheck(&try_catch);
5315 THREADED_TEST(Equality) {
5316 LocalContext context;
5317 v8::Isolate* isolate = context->GetIsolate();
5318 v8::HandleScope scope(context->GetIsolate());
5319 // Check that equality works at all before relying on CHECK_EQ
5320 CHECK(v8_str("a")->Equals(v8_str("a")));
5321 CHECK(!v8_str("a")->Equals(v8_str("b")));
5323 CHECK_EQ(v8_str("a"), v8_str("a"));
5324 CHECK_NE(v8_str("a"), v8_str("b"));
5325 CHECK_EQ(v8_num(1), v8_num(1));
5326 CHECK_EQ(v8_num(1.00), v8_num(1));
5327 CHECK_NE(v8_num(1), v8_num(2));
5329 // Assume String is not internalized.
5330 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5331 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5332 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5333 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5334 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5335 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5336 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5337 CHECK(!not_a_number->StrictEquals(not_a_number));
5338 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5339 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5341 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5342 v8::Persistent<v8::Object> alias(isolate, obj);
5343 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5346 CHECK(v8_str("a")->SameValue(v8_str("a")));
5347 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5348 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5349 CHECK(v8_num(1)->SameValue(v8_num(1)));
5350 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5351 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5352 CHECK(not_a_number->SameValue(not_a_number));
5353 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5354 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5358 THREADED_TEST(MultiRun) {
5359 LocalContext context;
5360 v8::HandleScope scope(context->GetIsolate());
5361 Local<Script> script = Script::Compile(v8_str("x"));
5362 for (int i = 0; i < 10; i++)
5367 static void GetXValue(Local<String> name,
5368 const v8::PropertyCallbackInfo<v8::Value>& info) {
5369 ApiTestFuzzer::Fuzz();
5370 CHECK_EQ(info.Data(), v8_str("donut"));
5371 CHECK_EQ(name, v8_str("x"));
5372 info.GetReturnValue().Set(name);
5376 THREADED_TEST(SimplePropertyRead) {
5377 LocalContext context;
5378 v8::Isolate* isolate = context->GetIsolate();
5379 v8::HandleScope scope(isolate);
5380 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5381 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5382 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5383 Local<Script> script = Script::Compile(v8_str("obj.x"));
5384 for (int i = 0; i < 10; i++) {
5385 Local<Value> result = script->Run();
5386 CHECK_EQ(result, v8_str("x"));
5391 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5392 LocalContext context;
5393 v8::Isolate* isolate = context->GetIsolate();
5394 v8::HandleScope scope(isolate);
5395 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5396 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5397 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5399 // Uses getOwnPropertyDescriptor to check the configurable status
5400 Local<Script> script_desc
5401 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5403 "prop.configurable;"));
5404 Local<Value> result = script_desc->Run();
5405 CHECK_EQ(result->BooleanValue(), true);
5407 // Redefine get - but still configurable
5408 Local<Script> script_define
5409 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5410 " configurable: true };"
5411 "Object.defineProperty(obj, 'x', desc);"
5413 result = script_define->Run();
5414 CHECK_EQ(result, v8_num(42));
5416 // Check that the accessor is still configurable
5417 result = script_desc->Run();
5418 CHECK_EQ(result->BooleanValue(), true);
5420 // Redefine to a non-configurable
5422 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5423 " configurable: false };"
5424 "Object.defineProperty(obj, 'x', desc);"
5426 result = script_define->Run();
5427 CHECK_EQ(result, v8_num(43));
5428 result = script_desc->Run();
5429 CHECK_EQ(result->BooleanValue(), false);
5431 // Make sure that it is not possible to redefine again
5432 v8::TryCatch try_catch;
5433 result = script_define->Run();
5434 CHECK(try_catch.HasCaught());
5435 String::Utf8Value exception_value(try_catch.Exception());
5436 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5440 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5441 v8::Isolate* isolate = CcTest::isolate();
5442 v8::HandleScope scope(isolate);
5443 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5444 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5445 LocalContext context;
5446 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5448 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5449 "Object.getOwnPropertyDescriptor( "
5451 "prop.configurable;"));
5452 Local<Value> result = script_desc->Run();
5453 CHECK_EQ(result->BooleanValue(), true);
5455 Local<Script> script_define =
5456 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5457 " configurable: true };"
5458 "Object.defineProperty(obj, 'x', desc);"
5460 result = script_define->Run();
5461 CHECK_EQ(result, v8_num(42));
5464 result = script_desc->Run();
5465 CHECK_EQ(result->BooleanValue(), true);
5469 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5470 " configurable: false };"
5471 "Object.defineProperty(obj, 'x', desc);"
5473 result = script_define->Run();
5474 CHECK_EQ(result, v8_num(43));
5475 result = script_desc->Run();
5477 CHECK_EQ(result->BooleanValue(), false);
5479 v8::TryCatch try_catch;
5480 result = script_define->Run();
5481 CHECK(try_catch.HasCaught());
5482 String::Utf8Value exception_value(try_catch.Exception());
5483 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5487 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5489 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5493 THREADED_TEST(DefineAPIAccessorOnObject) {
5494 v8::Isolate* isolate = CcTest::isolate();
5495 v8::HandleScope scope(isolate);
5496 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5497 LocalContext context;
5499 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5500 CompileRun("var obj2 = {};");
5502 CHECK(CompileRun("obj1.x")->IsUndefined());
5503 CHECK(CompileRun("obj2.x")->IsUndefined());
5505 CHECK(GetGlobalProperty(&context, "obj1")->
5506 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5508 ExpectString("obj1.x", "x");
5509 CHECK(CompileRun("obj2.x")->IsUndefined());
5511 CHECK(GetGlobalProperty(&context, "obj2")->
5512 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5514 ExpectString("obj1.x", "x");
5515 ExpectString("obj2.x", "x");
5517 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5518 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5520 CompileRun("Object.defineProperty(obj1, 'x',"
5521 "{ get: function() { return 'y'; }, configurable: true })");
5523 ExpectString("obj1.x", "y");
5524 ExpectString("obj2.x", "x");
5526 CompileRun("Object.defineProperty(obj2, 'x',"
5527 "{ get: function() { return 'y'; }, configurable: true })");
5529 ExpectString("obj1.x", "y");
5530 ExpectString("obj2.x", "y");
5532 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5533 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5535 CHECK(GetGlobalProperty(&context, "obj1")->
5536 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5537 CHECK(GetGlobalProperty(&context, "obj2")->
5538 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5540 ExpectString("obj1.x", "x");
5541 ExpectString("obj2.x", "x");
5543 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5544 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5546 // Define getters/setters, but now make them not configurable.
5547 CompileRun("Object.defineProperty(obj1, 'x',"
5548 "{ get: function() { return 'z'; }, configurable: false })");
5549 CompileRun("Object.defineProperty(obj2, 'x',"
5550 "{ get: function() { return 'z'; }, configurable: false })");
5552 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5553 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5555 ExpectString("obj1.x", "z");
5556 ExpectString("obj2.x", "z");
5558 CHECK(!GetGlobalProperty(&context, "obj1")->
5559 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5560 CHECK(!GetGlobalProperty(&context, "obj2")->
5561 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5563 ExpectString("obj1.x", "z");
5564 ExpectString("obj2.x", "z");
5568 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5569 v8::Isolate* isolate = CcTest::isolate();
5570 v8::HandleScope scope(isolate);
5571 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5572 LocalContext context;
5574 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5575 CompileRun("var obj2 = {};");
5577 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5580 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5581 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5584 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5586 ExpectString("obj1.x", "x");
5587 ExpectString("obj2.x", "x");
5589 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5590 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5592 CHECK(!GetGlobalProperty(&context, "obj1")->
5593 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5594 CHECK(!GetGlobalProperty(&context, "obj2")->
5595 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5598 v8::TryCatch try_catch;
5599 CompileRun("Object.defineProperty(obj1, 'x',"
5600 "{get: function() { return 'func'; }})");
5601 CHECK(try_catch.HasCaught());
5602 String::Utf8Value exception_value(try_catch.Exception());
5603 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5606 v8::TryCatch try_catch;
5607 CompileRun("Object.defineProperty(obj2, 'x',"
5608 "{get: function() { return 'func'; }})");
5609 CHECK(try_catch.HasCaught());
5610 String::Utf8Value exception_value(try_catch.Exception());
5611 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5616 static void Get239Value(Local<String> name,
5617 const v8::PropertyCallbackInfo<v8::Value>& info) {
5618 ApiTestFuzzer::Fuzz();
5619 CHECK_EQ(info.Data(), v8_str("donut"));
5620 CHECK_EQ(name, v8_str("239"));
5621 info.GetReturnValue().Set(name);
5625 THREADED_TEST(ElementAPIAccessor) {
5626 v8::Isolate* isolate = CcTest::isolate();
5627 v8::HandleScope scope(isolate);
5628 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5629 LocalContext context;
5631 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5632 CompileRun("var obj2 = {};");
5634 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5638 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5643 ExpectString("obj1[239]", "239");
5644 ExpectString("obj2[239]", "239");
5645 ExpectString("obj1['239']", "239");
5646 ExpectString("obj2['239']", "239");
5650 v8::Persistent<Value> xValue;
5653 static void SetXValue(Local<String> name,
5655 const v8::PropertyCallbackInfo<void>& info) {
5656 CHECK_EQ(value, v8_num(4));
5657 CHECK_EQ(info.Data(), v8_str("donut"));
5658 CHECK_EQ(name, v8_str("x"));
5659 CHECK(xValue.IsEmpty());
5660 xValue.Reset(info.GetIsolate(), value);
5664 THREADED_TEST(SimplePropertyWrite) {
5665 v8::Isolate* isolate = CcTest::isolate();
5666 v8::HandleScope scope(isolate);
5667 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5668 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5669 LocalContext context;
5670 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5671 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5672 for (int i = 0; i < 10; i++) {
5673 CHECK(xValue.IsEmpty());
5675 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5681 THREADED_TEST(SetterOnly) {
5682 v8::Isolate* isolate = CcTest::isolate();
5683 v8::HandleScope scope(isolate);
5684 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5685 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5686 LocalContext context;
5687 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5688 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5689 for (int i = 0; i < 10; i++) {
5690 CHECK(xValue.IsEmpty());
5692 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5698 THREADED_TEST(NoAccessors) {
5699 v8::Isolate* isolate = CcTest::isolate();
5700 v8::HandleScope scope(isolate);
5701 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5702 templ->SetAccessor(v8_str("x"),
5703 static_cast<v8::AccessorGetterCallback>(NULL),
5706 LocalContext context;
5707 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5708 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5709 for (int i = 0; i < 10; i++) {
5715 static void XPropertyGetter(Local<String> property,
5716 const v8::PropertyCallbackInfo<v8::Value>& info) {
5717 ApiTestFuzzer::Fuzz();
5718 CHECK(info.Data()->IsUndefined());
5719 info.GetReturnValue().Set(property);
5723 THREADED_TEST(NamedInterceptorPropertyRead) {
5724 v8::Isolate* isolate = CcTest::isolate();
5725 v8::HandleScope scope(isolate);
5726 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5727 templ->SetNamedPropertyHandler(XPropertyGetter);
5728 LocalContext context;
5729 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5730 Local<Script> script = Script::Compile(v8_str("obj.x"));
5731 for (int i = 0; i < 10; i++) {
5732 Local<Value> result = script->Run();
5733 CHECK_EQ(result, v8_str("x"));
5738 THREADED_TEST(NamedInterceptorDictionaryIC) {
5739 v8::Isolate* isolate = CcTest::isolate();
5740 v8::HandleScope scope(isolate);
5741 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5742 templ->SetNamedPropertyHandler(XPropertyGetter);
5743 LocalContext context;
5744 // Create an object with a named interceptor.
5745 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5746 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5747 for (int i = 0; i < 10; i++) {
5748 Local<Value> result = script->Run();
5749 CHECK_EQ(result, v8_str("x"));
5751 // Create a slow case object and a function accessing a property in
5752 // that slow case object (with dictionary probing in generated
5753 // code). Then force object with a named interceptor into slow-case,
5754 // pass it to the function, and check that the interceptor is called
5755 // instead of accessing the local property.
5756 Local<Value> result =
5757 CompileRun("function get_x(o) { return o.x; };"
5758 "var obj = { x : 42, y : 0 };"
5760 "for (var i = 0; i < 10; i++) get_x(obj);"
5761 "interceptor_obj.x = 42;"
5762 "interceptor_obj.y = 10;"
5763 "delete interceptor_obj.y;"
5764 "get_x(interceptor_obj)");
5765 CHECK_EQ(result, v8_str("x"));
5769 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5770 v8::Isolate* isolate = CcTest::isolate();
5771 v8::HandleScope scope(isolate);
5772 v8::Local<Context> context1 = Context::New(isolate);
5775 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5776 templ->SetNamedPropertyHandler(XPropertyGetter);
5777 // Create an object with a named interceptor.
5778 v8::Local<v8::Object> object = templ->NewInstance();
5779 context1->Global()->Set(v8_str("interceptor_obj"), object);
5781 // Force the object into the slow case.
5782 CompileRun("interceptor_obj.y = 0;"
5783 "delete interceptor_obj.y;");
5787 // Introduce the object into a different context.
5788 // Repeat named loads to exercise ICs.
5789 LocalContext context2;
5790 context2->Global()->Set(v8_str("interceptor_obj"), object);
5791 Local<Value> result =
5792 CompileRun("function get_x(o) { return o.x; }"
5793 "interceptor_obj.x = 42;"
5794 "for (var i=0; i != 10; i++) {"
5795 " get_x(interceptor_obj);"
5797 "get_x(interceptor_obj)");
5798 // Check that the interceptor was actually invoked.
5799 CHECK_EQ(result, v8_str("x"));
5802 // Return to the original context and force some object to the slow case
5803 // to cause the NormalizedMapCache to verify.
5805 CompileRun("var obj = { x : 0 }; delete obj.x;");
5810 static void SetXOnPrototypeGetter(
5811 Local<String> property,
5812 const v8::PropertyCallbackInfo<v8::Value>& info) {
5813 // Set x on the prototype object and do not handle the get request.
5814 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5815 proto.As<v8::Object>()->Set(v8_str("x"),
5816 v8::Integer::New(info.GetIsolate(), 23));
5820 // This is a regression test for http://crbug.com/20104. Map
5821 // transitions should not interfere with post interceptor lookup.
5822 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5823 v8::Isolate* isolate = CcTest::isolate();
5824 v8::HandleScope scope(isolate);
5825 Local<v8::FunctionTemplate> function_template =
5826 v8::FunctionTemplate::New(isolate);
5827 Local<v8::ObjectTemplate> instance_template
5828 = function_template->InstanceTemplate();
5829 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5830 LocalContext context;
5831 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5832 // Create an instance of F and introduce a map transition for x.
5833 CompileRun("var o = new F(); o.x = 23;");
5834 // Create an instance of F and invoke the getter. The result should be 23.
5835 Local<Value> result = CompileRun("o = new F(); o.x");
5836 CHECK_EQ(result->Int32Value(), 23);
5840 static void IndexedPropertyGetter(
5842 const v8::PropertyCallbackInfo<v8::Value>& info) {
5843 ApiTestFuzzer::Fuzz();
5845 info.GetReturnValue().Set(v8_num(625));
5850 static void IndexedPropertySetter(
5853 const v8::PropertyCallbackInfo<v8::Value>& info) {
5854 ApiTestFuzzer::Fuzz();
5856 info.GetReturnValue().Set(value);
5861 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5862 v8::Isolate* isolate = CcTest::isolate();
5863 v8::HandleScope scope(isolate);
5864 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5865 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5866 IndexedPropertySetter);
5867 LocalContext context;
5868 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5869 Local<Script> getter_script = Script::Compile(v8_str(
5870 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5871 Local<Script> setter_script = Script::Compile(v8_str(
5872 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5875 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5876 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5878 "obj.foo;")); // This setter should not run, due to the interceptor.
5879 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5881 Local<Value> result = getter_script->Run();
5882 CHECK_EQ(v8_num(5), result);
5883 result = setter_script->Run();
5884 CHECK_EQ(v8_num(23), result);
5885 result = interceptor_setter_script->Run();
5886 CHECK_EQ(v8_num(23), result);
5887 result = interceptor_getter_script->Run();
5888 CHECK_EQ(v8_num(625), result);
5892 static void UnboxedDoubleIndexedPropertyGetter(
5894 const v8::PropertyCallbackInfo<v8::Value>& info) {
5895 ApiTestFuzzer::Fuzz();
5897 info.GetReturnValue().Set(v8_num(index));
5902 static void UnboxedDoubleIndexedPropertySetter(
5905 const v8::PropertyCallbackInfo<v8::Value>& info) {
5906 ApiTestFuzzer::Fuzz();
5908 info.GetReturnValue().Set(v8_num(index));
5913 void UnboxedDoubleIndexedPropertyEnumerator(
5914 const v8::PropertyCallbackInfo<v8::Array>& info) {
5915 // Force the list of returned keys to be stored in a FastDoubleArray.
5916 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5917 "keys = new Array(); keys[125000] = 1;"
5918 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5919 "keys.length = 25; keys;"));
5920 Local<Value> result = indexed_property_names_script->Run();
5921 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5925 // Make sure that the the interceptor code in the runtime properly handles
5926 // merging property name lists for double-array-backed arrays.
5927 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5928 v8::Isolate* isolate = CcTest::isolate();
5929 v8::HandleScope scope(isolate);
5930 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5931 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5932 UnboxedDoubleIndexedPropertySetter,
5935 UnboxedDoubleIndexedPropertyEnumerator);
5936 LocalContext context;
5937 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5938 // When obj is created, force it to be Stored in a FastDoubleArray.
5939 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5940 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5942 "for (x in obj) {key_count++;};"
5944 Local<Value> result = create_unboxed_double_script->Run();
5945 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5946 Local<Script> key_count_check = Script::Compile(v8_str(
5948 result = key_count_check->Run();
5949 CHECK_EQ(v8_num(40013), result);
5953 void NonStrictArgsIndexedPropertyEnumerator(
5954 const v8::PropertyCallbackInfo<v8::Array>& info) {
5955 // Force the list of returned keys to be stored in a Arguments object.
5956 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5958 " return arguments;"
5960 "keys = f(0, 1, 2, 3);"
5962 Local<Object> result =
5963 Local<Object>::Cast(indexed_property_names_script->Run());
5964 // Have to populate the handle manually, as it's not Cast-able.
5965 i::Handle<i::JSObject> o =
5966 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5967 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5968 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5972 static void NonStrictIndexedPropertyGetter(
5974 const v8::PropertyCallbackInfo<v8::Value>& info) {
5975 ApiTestFuzzer::Fuzz();
5977 info.GetReturnValue().Set(v8_num(index));
5982 // Make sure that the the interceptor code in the runtime properly handles
5983 // merging property name lists for non-string arguments arrays.
5984 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5985 v8::Isolate* isolate = CcTest::isolate();
5986 v8::HandleScope scope(isolate);
5987 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5988 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5992 NonStrictArgsIndexedPropertyEnumerator);
5993 LocalContext context;
5994 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5995 Local<Script> create_args_script =
5996 Script::Compile(v8_str(
5997 "var key_count = 0;"
5998 "for (x in obj) {key_count++;} key_count;"));
5999 Local<Value> result = create_args_script->Run();
6000 CHECK_EQ(v8_num(4), result);
6004 static void IdentityIndexedPropertyGetter(
6006 const v8::PropertyCallbackInfo<v8::Value>& info) {
6007 info.GetReturnValue().Set(index);
6011 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6012 v8::Isolate* isolate = CcTest::isolate();
6013 v8::HandleScope scope(isolate);
6014 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6015 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6017 LocalContext context;
6018 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6020 // Check fast object case.
6021 const char* fast_case_code =
6022 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6023 ExpectString(fast_case_code, "0");
6026 const char* slow_case_code =
6027 "obj.x = 1; delete obj.x;"
6028 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6029 ExpectString(slow_case_code, "1");
6033 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6034 v8::Isolate* isolate = CcTest::isolate();
6035 v8::HandleScope scope(isolate);
6036 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6037 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6039 LocalContext context;
6040 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6045 " for (var i = 0; i < 100; i++) {"
6047 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6053 ExpectString(code, "PASSED");
6057 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6058 v8::Isolate* isolate = CcTest::isolate();
6059 v8::HandleScope scope(isolate);
6060 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6061 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6063 LocalContext context;
6064 Local<v8::Object> obj = templ->NewInstance();
6065 obj->TurnOnAccessCheck();
6066 context->Global()->Set(v8_str("obj"), obj);
6070 " for (var i = 0; i < 100; i++) {"
6072 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6078 ExpectString(code, "PASSED");
6082 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6083 i::FLAG_allow_natives_syntax = true;
6084 v8::Isolate* isolate = CcTest::isolate();
6085 v8::HandleScope scope(isolate);
6086 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6087 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6089 LocalContext context;
6090 Local<v8::Object> obj = templ->NewInstance();
6091 context->Global()->Set(v8_str("obj"), obj);
6095 " for (var i = 0; i < 100; i++) {"
6096 " var expected = i;"
6098 " %EnableAccessChecks(obj);"
6099 " expected = undefined;"
6102 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6103 " if (i == 5) %DisableAccessChecks(obj);"
6109 ExpectString(code, "PASSED");
6113 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6114 v8::Isolate* isolate = CcTest::isolate();
6115 v8::HandleScope scope(isolate);
6116 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6117 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6119 LocalContext context;
6120 Local<v8::Object> obj = templ->NewInstance();
6121 context->Global()->Set(v8_str("obj"), obj);
6125 " for (var i = 0; i < 100; i++) {"
6127 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6133 ExpectString(code, "PASSED");
6137 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6138 v8::Isolate* isolate = CcTest::isolate();
6139 v8::HandleScope scope(isolate);
6140 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6141 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6143 LocalContext context;
6144 Local<v8::Object> obj = templ->NewInstance();
6145 context->Global()->Set(v8_str("obj"), obj);
6149 " for (var i = 0; i < 100; i++) {"
6150 " var expected = i;"
6154 " expected = undefined;"
6157 " /* probe minimal Smi number on 32-bit platforms */"
6158 " key = -(1 << 30);"
6159 " expected = undefined;"
6162 " /* probe minimal Smi number on 64-bit platforms */"
6164 " expected = undefined;"
6166 " var v = obj[key];"
6167 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6173 ExpectString(code, "PASSED");
6177 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6178 v8::Isolate* isolate = CcTest::isolate();
6179 v8::HandleScope scope(isolate);
6180 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6181 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6183 LocalContext context;
6184 Local<v8::Object> obj = templ->NewInstance();
6185 context->Global()->Set(v8_str("obj"), obj);
6189 " for (var i = 0; i < 100; i++) {"
6190 " var expected = i;"
6194 " expected = undefined;"
6196 " var v = obj[key];"
6197 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6203 ExpectString(code, "PASSED");
6207 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6208 v8::Isolate* isolate = CcTest::isolate();
6209 v8::HandleScope scope(isolate);
6210 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6211 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6213 LocalContext context;
6214 Local<v8::Object> obj = templ->NewInstance();
6215 context->Global()->Set(v8_str("obj"), obj);
6218 "var original = obj;"
6220 " for (var i = 0; i < 100; i++) {"
6221 " var expected = i;"
6223 " obj = {50: 'foobar'};"
6224 " expected = 'foobar';"
6227 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6228 " if (i == 50) obj = original;"
6234 ExpectString(code, "PASSED");
6238 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6239 v8::Isolate* isolate = CcTest::isolate();
6240 v8::HandleScope scope(isolate);
6241 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6242 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6244 LocalContext context;
6245 Local<v8::Object> obj = templ->NewInstance();
6246 context->Global()->Set(v8_str("obj"), obj);
6249 "var original = obj;"
6251 " for (var i = 0; i < 100; i++) {"
6252 " var expected = i;"
6255 " expected = undefined;"
6258 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6259 " if (i == 5) obj = original;"
6265 ExpectString(code, "PASSED");
6269 THREADED_TEST(IndexedInterceptorOnProto) {
6270 v8::Isolate* isolate = CcTest::isolate();
6271 v8::HandleScope scope(isolate);
6272 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6273 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6275 LocalContext context;
6276 Local<v8::Object> obj = templ->NewInstance();
6277 context->Global()->Set(v8_str("obj"), obj);
6280 "var o = {__proto__: obj};"
6282 " for (var i = 0; i < 100; i++) {"
6284 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6290 ExpectString(code, "PASSED");
6294 THREADED_TEST(MultiContexts) {
6295 v8::Isolate* isolate = CcTest::isolate();
6296 v8::HandleScope scope(isolate);
6297 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6298 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6301 Local<String> password = v8_str("Password");
6303 // Create an environment
6304 LocalContext context0(0, templ);
6305 context0->SetSecurityToken(password);
6306 v8::Handle<v8::Object> global0 = context0->Global();
6307 global0->Set(v8_str("custom"), v8_num(1234));
6308 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6310 // Create an independent environment
6311 LocalContext context1(0, templ);
6312 context1->SetSecurityToken(password);
6313 v8::Handle<v8::Object> global1 = context1->Global();
6314 global1->Set(v8_str("custom"), v8_num(1234));
6315 CHECK_NE(global0, global1);
6316 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6317 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6319 // Now create a new context with the old global
6320 LocalContext context2(0, templ, global1);
6321 context2->SetSecurityToken(password);
6322 v8::Handle<v8::Object> global2 = context2->Global();
6323 CHECK_EQ(global1, global2);
6324 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6325 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6329 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6330 // Make sure that functions created by cloning boilerplates cannot
6331 // communicate through their __proto__ field.
6333 v8::HandleScope scope(CcTest::isolate());
6336 v8::Handle<v8::Object> global0 =
6338 v8::Handle<v8::Object> object0 =
6339 global0->Get(v8_str("Object")).As<v8::Object>();
6340 v8::Handle<v8::Object> tostring0 =
6341 object0->Get(v8_str("toString")).As<v8::Object>();
6342 v8::Handle<v8::Object> proto0 =
6343 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6344 proto0->Set(v8_str("custom"), v8_num(1234));
6347 v8::Handle<v8::Object> global1 =
6349 v8::Handle<v8::Object> object1 =
6350 global1->Get(v8_str("Object")).As<v8::Object>();
6351 v8::Handle<v8::Object> tostring1 =
6352 object1->Get(v8_str("toString")).As<v8::Object>();
6353 v8::Handle<v8::Object> proto1 =
6354 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6355 CHECK(!proto1->Has(v8_str("custom")));
6359 THREADED_TEST(Regress892105) {
6360 // Make sure that object and array literals created by cloning
6361 // boilerplates cannot communicate through their __proto__
6362 // field. This is rather difficult to check, but we try to add stuff
6363 // to Object.prototype and Array.prototype and create a new
6364 // environment. This should succeed.
6366 v8::HandleScope scope(CcTest::isolate());
6368 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6369 "Array.prototype.arr = 4567;"
6373 Local<Script> script0 = Script::Compile(source);
6374 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6377 Local<Script> script1 = Script::Compile(source);
6378 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6382 THREADED_TEST(UndetectableObject) {
6384 v8::HandleScope scope(env->GetIsolate());
6386 Local<v8::FunctionTemplate> desc =
6387 v8::FunctionTemplate::New(env->GetIsolate());
6388 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6390 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6391 env->Global()->Set(v8_str("undetectable"), obj);
6393 ExpectString("undetectable.toString()", "[object Object]");
6394 ExpectString("typeof undetectable", "undefined");
6395 ExpectString("typeof(undetectable)", "undefined");
6396 ExpectBoolean("typeof undetectable == 'undefined'", true);
6397 ExpectBoolean("typeof undetectable == 'object'", false);
6398 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6399 ExpectBoolean("!undetectable", true);
6401 ExpectObject("true&&undetectable", obj);
6402 ExpectBoolean("false&&undetectable", false);
6403 ExpectBoolean("true||undetectable", true);
6404 ExpectObject("false||undetectable", obj);
6406 ExpectObject("undetectable&&true", obj);
6407 ExpectObject("undetectable&&false", obj);
6408 ExpectBoolean("undetectable||true", true);
6409 ExpectBoolean("undetectable||false", false);
6411 ExpectBoolean("undetectable==null", true);
6412 ExpectBoolean("null==undetectable", true);
6413 ExpectBoolean("undetectable==undefined", true);
6414 ExpectBoolean("undefined==undetectable", true);
6415 ExpectBoolean("undetectable==undetectable", true);
6418 ExpectBoolean("undetectable===null", false);
6419 ExpectBoolean("null===undetectable", false);
6420 ExpectBoolean("undetectable===undefined", false);
6421 ExpectBoolean("undefined===undetectable", false);
6422 ExpectBoolean("undetectable===undetectable", true);
6426 THREADED_TEST(VoidLiteral) {
6428 v8::Isolate* isolate = env->GetIsolate();
6429 v8::HandleScope scope(isolate);
6431 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6432 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6434 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6435 env->Global()->Set(v8_str("undetectable"), obj);
6437 ExpectBoolean("undefined == void 0", true);
6438 ExpectBoolean("undetectable == void 0", true);
6439 ExpectBoolean("null == void 0", true);
6440 ExpectBoolean("undefined === void 0", true);
6441 ExpectBoolean("undetectable === void 0", false);
6442 ExpectBoolean("null === void 0", false);
6444 ExpectBoolean("void 0 == undefined", true);
6445 ExpectBoolean("void 0 == undetectable", true);
6446 ExpectBoolean("void 0 == null", true);
6447 ExpectBoolean("void 0 === undefined", true);
6448 ExpectBoolean("void 0 === undetectable", false);
6449 ExpectBoolean("void 0 === null", false);
6451 ExpectString("(function() {"
6453 " return x === void 0;"
6455 " return e.toString();"
6458 "ReferenceError: x is not defined");
6459 ExpectString("(function() {"
6461 " return void 0 === x;"
6463 " return e.toString();"
6466 "ReferenceError: x is not defined");
6470 THREADED_TEST(ExtensibleOnUndetectable) {
6472 v8::Isolate* isolate = env->GetIsolate();
6473 v8::HandleScope scope(isolate);
6475 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6476 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6478 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6479 env->Global()->Set(v8_str("undetectable"), obj);
6481 Local<String> source = v8_str("undetectable.x = 42;"
6484 Local<Script> script = Script::Compile(source);
6486 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6488 ExpectBoolean("Object.isExtensible(undetectable)", true);
6490 source = v8_str("Object.preventExtensions(undetectable);");
6491 script = Script::Compile(source);
6493 ExpectBoolean("Object.isExtensible(undetectable)", false);
6495 source = v8_str("undetectable.y = 2000;");
6496 script = Script::Compile(source);
6498 ExpectBoolean("undetectable.y == undefined", true);
6503 THREADED_TEST(UndetectableString) {
6505 v8::HandleScope scope(env->GetIsolate());
6507 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6508 String::kUndetectableString);
6509 env->Global()->Set(v8_str("undetectable"), obj);
6511 ExpectString("undetectable", "foo");
6512 ExpectString("typeof undetectable", "undefined");
6513 ExpectString("typeof(undetectable)", "undefined");
6514 ExpectBoolean("typeof undetectable == 'undefined'", true);
6515 ExpectBoolean("typeof undetectable == 'string'", false);
6516 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6517 ExpectBoolean("!undetectable", true);
6519 ExpectObject("true&&undetectable", obj);
6520 ExpectBoolean("false&&undetectable", false);
6521 ExpectBoolean("true||undetectable", true);
6522 ExpectObject("false||undetectable", obj);
6524 ExpectObject("undetectable&&true", obj);
6525 ExpectObject("undetectable&&false", obj);
6526 ExpectBoolean("undetectable||true", true);
6527 ExpectBoolean("undetectable||false", false);
6529 ExpectBoolean("undetectable==null", true);
6530 ExpectBoolean("null==undetectable", true);
6531 ExpectBoolean("undetectable==undefined", true);
6532 ExpectBoolean("undefined==undetectable", true);
6533 ExpectBoolean("undetectable==undetectable", true);
6536 ExpectBoolean("undetectable===null", false);
6537 ExpectBoolean("null===undetectable", false);
6538 ExpectBoolean("undetectable===undefined", false);
6539 ExpectBoolean("undefined===undetectable", false);
6540 ExpectBoolean("undetectable===undetectable", true);
6544 TEST(UndetectableOptimized) {
6545 i::FLAG_allow_natives_syntax = true;
6547 v8::HandleScope scope(env->GetIsolate());
6549 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6550 String::kUndetectableString);
6551 env->Global()->Set(v8_str("undetectable"), obj);
6552 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6555 "function testBranch() {"
6556 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6557 " if (%_IsUndetectableObject(detectable)) throw 2;"
6559 "function testBool() {"
6560 " var b1 = !%_IsUndetectableObject(undetectable);"
6561 " var b2 = %_IsUndetectableObject(detectable);"
6566 "%OptimizeFunctionOnNextCall(testBranch);"
6567 "%OptimizeFunctionOnNextCall(testBool);"
6568 "for (var i = 0; i < 10; i++) {"
6577 template <typename T> static void USE(T) { }
6580 // The point of this test is type checking. We run it only so compilers
6581 // don't complain about an unused function.
6582 TEST(PersistentHandles) {
6584 v8::Isolate* isolate = CcTest::isolate();
6585 v8::HandleScope scope(isolate);
6586 Local<String> str = v8_str("foo");
6587 v8::Persistent<String> p_str(isolate, str);
6589 Local<Script> scr = Script::Compile(v8_str(""));
6590 v8::Persistent<Script> p_scr(isolate, scr);
6592 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6593 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6598 static void HandleLogDelegator(
6599 const v8::FunctionCallbackInfo<v8::Value>& args) {
6600 ApiTestFuzzer::Fuzz();
6604 THREADED_TEST(GlobalObjectTemplate) {
6605 v8::Isolate* isolate = CcTest::isolate();
6606 v8::HandleScope handle_scope(isolate);
6607 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6608 global_template->Set(v8_str("JSNI_Log"),
6609 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6610 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6611 Context::Scope context_scope(context);
6612 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6616 static const char* kSimpleExtensionSource =
6622 TEST(SimpleExtensions) {
6623 v8::HandleScope handle_scope(CcTest::isolate());
6624 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6625 const char* extension_names[] = { "simpletest" };
6626 v8::ExtensionConfiguration extensions(1, extension_names);
6627 v8::Handle<Context> context =
6628 Context::New(CcTest::isolate(), &extensions);
6629 Context::Scope lock(context);
6630 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6631 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6635 TEST(NullExtensions) {
6636 v8::HandleScope handle_scope(CcTest::isolate());
6637 v8::RegisterExtension(new Extension("nulltest", NULL));
6638 const char* extension_names[] = { "nulltest" };
6639 v8::ExtensionConfiguration extensions(1, extension_names);
6640 v8::Handle<Context> context =
6641 Context::New(CcTest::isolate(), &extensions);
6642 Context::Scope lock(context);
6643 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6644 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6648 static const char* kEmbeddedExtensionSource =
6649 "function Ret54321(){return 54321;}~~@@$"
6650 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6651 static const int kEmbeddedExtensionSourceValidLen = 34;
6654 TEST(ExtensionMissingSourceLength) {
6655 v8::HandleScope handle_scope(CcTest::isolate());
6656 v8::RegisterExtension(new Extension("srclentest_fail",
6657 kEmbeddedExtensionSource));
6658 const char* extension_names[] = { "srclentest_fail" };
6659 v8::ExtensionConfiguration extensions(1, extension_names);
6660 v8::Handle<Context> context =
6661 Context::New(CcTest::isolate(), &extensions);
6662 CHECK_EQ(0, *context);
6666 TEST(ExtensionWithSourceLength) {
6667 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6668 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6669 v8::HandleScope handle_scope(CcTest::isolate());
6670 i::ScopedVector<char> extension_name(32);
6671 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6672 v8::RegisterExtension(new Extension(extension_name.start(),
6673 kEmbeddedExtensionSource, 0, 0,
6675 const char* extension_names[1] = { extension_name.start() };
6676 v8::ExtensionConfiguration extensions(1, extension_names);
6677 v8::Handle<Context> context =
6678 Context::New(CcTest::isolate(), &extensions);
6679 if (source_len == kEmbeddedExtensionSourceValidLen) {
6680 Context::Scope lock(context);
6681 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6682 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6684 // Anything but exactly the right length should fail to compile.
6685 CHECK_EQ(0, *context);
6691 static const char* kEvalExtensionSource1 =
6692 "function UseEval1() {"
6694 " return eval('x');"
6698 static const char* kEvalExtensionSource2 =
6702 " return eval('x');"
6704 " this.UseEval2 = e;"
6708 TEST(UseEvalFromExtension) {
6709 v8::HandleScope handle_scope(CcTest::isolate());
6710 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6711 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6712 const char* extension_names[] = { "evaltest1", "evaltest2" };
6713 v8::ExtensionConfiguration extensions(2, extension_names);
6714 v8::Handle<Context> context =
6715 Context::New(CcTest::isolate(), &extensions);
6716 Context::Scope lock(context);
6717 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6718 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6719 result = Script::Compile(v8_str("UseEval2()"))->Run();
6720 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6724 static const char* kWithExtensionSource1 =
6725 "function UseWith1() {"
6727 " with({x:87}) { return x; }"
6732 static const char* kWithExtensionSource2 =
6736 " with ({x:87}) { return x; }"
6738 " this.UseWith2 = e;"
6742 TEST(UseWithFromExtension) {
6743 v8::HandleScope handle_scope(CcTest::isolate());
6744 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6745 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6746 const char* extension_names[] = { "withtest1", "withtest2" };
6747 v8::ExtensionConfiguration extensions(2, extension_names);
6748 v8::Handle<Context> context =
6749 Context::New(CcTest::isolate(), &extensions);
6750 Context::Scope lock(context);
6751 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6752 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6753 result = Script::Compile(v8_str("UseWith2()"))->Run();
6754 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6758 TEST(AutoExtensions) {
6759 v8::HandleScope handle_scope(CcTest::isolate());
6760 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6761 extension->set_auto_enable(true);
6762 v8::RegisterExtension(extension);
6763 v8::Handle<Context> context =
6764 Context::New(CcTest::isolate());
6765 Context::Scope lock(context);
6766 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6767 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6771 static const char* kSyntaxErrorInExtensionSource =
6775 // Test that a syntax error in an extension does not cause a fatal
6776 // error but results in an empty context.
6777 TEST(SyntaxErrorExtensions) {
6778 v8::HandleScope handle_scope(CcTest::isolate());
6779 v8::RegisterExtension(new Extension("syntaxerror",
6780 kSyntaxErrorInExtensionSource));
6781 const char* extension_names[] = { "syntaxerror" };
6782 v8::ExtensionConfiguration extensions(1, extension_names);
6783 v8::Handle<Context> context =
6784 Context::New(CcTest::isolate(), &extensions);
6785 CHECK(context.IsEmpty());
6789 static const char* kExceptionInExtensionSource =
6793 // Test that an exception when installing an extension does not cause
6794 // a fatal error but results in an empty context.
6795 TEST(ExceptionExtensions) {
6796 v8::HandleScope handle_scope(CcTest::isolate());
6797 v8::RegisterExtension(new Extension("exception",
6798 kExceptionInExtensionSource));
6799 const char* extension_names[] = { "exception" };
6800 v8::ExtensionConfiguration extensions(1, extension_names);
6801 v8::Handle<Context> context =
6802 Context::New(CcTest::isolate(), &extensions);
6803 CHECK(context.IsEmpty());
6807 static const char* kNativeCallInExtensionSource =
6808 "function call_runtime_last_index_of(x) {"
6809 " return %StringLastIndexOf(x, 'bob', 10);"
6813 static const char* kNativeCallTest =
6814 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6816 // Test that a native runtime calls are supported in extensions.
6817 TEST(NativeCallInExtensions) {
6818 v8::HandleScope handle_scope(CcTest::isolate());
6819 v8::RegisterExtension(new Extension("nativecall",
6820 kNativeCallInExtensionSource));
6821 const char* extension_names[] = { "nativecall" };
6822 v8::ExtensionConfiguration extensions(1, extension_names);
6823 v8::Handle<Context> context =
6824 Context::New(CcTest::isolate(), &extensions);
6825 Context::Scope lock(context);
6826 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6827 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6831 class NativeFunctionExtension : public Extension {
6833 NativeFunctionExtension(const char* name,
6835 v8::FunctionCallback fun = &Echo)
6836 : Extension(name, source),
6839 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6840 v8::Isolate* isolate,
6841 v8::Handle<v8::String> name) {
6842 return v8::FunctionTemplate::New(isolate, function_);
6845 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6846 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6849 v8::FunctionCallback function_;
6853 TEST(NativeFunctionDeclaration) {
6854 v8::HandleScope handle_scope(CcTest::isolate());
6855 const char* name = "nativedecl";
6856 v8::RegisterExtension(new NativeFunctionExtension(name,
6857 "native function foo();"));
6858 const char* extension_names[] = { name };
6859 v8::ExtensionConfiguration extensions(1, extension_names);
6860 v8::Handle<Context> context =
6861 Context::New(CcTest::isolate(), &extensions);
6862 Context::Scope lock(context);
6863 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6864 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6868 TEST(NativeFunctionDeclarationError) {
6869 v8::HandleScope handle_scope(CcTest::isolate());
6870 const char* name = "nativedeclerr";
6871 // Syntax error in extension code.
6872 v8::RegisterExtension(new NativeFunctionExtension(name,
6873 "native\nfunction foo();"));
6874 const char* extension_names[] = { name };
6875 v8::ExtensionConfiguration extensions(1, extension_names);
6876 v8::Handle<Context> context =
6877 Context::New(CcTest::isolate(), &extensions);
6878 CHECK(context.IsEmpty());
6882 TEST(NativeFunctionDeclarationErrorEscape) {
6883 v8::HandleScope handle_scope(CcTest::isolate());
6884 const char* name = "nativedeclerresc";
6885 // Syntax error in extension code - escape code in "native" means that
6886 // it's not treated as a keyword.
6887 v8::RegisterExtension(new NativeFunctionExtension(
6889 "nativ\\u0065 function foo();"));
6890 const char* extension_names[] = { name };
6891 v8::ExtensionConfiguration extensions(1, extension_names);
6892 v8::Handle<Context> context =
6893 Context::New(CcTest::isolate(), &extensions);
6894 CHECK(context.IsEmpty());
6898 static void CheckDependencies(const char* name, const char* expected) {
6899 v8::HandleScope handle_scope(CcTest::isolate());
6900 v8::ExtensionConfiguration config(1, &name);
6901 LocalContext context(&config);
6902 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6903 context->Global()->Get(v8_str("loaded")));
6914 THREADED_TEST(ExtensionDependency) {
6915 static const char* kEDeps[] = { "D" };
6916 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6917 static const char* kDDeps[] = { "B", "C" };
6918 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6919 static const char* kBCDeps[] = { "A" };
6920 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6921 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6922 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6923 CheckDependencies("A", "undefinedA");
6924 CheckDependencies("B", "undefinedAB");
6925 CheckDependencies("C", "undefinedAC");
6926 CheckDependencies("D", "undefinedABCD");
6927 CheckDependencies("E", "undefinedABCDE");
6928 v8::HandleScope handle_scope(CcTest::isolate());
6929 static const char* exts[2] = { "C", "E" };
6930 v8::ExtensionConfiguration config(2, exts);
6931 LocalContext context(&config);
6932 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6936 static const char* kExtensionTestScript =
6937 "native function A();"
6938 "native function B();"
6939 "native function C();"
6941 " if (i == 0) return A();"
6942 " if (i == 1) return B();"
6943 " if (i == 2) return C();"
6947 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6948 ApiTestFuzzer::Fuzz();
6949 if (args.IsConstructCall()) {
6950 args.This()->Set(v8_str("data"), args.Data());
6951 args.GetReturnValue().SetNull();
6954 args.GetReturnValue().Set(args.Data());
6958 class FunctionExtension : public Extension {
6960 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6961 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6962 v8::Isolate* isolate,
6963 v8::Handle<String> name);
6967 static int lookup_count = 0;
6968 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6969 v8::Isolate* isolate, v8::Handle<String> name) {
6971 if (name->Equals(v8_str("A"))) {
6972 return v8::FunctionTemplate::New(
6973 isolate, CallFun, v8::Integer::New(isolate, 8));
6974 } else if (name->Equals(v8_str("B"))) {
6975 return v8::FunctionTemplate::New(
6976 isolate, CallFun, v8::Integer::New(isolate, 7));
6977 } else if (name->Equals(v8_str("C"))) {
6978 return v8::FunctionTemplate::New(
6979 isolate, CallFun, v8::Integer::New(isolate, 6));
6981 return v8::Handle<v8::FunctionTemplate>();
6986 THREADED_TEST(FunctionLookup) {
6987 v8::RegisterExtension(new FunctionExtension());
6988 v8::HandleScope handle_scope(CcTest::isolate());
6989 static const char* exts[1] = { "functiontest" };
6990 v8::ExtensionConfiguration config(1, exts);
6991 LocalContext context(&config);
6992 CHECK_EQ(3, lookup_count);
6993 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
6994 Script::Compile(v8_str("Foo(0)"))->Run());
6995 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
6996 Script::Compile(v8_str("Foo(1)"))->Run());
6997 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
6998 Script::Compile(v8_str("Foo(2)"))->Run());
7002 THREADED_TEST(NativeFunctionConstructCall) {
7003 v8::RegisterExtension(new FunctionExtension());
7004 v8::HandleScope handle_scope(CcTest::isolate());
7005 static const char* exts[1] = { "functiontest" };
7006 v8::ExtensionConfiguration config(1, exts);
7007 LocalContext context(&config);
7008 for (int i = 0; i < 10; i++) {
7009 // Run a few times to ensure that allocation of objects doesn't
7010 // change behavior of a constructor function.
7011 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7012 Script::Compile(v8_str("(new A()).data"))->Run());
7013 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7014 Script::Compile(v8_str("(new B()).data"))->Run());
7015 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7016 Script::Compile(v8_str("(new C()).data"))->Run());
7021 static const char* last_location;
7022 static const char* last_message;
7023 void StoringErrorCallback(const char* location, const char* message) {
7024 if (last_location == NULL) {
7025 last_location = location;
7026 last_message = message;
7031 // ErrorReporting creates a circular extensions configuration and
7032 // tests that the fatal error handler gets called. This renders V8
7033 // unusable and therefore this test cannot be run in parallel.
7034 TEST(ErrorReporting) {
7035 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7036 static const char* aDeps[] = { "B" };
7037 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7038 static const char* bDeps[] = { "A" };
7039 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7040 last_location = NULL;
7041 v8::ExtensionConfiguration config(1, bDeps);
7042 v8::Handle<Context> context =
7043 Context::New(CcTest::isolate(), &config);
7044 CHECK(context.IsEmpty());
7045 CHECK_NE(last_location, NULL);
7049 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7050 v8::Handle<Value> data) {
7051 CHECK(message->GetScriptResourceName()->IsUndefined());
7052 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7053 message->GetLineNumber();
7054 message->GetSourceLine();
7058 THREADED_TEST(ErrorWithMissingScriptInfo) {
7059 LocalContext context;
7060 v8::HandleScope scope(context->GetIsolate());
7061 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7062 Script::Compile(v8_str("throw Error()"))->Run();
7063 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7067 struct FlagAndPersistent {
7069 v8::Persistent<v8::Object> handle;
7073 static void DisposeAndSetFlag(
7074 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7075 data.GetParameter()->handle.Reset();
7076 data.GetParameter()->flag = true;
7080 THREADED_TEST(IndependentWeakHandle) {
7081 v8::Isolate* iso = CcTest::isolate();
7082 v8::HandleScope scope(iso);
7083 v8::Handle<Context> context = Context::New(iso);
7084 Context::Scope context_scope(context);
7086 FlagAndPersistent object_a, object_b;
7089 v8::HandleScope handle_scope(iso);
7090 object_a.handle.Reset(iso, v8::Object::New(iso));
7091 object_b.handle.Reset(iso, v8::Object::New(iso));
7094 object_a.flag = false;
7095 object_b.flag = false;
7096 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7097 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7098 CHECK(!object_b.handle.IsIndependent());
7099 object_a.handle.MarkIndependent();
7100 object_b.handle.MarkIndependent();
7101 CHECK(object_b.handle.IsIndependent());
7102 CcTest::heap()->PerformScavenge();
7103 CHECK(object_a.flag);
7104 CHECK(object_b.flag);
7108 static void InvokeScavenge() {
7109 CcTest::heap()->PerformScavenge();
7113 static void InvokeMarkSweep() {
7114 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7118 static void ForceScavenge(
7119 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7120 data.GetParameter()->handle.Reset();
7121 data.GetParameter()->flag = true;
7126 static void ForceMarkSweep(
7127 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7128 data.GetParameter()->handle.Reset();
7129 data.GetParameter()->flag = true;
7134 THREADED_TEST(GCFromWeakCallbacks) {
7135 v8::Isolate* isolate = CcTest::isolate();
7136 v8::HandleScope scope(isolate);
7137 v8::Handle<Context> context = Context::New(isolate);
7138 Context::Scope context_scope(context);
7140 static const int kNumberOfGCTypes = 2;
7141 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7143 Callback gc_forcing_callback[kNumberOfGCTypes] =
7144 {&ForceScavenge, &ForceMarkSweep};
7146 typedef void (*GCInvoker)();
7147 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7149 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7150 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7151 FlagAndPersistent object;
7153 v8::HandleScope handle_scope(isolate);
7154 object.handle.Reset(isolate, v8::Object::New(isolate));
7156 object.flag = false;
7157 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7158 object.handle.MarkIndependent();
7159 invoke_gc[outer_gc]();
7166 static void RevivingCallback(
7167 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7168 data.GetParameter()->handle.ClearWeak();
7169 data.GetParameter()->flag = true;
7173 THREADED_TEST(IndependentHandleRevival) {
7174 v8::Isolate* isolate = CcTest::isolate();
7175 v8::HandleScope scope(isolate);
7176 v8::Handle<Context> context = Context::New(isolate);
7177 Context::Scope context_scope(context);
7179 FlagAndPersistent object;
7181 v8::HandleScope handle_scope(isolate);
7182 v8::Local<v8::Object> o = v8::Object::New(isolate);
7183 object.handle.Reset(isolate, o);
7184 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7185 v8::Local<String> y_str = v8_str("y");
7186 o->Set(y_str, y_str);
7188 object.flag = false;
7189 object.handle.SetWeak(&object, &RevivingCallback);
7190 object.handle.MarkIndependent();
7191 CcTest::heap()->PerformScavenge();
7193 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7195 v8::HandleScope handle_scope(isolate);
7196 v8::Local<v8::Object> o =
7197 v8::Local<v8::Object>::New(isolate, object.handle);
7198 v8::Local<String> y_str = v8_str("y");
7199 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7200 CHECK(o->Get(y_str)->Equals(y_str));
7205 v8::Handle<Function> args_fun;
7208 static void ArgumentsTestCallback(
7209 const v8::FunctionCallbackInfo<v8::Value>& args) {
7210 ApiTestFuzzer::Fuzz();
7211 v8::Isolate* isolate = args.GetIsolate();
7212 CHECK_EQ(args_fun, args.Callee());
7213 CHECK_EQ(3, args.Length());
7214 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7215 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7216 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7217 CHECK_EQ(v8::Undefined(isolate), args[3]);
7218 v8::HandleScope scope(args.GetIsolate());
7219 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7223 THREADED_TEST(Arguments) {
7224 v8::Isolate* isolate = CcTest::isolate();
7225 v8::HandleScope scope(isolate);
7226 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7227 global->Set(v8_str("f"),
7228 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7229 LocalContext context(NULL, global);
7230 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7231 v8_compile("f(1, 2, 3)")->Run();
7235 static void NoBlockGetterX(Local<String> name,
7236 const v8::PropertyCallbackInfo<v8::Value>&) {
7240 static void NoBlockGetterI(uint32_t index,
7241 const v8::PropertyCallbackInfo<v8::Value>&) {
7245 static void PDeleter(Local<String> name,
7246 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7247 if (!name->Equals(v8_str("foo"))) {
7248 return; // not intercepted
7251 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7255 static void IDeleter(uint32_t index,
7256 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7258 return; // not intercepted
7261 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7265 THREADED_TEST(Deleter) {
7266 v8::Isolate* isolate = CcTest::isolate();
7267 v8::HandleScope scope(isolate);
7268 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7269 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7270 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7271 LocalContext context;
7272 context->Global()->Set(v8_str("k"), obj->NewInstance());
7278 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7279 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7281 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7282 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7284 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7285 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7287 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7288 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7292 static void GetK(Local<String> name,
7293 const v8::PropertyCallbackInfo<v8::Value>& info) {
7294 ApiTestFuzzer::Fuzz();
7295 if (name->Equals(v8_str("foo")) ||
7296 name->Equals(v8_str("bar")) ||
7297 name->Equals(v8_str("baz"))) {
7298 info.GetReturnValue().SetUndefined();
7303 static void IndexedGetK(uint32_t index,
7304 const v8::PropertyCallbackInfo<v8::Value>& info) {
7305 ApiTestFuzzer::Fuzz();
7306 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7310 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7311 ApiTestFuzzer::Fuzz();
7312 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7313 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7314 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7315 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7316 info.GetReturnValue().Set(result);
7320 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7321 ApiTestFuzzer::Fuzz();
7322 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7323 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7324 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7325 info.GetReturnValue().Set(result);
7329 THREADED_TEST(Enumerators) {
7330 v8::Isolate* isolate = CcTest::isolate();
7331 v8::HandleScope scope(isolate);
7332 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7333 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7334 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7335 LocalContext context;
7336 context->Global()->Set(v8_str("k"), obj->NewInstance());
7337 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7342 "k[4294967295] = 0;"
7344 "k[4294967296] = 0;"
7348 "k[30000000000] = 0;"
7351 "for (var prop in k) {"
7352 " result.push(prop);"
7355 // Check that we get all the property names returned including the
7356 // ones from the enumerators in the right order: indexed properties
7357 // in numerical order, indexed interceptor properties, named
7358 // properties in insertion order, named interceptor properties.
7359 // This order is not mandated by the spec, so this test is just
7360 // documenting our behavior.
7361 CHECK_EQ(17, result->Length());
7362 // Indexed properties in numerical order.
7363 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7364 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7365 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7366 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7367 // Indexed interceptor properties in the order they are returned
7368 // from the enumerator interceptor.
7369 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7370 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7371 // Named properties in insertion order.
7372 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7373 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7374 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7375 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7376 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7377 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7378 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7379 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7380 // Named interceptor properties.
7381 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7382 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7383 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7388 int p_getter_count2;
7391 static void PGetter(Local<String> name,
7392 const v8::PropertyCallbackInfo<v8::Value>& info) {
7393 ApiTestFuzzer::Fuzz();
7395 v8::Handle<v8::Object> global =
7396 info.GetIsolate()->GetCurrentContext()->Global();
7397 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7398 if (name->Equals(v8_str("p1"))) {
7399 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7400 } else if (name->Equals(v8_str("p2"))) {
7401 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7402 } else if (name->Equals(v8_str("p3"))) {
7403 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7404 } else if (name->Equals(v8_str("p4"))) {
7405 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7410 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7411 ApiTestFuzzer::Fuzz();
7412 LocalContext context;
7413 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7415 "o1.__proto__ = { };"
7416 "var o2 = { __proto__: o1 };"
7417 "var o3 = { __proto__: o2 };"
7418 "var o4 = { __proto__: o3 };"
7419 "for (var i = 0; i < 10; i++) o4.p4;"
7420 "for (var i = 0; i < 10; i++) o3.p3;"
7421 "for (var i = 0; i < 10; i++) o2.p2;"
7422 "for (var i = 0; i < 10; i++) o1.p1;");
7426 static void PGetter2(Local<String> name,
7427 const v8::PropertyCallbackInfo<v8::Value>& info) {
7428 ApiTestFuzzer::Fuzz();
7430 v8::Handle<v8::Object> global =
7431 info.GetIsolate()->GetCurrentContext()->Global();
7432 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7433 if (name->Equals(v8_str("p1"))) {
7434 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7435 } else if (name->Equals(v8_str("p2"))) {
7436 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7437 } else if (name->Equals(v8_str("p3"))) {
7438 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7439 } else if (name->Equals(v8_str("p4"))) {
7440 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7445 THREADED_TEST(GetterHolders) {
7446 v8::Isolate* isolate = CcTest::isolate();
7447 v8::HandleScope scope(isolate);
7448 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7449 obj->SetAccessor(v8_str("p1"), PGetter);
7450 obj->SetAccessor(v8_str("p2"), PGetter);
7451 obj->SetAccessor(v8_str("p3"), PGetter);
7452 obj->SetAccessor(v8_str("p4"), PGetter);
7455 CHECK_EQ(40, p_getter_count);
7459 THREADED_TEST(PreInterceptorHolders) {
7460 v8::Isolate* isolate = CcTest::isolate();
7461 v8::HandleScope scope(isolate);
7462 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7463 obj->SetNamedPropertyHandler(PGetter2);
7464 p_getter_count2 = 0;
7466 CHECK_EQ(40, p_getter_count2);
7470 THREADED_TEST(ObjectInstantiation) {
7471 v8::Isolate* isolate = CcTest::isolate();
7472 v8::HandleScope scope(isolate);
7473 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7474 templ->SetAccessor(v8_str("t"), PGetter2);
7475 LocalContext context;
7476 context->Global()->Set(v8_str("o"), templ->NewInstance());
7477 for (int i = 0; i < 100; i++) {
7478 v8::HandleScope inner_scope(CcTest::isolate());
7479 v8::Handle<v8::Object> obj = templ->NewInstance();
7480 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7481 context->Global()->Set(v8_str("o2"), obj);
7482 v8::Handle<Value> value =
7483 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7484 CHECK_EQ(v8::True(isolate), value);
7485 context->Global()->Set(v8_str("o"), obj);
7490 static int StrCmp16(uint16_t* a, uint16_t* b) {
7492 if (*a == 0 && *b == 0) return 0;
7493 if (*a != *b) return 0 + *a - *b;
7500 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7502 if (n-- == 0) return 0;
7503 if (*a == 0 && *b == 0) return 0;
7504 if (*a != *b) return 0 + *a - *b;
7511 int GetUtf8Length(Handle<String> str) {
7512 int len = str->Utf8Length();
7514 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7515 i::FlattenString(istr);
7516 len = str->Utf8Length();
7522 THREADED_TEST(StringWrite) {
7523 LocalContext context;
7524 v8::HandleScope scope(context->GetIsolate());
7525 v8::Handle<String> str = v8_str("abcde");
7526 // abc<Icelandic eth><Unicode snowman>.
7527 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7528 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7529 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7530 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7531 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7532 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7533 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7534 // single lead surrogate
7535 uint16_t lead[1] = { 0xd800 };
7536 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7537 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7538 // single trail surrogate
7539 uint16_t trail[1] = { 0xdc00 };
7540 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7541 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7543 uint16_t pair[2] = { 0xd800, 0xdc00 };
7544 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7545 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7546 const int kStride = 4; // Must match stride in for loops in JS below.
7549 "for (var i = 0; i < 0xd800; i += 4) {"
7550 " left = left + String.fromCharCode(i);"
7554 "for (var i = 0; i < 0xd800; i += 4) {"
7555 " right = String.fromCharCode(i) + right;"
7557 v8::Handle<v8::Object> global = context->Global();
7558 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7559 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7561 CHECK_EQ(5, str2->Length());
7562 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7563 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7566 char utf8buf[0xd800 * 3];
7571 memset(utf8buf, 0x1, 1000);
7572 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7574 CHECK_EQ(5, charlen);
7575 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7577 memset(utf8buf, 0x1, 1000);
7578 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7580 CHECK_EQ(5, charlen);
7581 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7583 memset(utf8buf, 0x1, 1000);
7584 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7586 CHECK_EQ(4, charlen);
7587 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7589 memset(utf8buf, 0x1, 1000);
7590 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7592 CHECK_EQ(4, charlen);
7593 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7595 memset(utf8buf, 0x1, 1000);
7596 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7598 CHECK_EQ(4, charlen);
7599 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7601 memset(utf8buf, 0x1, 1000);
7602 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7604 CHECK_EQ(3, charlen);
7605 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7607 memset(utf8buf, 0x1, 1000);
7608 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7610 CHECK_EQ(3, charlen);
7611 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7613 memset(utf8buf, 0x1, 1000);
7614 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7616 CHECK_EQ(2, charlen);
7617 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7619 // allow orphan surrogates by default
7620 memset(utf8buf, 0x1, 1000);
7621 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7623 CHECK_EQ(8, charlen);
7624 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7626 // replace orphan surrogates with unicode replacement character
7627 memset(utf8buf, 0x1, 1000);
7628 len = orphans_str->WriteUtf8(utf8buf,
7631 String::REPLACE_INVALID_UTF8);
7633 CHECK_EQ(8, charlen);
7634 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7636 // replace single lead surrogate with unicode replacement character
7637 memset(utf8buf, 0x1, 1000);
7638 len = lead_str->WriteUtf8(utf8buf,
7641 String::REPLACE_INVALID_UTF8);
7643 CHECK_EQ(1, charlen);
7644 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7646 // replace single trail surrogate with unicode replacement character
7647 memset(utf8buf, 0x1, 1000);
7648 len = trail_str->WriteUtf8(utf8buf,
7651 String::REPLACE_INVALID_UTF8);
7653 CHECK_EQ(1, charlen);
7654 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7656 // do not replace / write anything if surrogate pair does not fit the buffer
7658 memset(utf8buf, 0x1, 1000);
7659 len = pair_str->WriteUtf8(utf8buf,
7662 String::REPLACE_INVALID_UTF8);
7664 CHECK_EQ(0, charlen);
7666 memset(utf8buf, 0x1, sizeof(utf8buf));
7667 len = GetUtf8Length(left_tree);
7669 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7670 CHECK_EQ(utf8_expected, len);
7671 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7672 CHECK_EQ(utf8_expected, len);
7673 CHECK_EQ(0xd800 / kStride, charlen);
7674 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7675 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7676 CHECK_EQ(0xc0 - kStride,
7677 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7678 CHECK_EQ(1, utf8buf[utf8_expected]);
7680 memset(utf8buf, 0x1, sizeof(utf8buf));
7681 len = GetUtf8Length(right_tree);
7682 CHECK_EQ(utf8_expected, len);
7683 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7684 CHECK_EQ(utf8_expected, len);
7685 CHECK_EQ(0xd800 / kStride, charlen);
7686 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7687 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7688 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7689 CHECK_EQ(1, utf8buf[utf8_expected]);
7691 memset(buf, 0x1, sizeof(buf));
7692 memset(wbuf, 0x1, sizeof(wbuf));
7693 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7695 len = str->Write(wbuf);
7697 CHECK_EQ(0, strcmp("abcde", buf));
7698 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7699 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7701 memset(buf, 0x1, sizeof(buf));
7702 memset(wbuf, 0x1, sizeof(wbuf));
7703 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7705 len = str->Write(wbuf, 0, 4);
7707 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7708 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7709 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7711 memset(buf, 0x1, sizeof(buf));
7712 memset(wbuf, 0x1, sizeof(wbuf));
7713 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7715 len = str->Write(wbuf, 0, 5);
7717 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7718 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7719 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7721 memset(buf, 0x1, sizeof(buf));
7722 memset(wbuf, 0x1, sizeof(wbuf));
7723 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7725 len = str->Write(wbuf, 0, 6);
7727 CHECK_EQ(0, strcmp("abcde", buf));
7728 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7729 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7731 memset(buf, 0x1, sizeof(buf));
7732 memset(wbuf, 0x1, sizeof(wbuf));
7733 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7735 len = str->Write(wbuf, 4, -1);
7737 CHECK_EQ(0, strcmp("e", buf));
7738 uint16_t answer5[] = {'e', '\0'};
7739 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7741 memset(buf, 0x1, sizeof(buf));
7742 memset(wbuf, 0x1, sizeof(wbuf));
7743 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7745 len = str->Write(wbuf, 4, 6);
7747 CHECK_EQ(0, strcmp("e", buf));
7748 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7750 memset(buf, 0x1, sizeof(buf));
7751 memset(wbuf, 0x1, sizeof(wbuf));
7752 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7754 len = str->Write(wbuf, 4, 1);
7756 CHECK_EQ(0, strncmp("e\1", buf, 2));
7757 uint16_t answer6[] = {'e', 0x101};
7758 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7760 memset(buf, 0x1, sizeof(buf));
7761 memset(wbuf, 0x1, sizeof(wbuf));
7762 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7764 len = str->Write(wbuf, 3, 1);
7766 CHECK_EQ(0, strncmp("d\1", buf, 2));
7767 uint16_t answer7[] = {'d', 0x101};
7768 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7770 memset(wbuf, 0x1, sizeof(wbuf));
7772 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7774 CHECK_EQ('X', wbuf[5]);
7775 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7776 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7777 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7778 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7780 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7782 memset(buf, 0x1, sizeof(buf));
7784 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7787 String::NO_NULL_TERMINATION);
7789 CHECK_EQ('X', buf[5]);
7790 CHECK_EQ(0, strncmp("abcde", buf, 5));
7791 CHECK_NE(0, strcmp("abcde", buf));
7793 CHECK_EQ(0, strcmp("abcde", buf));
7795 memset(utf8buf, 0x1, sizeof(utf8buf));
7797 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7798 String::NO_NULL_TERMINATION);
7800 CHECK_EQ('X', utf8buf[8]);
7801 CHECK_EQ(5, charlen);
7802 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7803 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7805 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7807 memset(utf8buf, 0x1, sizeof(utf8buf));
7809 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7810 String::NO_NULL_TERMINATION);
7812 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7813 CHECK_EQ(5, charlen);
7815 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7817 memset(buf, 0x1, sizeof(buf));
7818 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7820 CHECK_EQ(0, strcmp("abc", buf));
7821 CHECK_EQ(0, buf[3]);
7822 CHECK_EQ(0, strcmp("def", buf + 4));
7824 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7825 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7826 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7830 static void Utf16Helper(
7831 LocalContext& context,
7833 const char* lengths_name,
7835 Local<v8::Array> a =
7836 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7837 Local<v8::Array> alens =
7838 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7839 for (int i = 0; i < len; i++) {
7840 Local<v8::String> string =
7841 Local<v8::String>::Cast(a->Get(i));
7842 Local<v8::Number> expected_len =
7843 Local<v8::Number>::Cast(alens->Get(i));
7844 int length = GetUtf8Length(string);
7845 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7850 static uint16_t StringGet(Handle<String> str, int index) {
7851 i::Handle<i::String> istring =
7852 v8::Utils::OpenHandle(String::Cast(*str));
7853 return istring->Get(index);
7857 static void WriteUtf8Helper(
7858 LocalContext& context,
7860 const char* lengths_name,
7862 Local<v8::Array> b =
7863 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7864 Local<v8::Array> alens =
7865 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7868 for (int i = 0; i < len; i++) {
7869 Local<v8::String> string =
7870 Local<v8::String>::Cast(b->Get(i));
7871 Local<v8::Number> expected_len =
7872 Local<v8::Number>::Cast(alens->Get(i));
7873 int utf8_length = static_cast<int>(expected_len->Value());
7874 for (int j = utf8_length + 1; j >= 0; j--) {
7875 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7876 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7879 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7881 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7882 CHECK_GE(utf8_length + 1, utf8_written);
7883 CHECK_GE(utf8_length, utf8_written2);
7884 for (int k = 0; k < utf8_written2; k++) {
7885 CHECK_EQ(buffer[k], buffer2[k]);
7887 CHECK(nchars * 3 >= utf8_written - 1);
7888 CHECK(nchars <= utf8_written);
7889 if (j == utf8_length + 1) {
7890 CHECK_EQ(utf8_written2, utf8_length);
7891 CHECK_EQ(utf8_written2 + 1, utf8_written);
7893 CHECK_EQ(buffer[utf8_written], 42);
7894 if (j > utf8_length) {
7895 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7896 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7897 Handle<String> roundtrip = v8_str(buffer);
7898 CHECK(roundtrip->Equals(string));
7900 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7902 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7904 uint16_t trail = StringGet(string, nchars - 1);
7905 uint16_t lead = StringGet(string, nchars - 2);
7906 if (((lead & 0xfc00) == 0xd800) &&
7907 ((trail & 0xfc00) == 0xdc00)) {
7908 unsigned char u1 = buffer2[utf8_written2 - 4];
7909 unsigned char u2 = buffer2[utf8_written2 - 3];
7910 unsigned char u3 = buffer2[utf8_written2 - 2];
7911 unsigned char u4 = buffer2[utf8_written2 - 1];
7912 CHECK_EQ((u1 & 0xf8), 0xf0);
7913 CHECK_EQ((u2 & 0xc0), 0x80);
7914 CHECK_EQ((u3 & 0xc0), 0x80);
7915 CHECK_EQ((u4 & 0xc0), 0x80);
7916 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7917 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7918 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7919 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7920 CHECK_EQ((u1 & 0x3), c >> 18);
7928 THREADED_TEST(Utf16) {
7929 LocalContext context;
7930 v8::HandleScope scope(context->GetIsolate());
7932 "var pad = '01234567890123456789';"
7934 "var plens = [20, 3, 3];"
7935 "p.push('01234567890123456789');"
7936 "var lead = 0xd800;"
7937 "var trail = 0xdc00;"
7938 "p.push(String.fromCharCode(0xd800));"
7939 "p.push(String.fromCharCode(0xdc00));"
7944 "for (var i = 0; i < 3; i++) {"
7945 " p[1] = String.fromCharCode(lead++);"
7946 " for (var j = 0; j < 3; j++) {"
7947 " p[2] = String.fromCharCode(trail++);"
7948 " a.push(p[i] + p[j]);"
7949 " b.push(p[i] + p[j]);"
7950 " c.push(p[i] + p[j]);"
7951 " alens.push(plens[i] + plens[j]);"
7954 "alens[5] -= 2;" // Here the surrogate pairs match up.
7959 "for (var m = 0; m < 9; m++) {"
7960 " for (var n = 0; n < 9; n++) {"
7961 " a2.push(a[m] + a[n]);"
7962 " b2.push(b[m] + b[n]);"
7963 " var newc = 'x' + c[m] + c[n] + 'y';"
7964 " c2.push(newc.substring(1, newc.length - 1));"
7965 " var utf = alens[m] + alens[n];" // And here.
7966 // The 'n's that start with 0xdc.. are 6-8
7967 // The 'm's that end with 0xd8.. are 1, 4 and 7
7968 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7969 " a2lens.push(utf);"
7972 Utf16Helper(context, "a", "alens", 9);
7973 Utf16Helper(context, "a2", "a2lens", 81);
7974 WriteUtf8Helper(context, "b", "alens", 9);
7975 WriteUtf8Helper(context, "b2", "a2lens", 81);
7976 WriteUtf8Helper(context, "c2", "a2lens", 81);
7980 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7981 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7982 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7983 return *is1 == *is2;
7986 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
7988 Handle<String> symbol1 =
7989 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
7990 Handle<String> symbol2 =
7991 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
7992 CHECK(SameSymbol(symbol1, symbol2));
7996 THREADED_TEST(Utf16Symbol) {
7997 LocalContext context;
7998 v8::HandleScope scope(context->GetIsolate());
8000 Handle<String> symbol1 = v8::String::NewFromUtf8(
8001 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8002 Handle<String> symbol2 = v8::String::NewFromUtf8(
8003 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8004 CHECK(SameSymbol(symbol1, symbol2));
8006 SameSymbolHelper(context->GetIsolate(),
8007 "\360\220\220\205", // 4 byte encoding.
8008 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8009 SameSymbolHelper(context->GetIsolate(),
8010 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8011 "\360\220\220\206"); // 4 byte encoding.
8012 SameSymbolHelper(context->GetIsolate(),
8013 "x\360\220\220\205", // 4 byte encoding.
8014 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8015 SameSymbolHelper(context->GetIsolate(),
8016 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8017 "x\360\220\220\206"); // 4 byte encoding.
8019 "var sym0 = 'benedictus';"
8020 "var sym0b = 'S\303\270ren';"
8021 "var sym1 = '\355\240\201\355\260\207';"
8022 "var sym2 = '\360\220\220\210';"
8023 "var sym3 = 'x\355\240\201\355\260\207';"
8024 "var sym4 = 'x\360\220\220\210';"
8025 "if (sym1.length != 2) throw sym1;"
8026 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8027 "if (sym2.length != 2) throw sym2;"
8028 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8029 "if (sym3.length != 3) throw sym3;"
8030 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8031 "if (sym4.length != 3) throw sym4;"
8032 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8033 Handle<String> sym0 = v8::String::NewFromUtf8(
8034 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8035 Handle<String> sym0b = v8::String::NewFromUtf8(
8036 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8037 Handle<String> sym1 =
8038 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8039 v8::String::kInternalizedString);
8040 Handle<String> sym2 =
8041 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8042 v8::String::kInternalizedString);
8043 Handle<String> sym3 = v8::String::NewFromUtf8(
8044 context->GetIsolate(), "x\355\240\201\355\260\207",
8045 v8::String::kInternalizedString);
8046 Handle<String> sym4 =
8047 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8048 v8::String::kInternalizedString);
8049 v8::Local<v8::Object> global = context->Global();
8050 Local<Value> s0 = global->Get(v8_str("sym0"));
8051 Local<Value> s0b = global->Get(v8_str("sym0b"));
8052 Local<Value> s1 = global->Get(v8_str("sym1"));
8053 Local<Value> s2 = global->Get(v8_str("sym2"));
8054 Local<Value> s3 = global->Get(v8_str("sym3"));
8055 Local<Value> s4 = global->Get(v8_str("sym4"));
8056 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8057 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8058 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8059 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8060 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8061 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8065 THREADED_TEST(ToArrayIndex) {
8066 LocalContext context;
8067 v8::Isolate* isolate = context->GetIsolate();
8068 v8::HandleScope scope(isolate);
8070 v8::Handle<String> str = v8_str("42");
8071 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8072 CHECK(!index.IsEmpty());
8073 CHECK_EQ(42.0, index->Uint32Value());
8074 str = v8_str("42asdf");
8075 index = str->ToArrayIndex();
8076 CHECK(index.IsEmpty());
8077 str = v8_str("-42");
8078 index = str->ToArrayIndex();
8079 CHECK(index.IsEmpty());
8080 str = v8_str("4294967295");
8081 index = str->ToArrayIndex();
8082 CHECK(!index.IsEmpty());
8083 CHECK_EQ(4294967295.0, index->Uint32Value());
8084 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8085 index = num->ToArrayIndex();
8086 CHECK(!index.IsEmpty());
8087 CHECK_EQ(1.0, index->Uint32Value());
8088 num = v8::Number::New(isolate, -1);
8089 index = num->ToArrayIndex();
8090 CHECK(index.IsEmpty());
8091 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8092 index = obj->ToArrayIndex();
8093 CHECK(index.IsEmpty());
8097 THREADED_TEST(ErrorConstruction) {
8098 LocalContext context;
8099 v8::HandleScope scope(context->GetIsolate());
8101 v8::Handle<String> foo = v8_str("foo");
8102 v8::Handle<String> message = v8_str("message");
8103 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8104 CHECK(range_error->IsObject());
8105 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8106 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8107 CHECK(reference_error->IsObject());
8108 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8109 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8110 CHECK(syntax_error->IsObject());
8111 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8112 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8113 CHECK(type_error->IsObject());
8114 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8115 v8::Handle<Value> error = v8::Exception::Error(foo);
8116 CHECK(error->IsObject());
8117 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8121 static void YGetter(Local<String> name,
8122 const v8::PropertyCallbackInfo<v8::Value>& info) {
8123 ApiTestFuzzer::Fuzz();
8124 info.GetReturnValue().Set(v8_num(10));
8128 static void YSetter(Local<String> name,
8130 const v8::PropertyCallbackInfo<void>& info) {
8131 if (info.This()->Has(name)) {
8132 info.This()->Delete(name);
8134 info.This()->Set(name, value);
8138 THREADED_TEST(DeleteAccessor) {
8139 v8::Isolate* isolate = CcTest::isolate();
8140 v8::HandleScope scope(isolate);
8141 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8142 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8143 LocalContext context;
8144 v8::Handle<v8::Object> holder = obj->NewInstance();
8145 context->Global()->Set(v8_str("holder"), holder);
8146 v8::Handle<Value> result = CompileRun(
8147 "holder.y = 11; holder.y = 12; holder.y");
8148 CHECK_EQ(12, result->Uint32Value());
8152 THREADED_TEST(TypeSwitch) {
8153 v8::Isolate* isolate = CcTest::isolate();
8154 v8::HandleScope scope(isolate);
8155 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8156 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8157 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8158 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8159 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8160 LocalContext context;
8161 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8162 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8163 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8164 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8165 for (int i = 0; i < 10; i++) {
8166 CHECK_EQ(0, type_switch->match(obj0));
8167 CHECK_EQ(1, type_switch->match(obj1));
8168 CHECK_EQ(2, type_switch->match(obj2));
8169 CHECK_EQ(3, type_switch->match(obj3));
8170 CHECK_EQ(3, type_switch->match(obj3));
8171 CHECK_EQ(2, type_switch->match(obj2));
8172 CHECK_EQ(1, type_switch->match(obj1));
8173 CHECK_EQ(0, type_switch->match(obj0));
8178 // For use within the TestSecurityHandler() test.
8179 static bool g_security_callback_result = false;
8180 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8182 v8::AccessType type,
8183 Local<Value> data) {
8184 // Always allow read access.
8185 if (type == v8::ACCESS_GET)
8188 // Sometimes allow other access.
8189 return g_security_callback_result;
8193 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8195 v8::AccessType type,
8196 Local<Value> data) {
8197 // Always allow read access.
8198 if (type == v8::ACCESS_GET)
8201 // Sometimes allow other access.
8202 return g_security_callback_result;
8206 static int trouble_nesting = 0;
8207 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8208 ApiTestFuzzer::Fuzz();
8211 // Call a JS function that throws an uncaught exception.
8212 Local<v8::Object> arg_this =
8213 args.GetIsolate()->GetCurrentContext()->Global();
8214 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8215 arg_this->Get(v8_str("trouble_callee")) :
8216 arg_this->Get(v8_str("trouble_caller"));
8217 CHECK(trouble_callee->IsFunction());
8218 args.GetReturnValue().Set(
8219 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8223 static int report_count = 0;
8224 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8225 v8::Handle<Value>) {
8230 // Counts uncaught exceptions, but other tests running in parallel
8231 // also have uncaught exceptions.
8232 TEST(ApiUncaughtException) {
8235 v8::Isolate* isolate = env->GetIsolate();
8236 v8::HandleScope scope(isolate);
8237 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8239 Local<v8::FunctionTemplate> fun =
8240 v8::FunctionTemplate::New(isolate, TroubleCallback);
8241 v8::Local<v8::Object> global = env->Global();
8242 global->Set(v8_str("trouble"), fun->GetFunction());
8244 Script::Compile(v8_str("function trouble_callee() {"
8248 "function trouble_caller() {"
8251 Local<Value> trouble = global->Get(v8_str("trouble"));
8252 CHECK(trouble->IsFunction());
8253 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8254 CHECK(trouble_callee->IsFunction());
8255 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8256 CHECK(trouble_caller->IsFunction());
8257 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8258 CHECK_EQ(1, report_count);
8259 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8262 static const char* script_resource_name = "ExceptionInNativeScript.js";
8263 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8264 v8::Handle<Value>) {
8265 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8266 CHECK(!name_val.IsEmpty() && name_val->IsString());
8267 v8::String::Utf8Value name(message->GetScriptResourceName());
8268 CHECK_EQ(script_resource_name, *name);
8269 CHECK_EQ(3, message->GetLineNumber());
8270 v8::String::Utf8Value source_line(message->GetSourceLine());
8271 CHECK_EQ(" new o.foo();", *source_line);
8275 TEST(ExceptionInNativeScript) {
8277 v8::Isolate* isolate = env->GetIsolate();
8278 v8::HandleScope scope(isolate);
8279 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8281 Local<v8::FunctionTemplate> fun =
8282 v8::FunctionTemplate::New(isolate, TroubleCallback);
8283 v8::Local<v8::Object> global = env->Global();
8284 global->Set(v8_str("trouble"), fun->GetFunction());
8288 "function trouble() {\n"
8292 v8::String::NewFromUtf8(isolate, script_resource_name))->Run();
8293 Local<Value> trouble = global->Get(v8_str("trouble"));
8294 CHECK(trouble->IsFunction());
8295 Function::Cast(*trouble)->Call(global, 0, NULL);
8296 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8300 TEST(CompilationErrorUsingTryCatchHandler) {
8302 v8::HandleScope scope(env->GetIsolate());
8303 v8::TryCatch try_catch;
8304 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8305 CHECK_NE(NULL, *try_catch.Exception());
8306 CHECK(try_catch.HasCaught());
8310 TEST(TryCatchFinallyUsingTryCatchHandler) {
8312 v8::HandleScope scope(env->GetIsolate());
8313 v8::TryCatch try_catch;
8314 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8315 CHECK(!try_catch.HasCaught());
8316 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8317 CHECK(try_catch.HasCaught());
8319 Script::Compile(v8_str("(function() {"
8320 "try { throw ''; } finally { return; }"
8322 CHECK(!try_catch.HasCaught());
8323 Script::Compile(v8_str("(function()"
8324 " { try { throw ''; } finally { throw 0; }"
8326 CHECK(try_catch.HasCaught());
8330 // SecurityHandler can't be run twice
8331 TEST(SecurityHandler) {
8332 v8::Isolate* isolate = CcTest::isolate();
8333 v8::HandleScope scope0(isolate);
8334 v8::Handle<v8::ObjectTemplate> global_template =
8335 v8::ObjectTemplate::New(isolate);
8336 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8337 IndexedSecurityTestCallback);
8338 // Create an environment
8339 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8342 v8::Handle<v8::Object> global0 = context0->Global();
8343 v8::Handle<Script> script0 = v8_compile("foo = 111");
8345 global0->Set(v8_str("0"), v8_num(999));
8346 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8347 CHECK_EQ(111, foo0->Int32Value());
8348 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8349 CHECK_EQ(999, z0->Int32Value());
8351 // Create another environment, should fail security checks.
8352 v8::HandleScope scope1(isolate);
8354 v8::Handle<Context> context1 =
8355 Context::New(isolate, NULL, global_template);
8358 v8::Handle<v8::Object> global1 = context1->Global();
8359 global1->Set(v8_str("othercontext"), global0);
8360 // This set will fail the security check.
8361 v8::Handle<Script> script1 =
8362 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8364 // This read will pass the security check.
8365 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8366 CHECK_EQ(111, foo1->Int32Value());
8367 // This read will pass the security check.
8368 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8369 CHECK_EQ(999, z1->Int32Value());
8371 // Create another environment, should pass security checks.
8372 { g_security_callback_result = true; // allow security handler to pass.
8373 v8::HandleScope scope2(isolate);
8374 LocalContext context2;
8375 v8::Handle<v8::Object> global2 = context2->Global();
8376 global2->Set(v8_str("othercontext"), global0);
8377 v8::Handle<Script> script2 =
8378 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8380 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8381 CHECK_EQ(333, foo2->Int32Value());
8382 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8383 CHECK_EQ(888, z2->Int32Value());
8391 THREADED_TEST(SecurityChecks) {
8393 v8::HandleScope handle_scope(env1->GetIsolate());
8394 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8396 Local<Value> foo = v8_str("foo");
8397 Local<Value> bar = v8_str("bar");
8399 // Set to the same domain.
8400 env1->SetSecurityToken(foo);
8402 // Create a function in env1.
8403 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8404 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8405 CHECK(spy->IsFunction());
8407 // Create another function accessing global objects.
8408 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8409 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8410 CHECK(spy2->IsFunction());
8412 // Switch to env2 in the same domain and invoke spy on env2.
8414 env2->SetSecurityToken(foo);
8416 Context::Scope scope_env2(env2);
8417 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8418 CHECK(result->IsFunction());
8422 env2->SetSecurityToken(bar);
8423 Context::Scope scope_env2(env2);
8425 // Call cross_domain_call, it should throw an exception
8426 v8::TryCatch try_catch;
8427 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8428 CHECK(try_catch.HasCaught());
8433 // Regression test case for issue 1183439.
8434 THREADED_TEST(SecurityChecksForPrototypeChain) {
8435 LocalContext current;
8436 v8::HandleScope scope(current->GetIsolate());
8437 v8::Handle<Context> other = Context::New(current->GetIsolate());
8439 // Change context to be able to get to the Object function in the
8440 // other context without hitting the security checks.
8441 v8::Local<Value> other_object;
8442 { Context::Scope scope(other);
8443 other_object = other->Global()->Get(v8_str("Object"));
8444 other->Global()->Set(v8_num(42), v8_num(87));
8447 current->Global()->Set(v8_str("other"), other->Global());
8448 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8450 // Make sure the security check fails here and we get an undefined
8451 // result instead of getting the Object function. Repeat in a loop
8452 // to make sure to exercise the IC code.
8453 v8::Local<Script> access_other0 = v8_compile("other.Object");
8454 v8::Local<Script> access_other1 = v8_compile("other[42]");
8455 for (int i = 0; i < 5; i++) {
8456 CHECK(!access_other0->Run()->Equals(other_object));
8457 CHECK(access_other0->Run()->IsUndefined());
8458 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8459 CHECK(access_other1->Run()->IsUndefined());
8462 // Create an object that has 'other' in its prototype chain and make
8463 // sure we cannot access the Object function indirectly through
8464 // that. Repeat in a loop to make sure to exercise the IC code.
8465 v8_compile("function F() { };"
8466 "F.prototype = other;"
8467 "var f = new F();")->Run();
8468 v8::Local<Script> access_f0 = v8_compile("f.Object");
8469 v8::Local<Script> access_f1 = v8_compile("f[42]");
8470 for (int j = 0; j < 5; j++) {
8471 CHECK(!access_f0->Run()->Equals(other_object));
8472 CHECK(access_f0->Run()->IsUndefined());
8473 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8474 CHECK(access_f1->Run()->IsUndefined());
8477 // Now it gets hairy: Set the prototype for the other global object
8478 // to be the current global object. The prototype chain for 'f' now
8479 // goes through 'other' but ends up in the current global object.
8480 { Context::Scope scope(other);
8481 other->Global()->Set(v8_str("__proto__"), current->Global());
8483 // Set a named and an index property on the current global
8484 // object. To force the lookup to go through the other global object,
8485 // the properties must not exist in the other global object.
8486 current->Global()->Set(v8_str("foo"), v8_num(100));
8487 current->Global()->Set(v8_num(99), v8_num(101));
8488 // Try to read the properties from f and make sure that the access
8489 // gets stopped by the security checks on the other global object.
8490 Local<Script> access_f2 = v8_compile("f.foo");
8491 Local<Script> access_f3 = v8_compile("f[99]");
8492 for (int k = 0; k < 5; k++) {
8493 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8494 CHECK(access_f2->Run()->IsUndefined());
8495 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8496 CHECK(access_f3->Run()->IsUndefined());
8501 THREADED_TEST(CrossDomainDelete) {
8503 v8::HandleScope handle_scope(env1->GetIsolate());
8504 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8506 Local<Value> foo = v8_str("foo");
8507 Local<Value> bar = v8_str("bar");
8509 // Set to the same domain.
8510 env1->SetSecurityToken(foo);
8511 env2->SetSecurityToken(foo);
8513 env1->Global()->Set(v8_str("prop"), v8_num(3));
8514 env2->Global()->Set(v8_str("env1"), env1->Global());
8516 // Change env2 to a different domain and delete env1.prop.
8517 env2->SetSecurityToken(bar);
8519 Context::Scope scope_env2(env2);
8520 Local<Value> result =
8521 Script::Compile(v8_str("delete env1.prop"))->Run();
8522 CHECK(result->IsFalse());
8525 // Check that env1.prop still exists.
8526 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8527 CHECK(v->IsNumber());
8528 CHECK_EQ(3, v->Int32Value());
8532 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8534 v8::HandleScope handle_scope(env1->GetIsolate());
8535 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8537 Local<Value> foo = v8_str("foo");
8538 Local<Value> bar = v8_str("bar");
8540 // Set to the same domain.
8541 env1->SetSecurityToken(foo);
8542 env2->SetSecurityToken(foo);
8544 env1->Global()->Set(v8_str("prop"), v8_num(3));
8545 env2->Global()->Set(v8_str("env1"), env1->Global());
8547 // env1.prop is enumerable in env2.
8548 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8550 Context::Scope scope_env2(env2);
8551 Local<Value> result = Script::Compile(test)->Run();
8552 CHECK(result->IsTrue());
8555 // Change env2 to a different domain and test again.
8556 env2->SetSecurityToken(bar);
8558 Context::Scope scope_env2(env2);
8559 Local<Value> result = Script::Compile(test)->Run();
8560 CHECK(result->IsFalse());
8565 THREADED_TEST(CrossDomainForIn) {
8567 v8::HandleScope handle_scope(env1->GetIsolate());
8568 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8570 Local<Value> foo = v8_str("foo");
8571 Local<Value> bar = v8_str("bar");
8573 // Set to the same domain.
8574 env1->SetSecurityToken(foo);
8575 env2->SetSecurityToken(foo);
8577 env1->Global()->Set(v8_str("prop"), v8_num(3));
8578 env2->Global()->Set(v8_str("env1"), env1->Global());
8580 // Change env2 to a different domain and set env1's global object
8581 // as the __proto__ of an object in env2 and enumerate properties
8582 // in for-in. It shouldn't enumerate properties on env1's global
8584 env2->SetSecurityToken(bar);
8586 Context::Scope scope_env2(env2);
8587 Local<Value> result =
8588 CompileRun("(function(){var obj = {'__proto__':env1};"
8589 "for (var p in obj)"
8590 " if (p == 'prop') return false;"
8591 "return true;})()");
8592 CHECK(result->IsTrue());
8597 TEST(ContextDetachGlobal) {
8599 v8::HandleScope handle_scope(env1->GetIsolate());
8600 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8602 Local<v8::Object> global1 = env1->Global();
8604 Local<Value> foo = v8_str("foo");
8606 // Set to the same domain.
8607 env1->SetSecurityToken(foo);
8608 env2->SetSecurityToken(foo);
8613 // Create a function in env2 and add a reference to it in env1.
8614 Local<v8::Object> global2 = env2->Global();
8615 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8616 CompileRun("function getProp() {return prop;}");
8618 env1->Global()->Set(v8_str("getProp"),
8619 global2->Get(v8_str("getProp")));
8621 // Detach env2's global, and reuse the global object of env2
8623 env2->DetachGlobal();
8625 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8627 v8::Handle<v8::ObjectTemplate>(),
8629 env3->SetSecurityToken(v8_str("bar"));
8632 Local<v8::Object> global3 = env3->Global();
8633 CHECK_EQ(global2, global3);
8634 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8635 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8636 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8637 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8640 // Call getProp in env1, and it should return the value 1
8642 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8643 CHECK(get_prop->IsFunction());
8644 v8::TryCatch try_catch;
8645 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8646 CHECK(!try_catch.HasCaught());
8647 CHECK_EQ(1, r->Int32Value());
8650 // Check that env3 is not accessible from env1
8652 Local<Value> r = global3->Get(v8_str("prop2"));
8653 CHECK(r->IsUndefined());
8658 TEST(DetachGlobal) {
8660 v8::HandleScope scope(env1->GetIsolate());
8662 // Create second environment.
8663 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8665 Local<Value> foo = v8_str("foo");
8667 // Set same security token for env1 and env2.
8668 env1->SetSecurityToken(foo);
8669 env2->SetSecurityToken(foo);
8671 // Create a property on the global object in env2.
8673 v8::Context::Scope scope(env2);
8674 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8677 // Create a reference to env2 global from env1 global.
8678 env1->Global()->Set(v8_str("other"), env2->Global());
8680 // Check that we have access to other.p in env2 from env1.
8681 Local<Value> result = CompileRun("other.p");
8682 CHECK(result->IsInt32());
8683 CHECK_EQ(42, result->Int32Value());
8685 // Hold on to global from env2 and detach global from env2.
8686 Local<v8::Object> global2 = env2->Global();
8687 env2->DetachGlobal();
8689 // Check that the global has been detached. No other.p property can
8691 result = CompileRun("other.p");
8692 CHECK(result->IsUndefined());
8694 // Reuse global2 for env3.
8695 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8697 v8::Handle<v8::ObjectTemplate>(),
8699 CHECK_EQ(global2, env3->Global());
8701 // Start by using the same security token for env3 as for env1 and env2.
8702 env3->SetSecurityToken(foo);
8704 // Create a property on the global object in env3.
8706 v8::Context::Scope scope(env3);
8707 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8710 // Check that other.p is now the property in env3 and that we have access.
8711 result = CompileRun("other.p");
8712 CHECK(result->IsInt32());
8713 CHECK_EQ(24, result->Int32Value());
8715 // Change security token for env3 to something different from env1 and env2.
8716 env3->SetSecurityToken(v8_str("bar"));
8718 // Check that we do not have access to other.p in env1. |other| is now
8719 // the global object for env3 which has a different security token,
8720 // so access should be blocked.
8721 result = CompileRun("other.p");
8722 CHECK(result->IsUndefined());
8726 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8727 info.GetReturnValue().Set(
8728 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8732 TEST(DetachedAccesses) {
8734 v8::HandleScope scope(env1->GetIsolate());
8736 // Create second environment.
8737 Local<ObjectTemplate> inner_global_template =
8738 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8739 inner_global_template ->SetAccessorProperty(
8740 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8741 v8::Local<Context> env2 =
8742 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8744 Local<Value> foo = v8_str("foo");
8746 // Set same security token for env1 and env2.
8747 env1->SetSecurityToken(foo);
8748 env2->SetSecurityToken(foo);
8750 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8753 v8::Context::Scope scope(env2);
8754 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8756 "function bound_x() { return x; }"
8757 "function get_x() { return this.x; }"
8758 "function get_x_w() { return (function() {return this.x;})(); }");
8759 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8760 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8761 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8762 env1->Global()->Set(
8764 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8767 Local<Object> env2_global = env2->Global();
8768 env2_global->TurnOnAccessCheck();
8769 env2->DetachGlobal();
8771 Local<Value> result;
8772 result = CompileRun("bound_x()");
8773 CHECK_EQ(v8_str("env2_x"), result);
8774 result = CompileRun("get_x()");
8775 CHECK(result->IsUndefined());
8776 result = CompileRun("get_x_w()");
8777 CHECK(result->IsUndefined());
8778 result = CompileRun("this_x()");
8779 CHECK_EQ(v8_str("env2_x"), result);
8781 // Reattach env2's proxy
8782 env2 = Context::New(env1->GetIsolate(),
8784 v8::Handle<v8::ObjectTemplate>(),
8786 env2->SetSecurityToken(foo);
8788 v8::Context::Scope scope(env2);
8789 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8790 env2->Global()->Set(v8_str("env1"), env1->Global());
8791 result = CompileRun(
8793 "for (var i = 0; i < 4; i++ ) {"
8794 " results.push(env1.bound_x());"
8795 " results.push(env1.get_x());"
8796 " results.push(env1.get_x_w());"
8797 " results.push(env1.this_x());"
8800 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8801 CHECK_EQ(16, results->Length());
8802 for (int i = 0; i < 16; i += 4) {
8803 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8804 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8805 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8806 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8810 result = CompileRun(
8812 "for (var i = 0; i < 4; i++ ) {"
8813 " results.push(bound_x());"
8814 " results.push(get_x());"
8815 " results.push(get_x_w());"
8816 " results.push(this_x());"
8819 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8820 CHECK_EQ(16, results->Length());
8821 for (int i = 0; i < 16; i += 4) {
8822 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8823 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8824 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8825 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8828 result = CompileRun(
8830 "for (var i = 0; i < 4; i++ ) {"
8831 " results.push(this.bound_x());"
8832 " results.push(this.get_x());"
8833 " results.push(this.get_x_w());"
8834 " results.push(this.this_x());"
8837 results = Local<v8::Array>::Cast(result);
8838 CHECK_EQ(16, results->Length());
8839 for (int i = 0; i < 16; i += 4) {
8840 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8841 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8842 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8843 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8848 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8849 static bool NamedAccessBlocker(Local<v8::Object> global,
8851 v8::AccessType type,
8852 Local<Value> data) {
8853 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8854 allowed_access_type[type];
8858 static bool IndexedAccessBlocker(Local<v8::Object> global,
8860 v8::AccessType type,
8861 Local<Value> data) {
8862 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8863 allowed_access_type[type];
8867 static int g_echo_value_1 = -1;
8868 static int g_echo_value_2 = -1;
8871 static void EchoGetter(
8873 const v8::PropertyCallbackInfo<v8::Value>& info) {
8874 info.GetReturnValue().Set(v8_num(g_echo_value_1));
8878 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8879 info.GetReturnValue().Set(v8_num(g_echo_value_2));
8883 static void EchoSetter(Local<String> name,
8885 const v8::PropertyCallbackInfo<void>&) {
8886 if (value->IsNumber())
8887 g_echo_value_1 = value->Int32Value();
8891 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8892 v8::Handle<v8::Value> value = info[0];
8893 if (value->IsNumber())
8894 g_echo_value_2 = value->Int32Value();
8898 static void UnreachableGetter(
8900 const v8::PropertyCallbackInfo<v8::Value>& info) {
8901 CHECK(false); // This function should not be called..
8905 static void UnreachableSetter(Local<String>,
8907 const v8::PropertyCallbackInfo<void>&) {
8908 CHECK(false); // This function should nto be called.
8912 static void UnreachableFunction(
8913 const v8::FunctionCallbackInfo<v8::Value>& info) {
8914 CHECK(false); // This function should not be called..
8918 TEST(AccessControl) {
8919 v8::Isolate* isolate = CcTest::isolate();
8920 v8::HandleScope handle_scope(isolate);
8921 v8::Handle<v8::ObjectTemplate> global_template =
8922 v8::ObjectTemplate::New(isolate);
8924 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8925 IndexedAccessBlocker);
8927 // Add an accessor accessible by cross-domain JS code.
8928 global_template->SetAccessor(
8929 v8_str("accessible_prop"),
8930 EchoGetter, EchoSetter,
8931 v8::Handle<Value>(),
8932 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8935 global_template->SetAccessorProperty(
8936 v8_str("accessible_js_prop"),
8937 v8::FunctionTemplate::New(isolate, EchoGetter),
8938 v8::FunctionTemplate::New(isolate, EchoSetter),
8940 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8942 // Add an accessor that is not accessible by cross-domain JS code.
8943 global_template->SetAccessor(v8_str("blocked_prop"),
8944 UnreachableGetter, UnreachableSetter,
8945 v8::Handle<Value>(),
8948 global_template->SetAccessorProperty(
8949 v8_str("blocked_js_prop"),
8950 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8951 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8955 // Create an environment
8956 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8959 v8::Handle<v8::Object> global0 = context0->Global();
8961 // Define a property with JS getter and setter.
8963 "function getter() { return 'getter'; };\n"
8964 "function setter() { return 'setter'; }\n"
8965 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8967 Local<Value> getter = global0->Get(v8_str("getter"));
8968 Local<Value> setter = global0->Get(v8_str("setter"));
8970 // And define normal element.
8971 global0->Set(239, v8_str("239"));
8973 // Define an element with JS getter and setter.
8975 "function el_getter() { return 'el_getter'; };\n"
8976 "function el_setter() { return 'el_setter'; };\n"
8977 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8979 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8980 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8982 v8::HandleScope scope1(isolate);
8984 v8::Local<Context> context1 = Context::New(isolate);
8987 v8::Handle<v8::Object> global1 = context1->Global();
8988 global1->Set(v8_str("other"), global0);
8990 // Access blocked property.
8991 CompileRun("other.blocked_prop = 1");
8993 ExpectUndefined("other.blocked_prop");
8995 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8996 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8998 // Enable ACCESS_HAS
8999 allowed_access_type[v8::ACCESS_HAS] = true;
9000 ExpectUndefined("other.blocked_prop");
9001 // ... and now we can get the descriptor...
9003 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9004 // ... and enumerate the property.
9005 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9006 allowed_access_type[v8::ACCESS_HAS] = false;
9008 // Access blocked element.
9009 CompileRun("other[239] = 1");
9011 ExpectUndefined("other[239]");
9012 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9013 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9015 // Enable ACCESS_HAS
9016 allowed_access_type[v8::ACCESS_HAS] = true;
9017 ExpectUndefined("other[239]");
9018 // ... and now we can get the descriptor...
9019 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9020 // ... and enumerate the property.
9021 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9022 allowed_access_type[v8::ACCESS_HAS] = false;
9024 // Access a property with JS accessor.
9025 CompileRun("other.js_accessor_p = 2");
9027 ExpectUndefined("other.js_accessor_p");
9029 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9031 // Enable ACCESS_HAS.
9032 allowed_access_type[v8::ACCESS_HAS] = true;
9033 ExpectUndefined("other.js_accessor_p");
9035 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9037 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9039 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9040 allowed_access_type[v8::ACCESS_HAS] = false;
9042 // Enable both ACCESS_HAS and ACCESS_GET.
9043 allowed_access_type[v8::ACCESS_HAS] = true;
9044 allowed_access_type[v8::ACCESS_GET] = true;
9046 ExpectString("other.js_accessor_p", "getter");
9048 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9050 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9052 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9054 allowed_access_type[v8::ACCESS_GET] = false;
9055 allowed_access_type[v8::ACCESS_HAS] = false;
9057 // Enable both ACCESS_HAS and ACCESS_SET.
9058 allowed_access_type[v8::ACCESS_HAS] = true;
9059 allowed_access_type[v8::ACCESS_SET] = true;
9061 ExpectUndefined("other.js_accessor_p");
9063 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9065 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9067 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9069 allowed_access_type[v8::ACCESS_SET] = false;
9070 allowed_access_type[v8::ACCESS_HAS] = false;
9072 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9073 allowed_access_type[v8::ACCESS_HAS] = true;
9074 allowed_access_type[v8::ACCESS_GET] = true;
9075 allowed_access_type[v8::ACCESS_SET] = true;
9077 ExpectString("other.js_accessor_p", "getter");
9079 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9081 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9083 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9085 allowed_access_type[v8::ACCESS_SET] = false;
9086 allowed_access_type[v8::ACCESS_GET] = false;
9087 allowed_access_type[v8::ACCESS_HAS] = false;
9089 // Access an element with JS accessor.
9090 CompileRun("other[42] = 2");
9092 ExpectUndefined("other[42]");
9093 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9095 // Enable ACCESS_HAS.
9096 allowed_access_type[v8::ACCESS_HAS] = true;
9097 ExpectUndefined("other[42]");
9098 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9099 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9100 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9101 allowed_access_type[v8::ACCESS_HAS] = false;
9103 // Enable both ACCESS_HAS and ACCESS_GET.
9104 allowed_access_type[v8::ACCESS_HAS] = true;
9105 allowed_access_type[v8::ACCESS_GET] = true;
9107 ExpectString("other[42]", "el_getter");
9108 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9109 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9110 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9112 allowed_access_type[v8::ACCESS_GET] = false;
9113 allowed_access_type[v8::ACCESS_HAS] = false;
9115 // Enable both ACCESS_HAS and ACCESS_SET.
9116 allowed_access_type[v8::ACCESS_HAS] = true;
9117 allowed_access_type[v8::ACCESS_SET] = true;
9119 ExpectUndefined("other[42]");
9120 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9121 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9122 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9124 allowed_access_type[v8::ACCESS_SET] = false;
9125 allowed_access_type[v8::ACCESS_HAS] = false;
9127 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9128 allowed_access_type[v8::ACCESS_HAS] = true;
9129 allowed_access_type[v8::ACCESS_GET] = true;
9130 allowed_access_type[v8::ACCESS_SET] = true;
9132 ExpectString("other[42]", "el_getter");
9133 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9134 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9135 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9137 allowed_access_type[v8::ACCESS_SET] = false;
9138 allowed_access_type[v8::ACCESS_GET] = false;
9139 allowed_access_type[v8::ACCESS_HAS] = false;
9141 v8::Handle<Value> value;
9143 // Access accessible property
9144 value = CompileRun("other.accessible_prop = 3");
9145 CHECK(value->IsNumber());
9146 CHECK_EQ(3, value->Int32Value());
9147 CHECK_EQ(3, g_echo_value_1);
9149 // Access accessible js property
9150 value = CompileRun("other.accessible_js_prop = 3");
9151 CHECK(value->IsNumber());
9152 CHECK_EQ(3, value->Int32Value());
9153 CHECK_EQ(3, g_echo_value_2);
9155 value = CompileRun("other.accessible_prop");
9156 CHECK(value->IsNumber());
9157 CHECK_EQ(3, value->Int32Value());
9159 value = CompileRun("other.accessible_js_prop");
9160 CHECK(value->IsNumber());
9161 CHECK_EQ(3, value->Int32Value());
9164 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9165 CHECK(value->IsNumber());
9166 CHECK_EQ(3, value->Int32Value());
9169 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9170 CHECK(value->IsNumber());
9171 CHECK_EQ(3, value->Int32Value());
9173 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9174 CHECK(value->IsTrue());
9176 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9177 CHECK(value->IsTrue());
9179 // Enumeration doesn't enumerate accessors from inaccessible objects in
9180 // the prototype chain even if the accessors are in themselves accessible.
9182 CompileRun("(function(){var obj = {'__proto__':other};"
9183 "for (var p in obj)"
9184 " if (p == 'accessible_prop' ||"
9185 " p == 'accessible_js_prop' ||"
9186 " p == 'blocked_js_prop' ||"
9187 " p == 'blocked_js_prop') {"
9190 "return true;})()");
9191 CHECK(value->IsTrue());
9198 TEST(AccessControlES5) {
9199 v8::Isolate* isolate = CcTest::isolate();
9200 v8::HandleScope handle_scope(isolate);
9201 v8::Handle<v8::ObjectTemplate> global_template =
9202 v8::ObjectTemplate::New(isolate);
9204 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9205 IndexedAccessBlocker);
9207 // Add accessible accessor.
9208 global_template->SetAccessor(
9209 v8_str("accessible_prop"),
9210 EchoGetter, EchoSetter,
9211 v8::Handle<Value>(),
9212 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9215 // Add an accessor that is not accessible by cross-domain JS code.
9216 global_template->SetAccessor(v8_str("blocked_prop"),
9217 UnreachableGetter, UnreachableSetter,
9218 v8::Handle<Value>(),
9221 // Create an environment
9222 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9225 v8::Handle<v8::Object> global0 = context0->Global();
9227 v8::Local<Context> context1 = Context::New(isolate);
9229 v8::Handle<v8::Object> global1 = context1->Global();
9230 global1->Set(v8_str("other"), global0);
9232 // Regression test for issue 1154.
9233 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9235 ExpectUndefined("other.blocked_prop");
9237 // Regression test for issue 1027.
9238 CompileRun("Object.defineProperty(\n"
9239 " other, 'blocked_prop', {configurable: false})");
9240 ExpectUndefined("other.blocked_prop");
9242 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9244 // Regression test for issue 1171.
9245 ExpectTrue("Object.isExtensible(other)");
9246 CompileRun("Object.preventExtensions(other)");
9247 ExpectTrue("Object.isExtensible(other)");
9249 // Object.seal and Object.freeze.
9250 CompileRun("Object.freeze(other)");
9251 ExpectTrue("Object.isExtensible(other)");
9253 CompileRun("Object.seal(other)");
9254 ExpectTrue("Object.isExtensible(other)");
9256 // Regression test for issue 1250.
9257 // Make sure that we can set the accessible accessors value using normal
9259 CompileRun("other.accessible_prop = 42");
9260 CHECK_EQ(42, g_echo_value_1);
9262 v8::Handle<Value> value;
9263 // We follow Safari in ignoring assignments to host object accessors.
9264 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9265 value = CompileRun("other.accessible_prop == 42");
9266 CHECK(value->IsTrue());
9270 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9272 v8::AccessType type,
9273 Local<Value> data) {
9278 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9280 v8::AccessType type,
9281 Local<Value> data) {
9286 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9287 v8::Isolate* isolate = CcTest::isolate();
9288 v8::HandleScope handle_scope(isolate);
9289 v8::Handle<v8::ObjectTemplate> obj_template =
9290 v8::ObjectTemplate::New(isolate);
9292 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9293 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9294 GetOwnPropertyNamesIndexedBlocker);
9296 // Create an environment
9297 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9300 v8::Handle<v8::Object> global0 = context0->Global();
9302 v8::HandleScope scope1(CcTest::isolate());
9304 v8::Local<Context> context1 = Context::New(isolate);
9307 v8::Handle<v8::Object> global1 = context1->Global();
9308 global1->Set(v8_str("other"), global0);
9309 global1->Set(v8_str("object"), obj_template->NewInstance());
9311 v8::Handle<Value> value;
9313 // Attempt to get the property names of the other global object and
9314 // of an object that requires access checks. Accessing the other
9315 // global object should be blocked by access checks on the global
9316 // proxy object. Accessing the object that requires access checks
9317 // is blocked by the access checks on the object itself.
9318 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9319 CHECK(value->IsTrue());
9321 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9322 CHECK(value->IsTrue());
9329 static void IndexedPropertyEnumerator(
9330 const v8::PropertyCallbackInfo<v8::Array>& info) {
9331 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9332 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9333 result->Set(1, v8::Object::New(info.GetIsolate()));
9334 info.GetReturnValue().Set(result);
9338 static void NamedPropertyEnumerator(
9339 const v8::PropertyCallbackInfo<v8::Array>& info) {
9340 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9341 result->Set(0, v8_str("x"));
9342 result->Set(1, v8::Object::New(info.GetIsolate()));
9343 info.GetReturnValue().Set(result);
9347 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9348 v8::Isolate* isolate = CcTest::isolate();
9349 v8::HandleScope handle_scope(isolate);
9350 v8::Handle<v8::ObjectTemplate> obj_template =
9351 v8::ObjectTemplate::New(isolate);
9353 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9354 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9355 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9356 IndexedPropertyEnumerator);
9357 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9358 NamedPropertyEnumerator);
9360 LocalContext context;
9361 v8::Handle<v8::Object> global = context->Global();
9362 global->Set(v8_str("object"), obj_template->NewInstance());
9364 v8::Handle<v8::Value> result =
9365 CompileRun("Object.getOwnPropertyNames(object)");
9366 CHECK(result->IsArray());
9367 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9368 CHECK_EQ(3, result_array->Length());
9369 CHECK(result_array->Get(0)->IsString());
9370 CHECK(result_array->Get(1)->IsString());
9371 CHECK(result_array->Get(2)->IsString());
9372 CHECK_EQ(v8_str("7"), result_array->Get(0));
9373 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9374 CHECK_EQ(v8_str("x"), result_array->Get(2));
9378 static void ConstTenGetter(Local<String> name,
9379 const v8::PropertyCallbackInfo<v8::Value>& info) {
9380 info.GetReturnValue().Set(v8_num(10));
9384 THREADED_TEST(CrossDomainAccessors) {
9385 v8::Isolate* isolate = CcTest::isolate();
9386 v8::HandleScope handle_scope(isolate);
9388 v8::Handle<v8::FunctionTemplate> func_template =
9389 v8::FunctionTemplate::New(isolate);
9391 v8::Handle<v8::ObjectTemplate> global_template =
9392 func_template->InstanceTemplate();
9394 v8::Handle<v8::ObjectTemplate> proto_template =
9395 func_template->PrototypeTemplate();
9397 // Add an accessor to proto that's accessible by cross-domain JS code.
9398 proto_template->SetAccessor(v8_str("accessible"),
9400 v8::Handle<Value>(),
9403 // Add an accessor that is not accessible by cross-domain JS code.
9404 global_template->SetAccessor(v8_str("unreachable"),
9405 UnreachableGetter, 0,
9406 v8::Handle<Value>(),
9409 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9412 Local<v8::Object> global = context0->Global();
9413 // Add a normal property that shadows 'accessible'
9414 global->Set(v8_str("accessible"), v8_num(11));
9416 // Enter a new context.
9417 v8::HandleScope scope1(CcTest::isolate());
9418 v8::Local<Context> context1 = Context::New(isolate);
9421 v8::Handle<v8::Object> global1 = context1->Global();
9422 global1->Set(v8_str("other"), global);
9424 // Should return 10, instead of 11
9425 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9426 CHECK(value->IsNumber());
9427 CHECK_EQ(10, value->Int32Value());
9429 value = v8_compile("other.unreachable")->Run();
9430 CHECK(value->IsUndefined());
9437 static int named_access_count = 0;
9438 static int indexed_access_count = 0;
9440 static bool NamedAccessCounter(Local<v8::Object> global,
9442 v8::AccessType type,
9443 Local<Value> data) {
9444 named_access_count++;
9449 static bool IndexedAccessCounter(Local<v8::Object> global,
9451 v8::AccessType type,
9452 Local<Value> data) {
9453 indexed_access_count++;
9458 // This one is too easily disturbed by other tests.
9459 TEST(AccessControlIC) {
9460 named_access_count = 0;
9461 indexed_access_count = 0;
9463 v8::Isolate* isolate = CcTest::isolate();
9464 v8::HandleScope handle_scope(isolate);
9466 // Create an environment.
9467 v8::Local<Context> context0 = Context::New(isolate);
9470 // Create an object that requires access-check functions to be
9471 // called for cross-domain access.
9472 v8::Handle<v8::ObjectTemplate> object_template =
9473 v8::ObjectTemplate::New(isolate);
9474 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9475 IndexedAccessCounter);
9476 Local<v8::Object> object = object_template->NewInstance();
9478 v8::HandleScope scope1(isolate);
9480 // Create another environment.
9481 v8::Local<Context> context1 = Context::New(isolate);
9484 // Make easy access to the object from the other environment.
9485 v8::Handle<v8::Object> global1 = context1->Global();
9486 global1->Set(v8_str("obj"), object);
9488 v8::Handle<Value> value;
9490 // Check that the named access-control function is called every time.
9491 CompileRun("function testProp(obj) {"
9492 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9493 " for (var j = 0; j < 10; j++) obj.prop;"
9496 value = CompileRun("testProp(obj)");
9497 CHECK(value->IsNumber());
9498 CHECK_EQ(1, value->Int32Value());
9499 CHECK_EQ(21, named_access_count);
9501 // Check that the named access-control function is called every time.
9502 CompileRun("var p = 'prop';"
9503 "function testKeyed(obj) {"
9504 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9505 " for (var j = 0; j < 10; j++) obj[p];"
9508 // Use obj which requires access checks. No inline caching is used
9510 value = CompileRun("testKeyed(obj)");
9511 CHECK(value->IsNumber());
9512 CHECK_EQ(1, value->Int32Value());
9513 CHECK_EQ(42, named_access_count);
9514 // Force the inline caches into generic state and try again.
9515 CompileRun("testKeyed({ a: 0 })");
9516 CompileRun("testKeyed({ b: 0 })");
9517 value = CompileRun("testKeyed(obj)");
9518 CHECK(value->IsNumber());
9519 CHECK_EQ(1, value->Int32Value());
9520 CHECK_EQ(63, named_access_count);
9522 // Check that the indexed access-control function is called every time.
9523 CompileRun("function testIndexed(obj) {"
9524 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9525 " for (var j = 0; j < 10; j++) obj[0];"
9528 value = CompileRun("testIndexed(obj)");
9529 CHECK(value->IsNumber());
9530 CHECK_EQ(1, value->Int32Value());
9531 CHECK_EQ(21, indexed_access_count);
9532 // Force the inline caches into generic state.
9533 CompileRun("testIndexed(new Array(1))");
9534 // Test that the indexed access check is called.
9535 value = CompileRun("testIndexed(obj)");
9536 CHECK(value->IsNumber());
9537 CHECK_EQ(1, value->Int32Value());
9538 CHECK_EQ(42, indexed_access_count);
9540 // Check that the named access check is called when invoking
9541 // functions on an object that requires access checks.
9542 CompileRun("obj.f = function() {}");
9543 CompileRun("function testCallNormal(obj) {"
9544 " for (var i = 0; i < 10; i++) obj.f();"
9546 CompileRun("testCallNormal(obj)");
9547 CHECK_EQ(74, named_access_count);
9549 // Force obj into slow case.
9550 value = CompileRun("delete obj.prop");
9551 CHECK(value->BooleanValue());
9552 // Force inline caches into dictionary probing mode.
9553 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9554 // Test that the named access check is called.
9555 value = CompileRun("testProp(obj);");
9556 CHECK(value->IsNumber());
9557 CHECK_EQ(1, value->Int32Value());
9558 CHECK_EQ(96, named_access_count);
9560 // Force the call inline cache into dictionary probing mode.
9561 CompileRun("o.f = function() {}; testCallNormal(o)");
9562 // Test that the named access check is still called for each
9563 // invocation of the function.
9564 value = CompileRun("testCallNormal(obj)");
9565 CHECK_EQ(106, named_access_count);
9572 static bool NamedAccessFlatten(Local<v8::Object> global,
9574 v8::AccessType type,
9575 Local<Value> data) {
9579 CHECK(name->IsString());
9581 memset(buf, 0x1, sizeof(buf));
9582 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9587 memset(buf, 0x1, sizeof(buf));
9588 len = name.As<String>()->Write(buf2);
9595 static bool IndexedAccessFlatten(Local<v8::Object> global,
9597 v8::AccessType type,
9598 Local<Value> data) {
9603 // Regression test. In access checks, operations that may cause
9604 // garbage collection are not allowed. It used to be the case that
9605 // using the Write operation on a string could cause a garbage
9606 // collection due to flattening of the string. This is no longer the
9608 THREADED_TEST(AccessControlFlatten) {
9609 named_access_count = 0;
9610 indexed_access_count = 0;
9612 v8::Isolate* isolate = CcTest::isolate();
9613 v8::HandleScope handle_scope(isolate);
9615 // Create an environment.
9616 v8::Local<Context> context0 = Context::New(isolate);
9619 // Create an object that requires access-check functions to be
9620 // called for cross-domain access.
9621 v8::Handle<v8::ObjectTemplate> object_template =
9622 v8::ObjectTemplate::New(isolate);
9623 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9624 IndexedAccessFlatten);
9625 Local<v8::Object> object = object_template->NewInstance();
9627 v8::HandleScope scope1(isolate);
9629 // Create another environment.
9630 v8::Local<Context> context1 = Context::New(isolate);
9633 // Make easy access to the object from the other environment.
9634 v8::Handle<v8::Object> global1 = context1->Global();
9635 global1->Set(v8_str("obj"), object);
9637 v8::Handle<Value> value;
9639 value = v8_compile("var p = 'as' + 'df';")->Run();
9640 value = v8_compile("obj[p];")->Run();
9647 static void AccessControlNamedGetter(
9649 const v8::PropertyCallbackInfo<v8::Value>& info) {
9650 info.GetReturnValue().Set(42);
9654 static void AccessControlNamedSetter(
9657 const v8::PropertyCallbackInfo<v8::Value>& info) {
9658 info.GetReturnValue().Set(value);
9662 static void AccessControlIndexedGetter(
9664 const v8::PropertyCallbackInfo<v8::Value>& info) {
9665 info.GetReturnValue().Set(v8_num(42));
9669 static void AccessControlIndexedSetter(
9672 const v8::PropertyCallbackInfo<v8::Value>& info) {
9673 info.GetReturnValue().Set(value);
9677 THREADED_TEST(AccessControlInterceptorIC) {
9678 named_access_count = 0;
9679 indexed_access_count = 0;
9681 v8::Isolate* isolate = CcTest::isolate();
9682 v8::HandleScope handle_scope(isolate);
9684 // Create an environment.
9685 v8::Local<Context> context0 = Context::New(isolate);
9688 // Create an object that requires access-check functions to be
9689 // called for cross-domain access. The object also has interceptors
9691 v8::Handle<v8::ObjectTemplate> object_template =
9692 v8::ObjectTemplate::New(isolate);
9693 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9694 IndexedAccessCounter);
9695 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9696 AccessControlNamedSetter);
9697 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9698 AccessControlIndexedSetter);
9699 Local<v8::Object> object = object_template->NewInstance();
9701 v8::HandleScope scope1(isolate);
9703 // Create another environment.
9704 v8::Local<Context> context1 = Context::New(isolate);
9707 // Make easy access to the object from the other environment.
9708 v8::Handle<v8::Object> global1 = context1->Global();
9709 global1->Set(v8_str("obj"), object);
9711 v8::Handle<Value> value;
9713 // Check that the named access-control function is called every time
9714 // eventhough there is an interceptor on the object.
9715 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9716 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9718 CHECK(value->IsNumber());
9719 CHECK_EQ(42, value->Int32Value());
9720 CHECK_EQ(21, named_access_count);
9722 value = v8_compile("var p = 'x';")->Run();
9723 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9724 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9726 CHECK(value->IsNumber());
9727 CHECK_EQ(42, value->Int32Value());
9728 CHECK_EQ(42, named_access_count);
9730 // Check that the indexed access-control function is called every
9731 // time eventhough there is an interceptor on the object.
9732 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9733 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9735 CHECK(value->IsNumber());
9736 CHECK_EQ(42, value->Int32Value());
9737 CHECK_EQ(21, indexed_access_count);
9744 THREADED_TEST(Version) {
9745 v8::V8::GetVersion();
9749 static void InstanceFunctionCallback(
9750 const v8::FunctionCallbackInfo<v8::Value>& args) {
9751 ApiTestFuzzer::Fuzz();
9752 args.GetReturnValue().Set(v8_num(12));
9756 THREADED_TEST(InstanceProperties) {
9757 LocalContext context;
9758 v8::Isolate* isolate = context->GetIsolate();
9759 v8::HandleScope handle_scope(isolate);
9761 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9762 Local<ObjectTemplate> instance = t->InstanceTemplate();
9764 instance->Set(v8_str("x"), v8_num(42));
9765 instance->Set(v8_str("f"),
9766 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9768 Local<Value> o = t->GetFunction()->NewInstance();
9770 context->Global()->Set(v8_str("i"), o);
9771 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9772 CHECK_EQ(42, value->Int32Value());
9774 value = Script::Compile(v8_str("i.f()"))->Run();
9775 CHECK_EQ(12, value->Int32Value());
9779 static void GlobalObjectInstancePropertiesGet(
9781 const v8::PropertyCallbackInfo<v8::Value>&) {
9782 ApiTestFuzzer::Fuzz();
9786 THREADED_TEST(GlobalObjectInstanceProperties) {
9787 v8::Isolate* isolate = CcTest::isolate();
9788 v8::HandleScope handle_scope(isolate);
9790 Local<Value> global_object;
9792 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9793 t->InstanceTemplate()->SetNamedPropertyHandler(
9794 GlobalObjectInstancePropertiesGet);
9795 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9796 instance_template->Set(v8_str("x"), v8_num(42));
9797 instance_template->Set(v8_str("f"),
9798 v8::FunctionTemplate::New(isolate,
9799 InstanceFunctionCallback));
9801 // The script to check how Crankshaft compiles missing global function
9802 // invocations. function g is not defined and should throw on call.
9803 const char* script =
9804 "function wrapper(call) {"
9805 " var x = 0, y = 1;"
9806 " for (var i = 0; i < 1000; i++) {"
9812 "for (var i = 0; i < 17; i++) wrapper(false);"
9814 "try { wrapper(true); } catch (e) { thrown = 1; };"
9818 LocalContext env(NULL, instance_template);
9819 // Hold on to the global object so it can be used again in another
9820 // environment initialization.
9821 global_object = env->Global();
9823 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9824 CHECK_EQ(42, value->Int32Value());
9825 value = Script::Compile(v8_str("f()"))->Run();
9826 CHECK_EQ(12, value->Int32Value());
9827 value = Script::Compile(v8_str(script))->Run();
9828 CHECK_EQ(1, value->Int32Value());
9832 // Create new environment reusing the global object.
9833 LocalContext env(NULL, instance_template, global_object);
9834 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9835 CHECK_EQ(42, value->Int32Value());
9836 value = Script::Compile(v8_str("f()"))->Run();
9837 CHECK_EQ(12, value->Int32Value());
9838 value = Script::Compile(v8_str(script))->Run();
9839 CHECK_EQ(1, value->Int32Value());
9844 THREADED_TEST(CallKnownGlobalReceiver) {
9845 v8::Isolate* isolate = CcTest::isolate();
9846 v8::HandleScope handle_scope(isolate);
9848 Local<Value> global_object;
9850 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9851 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9853 // The script to check that we leave global object not
9854 // global object proxy on stack when we deoptimize from inside
9855 // arguments evaluation.
9856 // To provoke error we need to both force deoptimization
9857 // from arguments evaluation and to force CallIC to take
9858 // CallIC_Miss code path that can't cope with global proxy.
9859 const char* script =
9860 "function bar(x, y) { try { } finally { } }"
9861 "function baz(x) { try { } finally { } }"
9862 "function bom(x) { try { } finally { } }"
9863 "function foo(x) { bar([x], bom(2)); }"
9864 "for (var i = 0; i < 10000; i++) foo(1);"
9869 LocalContext env(NULL, instance_template);
9870 // Hold on to the global object so it can be used again in another
9871 // environment initialization.
9872 global_object = env->Global();
9873 foo = Script::Compile(v8_str(script))->Run();
9877 // Create new environment reusing the global object.
9878 LocalContext env(NULL, instance_template, global_object);
9879 env->Global()->Set(v8_str("foo"), foo);
9880 Script::Compile(v8_str("foo()"))->Run();
9885 static void ShadowFunctionCallback(
9886 const v8::FunctionCallbackInfo<v8::Value>& args) {
9887 ApiTestFuzzer::Fuzz();
9888 args.GetReturnValue().Set(v8_num(42));
9892 static int shadow_y;
9893 static int shadow_y_setter_call_count;
9894 static int shadow_y_getter_call_count;
9897 static void ShadowYSetter(Local<String>,
9899 const v8::PropertyCallbackInfo<void>&) {
9900 shadow_y_setter_call_count++;
9905 static void ShadowYGetter(Local<String> name,
9906 const v8::PropertyCallbackInfo<v8::Value>& info) {
9907 ApiTestFuzzer::Fuzz();
9908 shadow_y_getter_call_count++;
9909 info.GetReturnValue().Set(v8_num(shadow_y));
9913 static void ShadowIndexedGet(uint32_t index,
9914 const v8::PropertyCallbackInfo<v8::Value>&) {
9918 static void ShadowNamedGet(Local<String> key,
9919 const v8::PropertyCallbackInfo<v8::Value>&) {
9923 THREADED_TEST(ShadowObject) {
9924 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9925 v8::Isolate* isolate = CcTest::isolate();
9926 v8::HandleScope handle_scope(isolate);
9928 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9929 LocalContext context(NULL, global_template);
9931 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9932 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9933 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9934 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9935 Local<ObjectTemplate> instance = t->InstanceTemplate();
9937 proto->Set(v8_str("f"),
9938 v8::FunctionTemplate::New(isolate,
9939 ShadowFunctionCallback,
9941 proto->Set(v8_str("x"), v8_num(12));
9943 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9945 Local<Value> o = t->GetFunction()->NewInstance();
9946 context->Global()->Set(v8_str("__proto__"), o);
9948 Local<Value> value =
9949 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9950 CHECK(value->IsBoolean());
9951 CHECK(!value->BooleanValue());
9953 value = Script::Compile(v8_str("x"))->Run();
9954 CHECK_EQ(12, value->Int32Value());
9956 value = Script::Compile(v8_str("f()"))->Run();
9957 CHECK_EQ(42, value->Int32Value());
9959 Script::Compile(v8_str("y = 43"))->Run();
9960 CHECK_EQ(1, shadow_y_setter_call_count);
9961 value = Script::Compile(v8_str("y"))->Run();
9962 CHECK_EQ(1, shadow_y_getter_call_count);
9963 CHECK_EQ(42, value->Int32Value());
9967 THREADED_TEST(HiddenPrototype) {
9968 LocalContext context;
9969 v8::Isolate* isolate = context->GetIsolate();
9970 v8::HandleScope handle_scope(isolate);
9972 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9973 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9974 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9975 t1->SetHiddenPrototype(true);
9976 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9977 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9978 t2->SetHiddenPrototype(true);
9979 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9980 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9981 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9983 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9984 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9985 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9986 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9988 // Setting the prototype on an object skips hidden prototypes.
9989 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9990 o0->Set(v8_str("__proto__"), o1);
9991 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9992 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9993 o0->Set(v8_str("__proto__"), o2);
9994 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9995 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9996 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9997 o0->Set(v8_str("__proto__"), o3);
9998 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9999 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10000 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10001 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10003 // Getting the prototype of o0 should get the first visible one
10004 // which is o3. Therefore, z should not be defined on the prototype
10006 Local<Value> proto = o0->Get(v8_str("__proto__"));
10007 CHECK(proto->IsObject());
10008 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10012 THREADED_TEST(HiddenPrototypeSet) {
10013 LocalContext context;
10014 v8::Isolate* isolate = context->GetIsolate();
10015 v8::HandleScope handle_scope(isolate);
10017 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10018 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10019 ht->SetHiddenPrototype(true);
10020 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10021 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10023 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10024 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10025 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10026 o->Set(v8_str("__proto__"), h);
10027 h->Set(v8_str("__proto__"), p);
10029 // Setting a property that exists on the hidden prototype goes there.
10030 o->Set(v8_str("x"), v8_num(7));
10031 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10032 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10033 CHECK(p->Get(v8_str("x"))->IsUndefined());
10035 // Setting a new property should not be forwarded to the hidden prototype.
10036 o->Set(v8_str("y"), v8_num(6));
10037 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10038 CHECK(h->Get(v8_str("y"))->IsUndefined());
10039 CHECK(p->Get(v8_str("y"))->IsUndefined());
10041 // Setting a property that only exists on a prototype of the hidden prototype
10042 // is treated normally again.
10043 p->Set(v8_str("z"), v8_num(8));
10044 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10045 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10046 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10047 o->Set(v8_str("z"), v8_num(9));
10048 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10049 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10050 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10054 // Regression test for issue 2457.
10055 THREADED_TEST(HiddenPrototypeIdentityHash) {
10056 LocalContext context;
10057 v8::HandleScope handle_scope(context->GetIsolate());
10059 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10060 t->SetHiddenPrototype(true);
10061 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10062 Handle<Object> p = t->GetFunction()->NewInstance();
10063 Handle<Object> o = Object::New(context->GetIsolate());
10064 o->SetPrototype(p);
10066 int hash = o->GetIdentityHash();
10068 o->Set(v8_str("foo"), v8_num(42));
10069 ASSERT_EQ(hash, o->GetIdentityHash());
10073 THREADED_TEST(SetPrototype) {
10074 LocalContext context;
10075 v8::Isolate* isolate = context->GetIsolate();
10076 v8::HandleScope handle_scope(isolate);
10078 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10079 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10080 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10081 t1->SetHiddenPrototype(true);
10082 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10083 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10084 t2->SetHiddenPrototype(true);
10085 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10086 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10087 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10089 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10090 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10091 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10092 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10094 // Setting the prototype on an object does not skip hidden prototypes.
10095 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10096 CHECK(o0->SetPrototype(o1));
10097 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10098 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10099 CHECK(o1->SetPrototype(o2));
10100 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10101 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10102 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10103 CHECK(o2->SetPrototype(o3));
10104 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10105 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10106 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10107 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10109 // Getting the prototype of o0 should get the first visible one
10110 // which is o3. Therefore, z should not be defined on the prototype
10112 Local<Value> proto = o0->Get(v8_str("__proto__"));
10113 CHECK(proto->IsObject());
10114 CHECK_EQ(proto.As<v8::Object>(), o3);
10116 // However, Object::GetPrototype ignores hidden prototype.
10117 Local<Value> proto0 = o0->GetPrototype();
10118 CHECK(proto0->IsObject());
10119 CHECK_EQ(proto0.As<v8::Object>(), o1);
10121 Local<Value> proto1 = o1->GetPrototype();
10122 CHECK(proto1->IsObject());
10123 CHECK_EQ(proto1.As<v8::Object>(), o2);
10125 Local<Value> proto2 = o2->GetPrototype();
10126 CHECK(proto2->IsObject());
10127 CHECK_EQ(proto2.As<v8::Object>(), o3);
10131 // Getting property names of an object with a prototype chain that
10132 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10133 // crash the runtime.
10134 THREADED_TEST(Regress91517) {
10135 i::FLAG_allow_natives_syntax = true;
10136 LocalContext context;
10137 v8::Isolate* isolate = context->GetIsolate();
10138 v8::HandleScope handle_scope(isolate);
10140 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10141 t1->SetHiddenPrototype(true);
10142 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10143 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10144 t2->SetHiddenPrototype(true);
10145 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10146 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10147 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10148 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10149 t3->SetHiddenPrototype(true);
10150 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10151 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10152 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10154 // Force dictionary-based properties.
10155 i::ScopedVector<char> name_buf(1024);
10156 for (int i = 1; i <= 1000; i++) {
10157 i::OS::SNPrintF(name_buf, "sdf%d", i);
10158 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10161 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10162 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10163 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10164 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10166 // Create prototype chain of hidden prototypes.
10167 CHECK(o4->SetPrototype(o3));
10168 CHECK(o3->SetPrototype(o2));
10169 CHECK(o2->SetPrototype(o1));
10171 // Call the runtime version of GetLocalPropertyNames() on the natively
10172 // created object through JavaScript.
10173 context->Global()->Set(v8_str("obj"), o4);
10174 // PROPERTY_ATTRIBUTES_NONE = 0
10175 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10177 ExpectInt32("names.length", 1006);
10178 ExpectTrue("names.indexOf(\"baz\") >= 0");
10179 ExpectTrue("names.indexOf(\"boo\") >= 0");
10180 ExpectTrue("names.indexOf(\"foo\") >= 0");
10181 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10182 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10183 ExpectFalse("names[1005] == undefined");
10187 // Getting property names of an object with a hidden and inherited
10188 // prototype should not duplicate the accessor properties inherited.
10189 THREADED_TEST(Regress269562) {
10190 i::FLAG_allow_natives_syntax = true;
10191 LocalContext context;
10192 v8::HandleScope handle_scope(context->GetIsolate());
10194 Local<v8::FunctionTemplate> t1 =
10195 v8::FunctionTemplate::New(context->GetIsolate());
10196 t1->SetHiddenPrototype(true);
10198 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10199 i1->SetAccessor(v8_str("foo"),
10200 SimpleAccessorGetter, SimpleAccessorSetter);
10201 i1->SetAccessor(v8_str("bar"),
10202 SimpleAccessorGetter, SimpleAccessorSetter);
10203 i1->SetAccessor(v8_str("baz"),
10204 SimpleAccessorGetter, SimpleAccessorSetter);
10205 i1->Set(v8_str("n1"), v8_num(1));
10206 i1->Set(v8_str("n2"), v8_num(2));
10208 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10209 Local<v8::FunctionTemplate> t2 =
10210 v8::FunctionTemplate::New(context->GetIsolate());
10211 t2->SetHiddenPrototype(true);
10213 // Inherit from t1 and mark prototype as hidden.
10215 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10217 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10218 CHECK(o2->SetPrototype(o1));
10220 v8::Local<v8::Symbol> sym = v8::Symbol::New(context->GetIsolate(), "s1");
10221 o1->Set(sym, v8_num(3));
10222 o1->SetHiddenValue(v8_str("h1"),
10223 v8::Integer::New(context->GetIsolate(), 2013));
10225 // Call the runtime version of GetLocalPropertyNames() on
10226 // the natively created object through JavaScript.
10227 context->Global()->Set(v8_str("obj"), o2);
10228 context->Global()->Set(v8_str("sym"), sym);
10229 // PROPERTY_ATTRIBUTES_NONE = 0
10230 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10232 ExpectInt32("names.length", 7);
10233 ExpectTrue("names.indexOf(\"foo\") >= 0");
10234 ExpectTrue("names.indexOf(\"bar\") >= 0");
10235 ExpectTrue("names.indexOf(\"baz\") >= 0");
10236 ExpectTrue("names.indexOf(\"n1\") >= 0");
10237 ExpectTrue("names.indexOf(\"n2\") >= 0");
10238 ExpectTrue("names.indexOf(sym) >= 0");
10239 ExpectTrue("names.indexOf(\"mine\") >= 0");
10243 THREADED_TEST(FunctionReadOnlyPrototype) {
10244 LocalContext context;
10245 v8::Isolate* isolate = context->GetIsolate();
10246 v8::HandleScope handle_scope(isolate);
10248 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10249 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10250 t1->ReadOnlyPrototype();
10251 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10252 // Configured value of ReadOnly flag.
10255 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10256 " return (descriptor['writable'] == false);"
10257 "})()")->BooleanValue());
10258 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10260 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10262 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10263 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10264 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10265 // Default value of ReadOnly flag.
10268 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10269 " return (descriptor['writable'] == true);"
10270 "})()")->BooleanValue());
10271 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10275 THREADED_TEST(SetPrototypeThrows) {
10276 LocalContext context;
10277 v8::Isolate* isolate = context->GetIsolate();
10278 v8::HandleScope handle_scope(isolate);
10280 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10282 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10283 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10285 CHECK(o0->SetPrototype(o1));
10286 // If setting the prototype leads to the cycle, SetPrototype should
10287 // return false and keep VM in sane state.
10288 v8::TryCatch try_catch;
10289 CHECK(!o1->SetPrototype(o0));
10290 CHECK(!try_catch.HasCaught());
10291 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10293 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10297 THREADED_TEST(FunctionRemovePrototype) {
10298 LocalContext context;
10299 v8::Isolate* isolate = context->GetIsolate();
10300 v8::HandleScope handle_scope(isolate);
10302 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10303 t1->RemovePrototype();
10304 Local<v8::Function> fun = t1->GetFunction();
10305 context->Global()->Set(v8_str("fun"), fun);
10306 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10308 v8::TryCatch try_catch;
10309 CompileRun("new fun()");
10310 CHECK(try_catch.HasCaught());
10313 fun->NewInstance();
10314 CHECK(try_catch.HasCaught());
10318 THREADED_TEST(GetterSetterExceptions) {
10319 LocalContext context;
10320 v8::Isolate* isolate = context->GetIsolate();
10321 v8::HandleScope handle_scope(isolate);
10323 "function Foo() { };"
10324 "function Throw() { throw 5; };"
10326 "x.__defineSetter__('set', Throw);"
10327 "x.__defineGetter__('get', Throw);");
10328 Local<v8::Object> x =
10329 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10330 v8::TryCatch try_catch;
10331 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10332 x->Get(v8_str("get"));
10333 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10334 x->Get(v8_str("get"));
10335 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10336 x->Get(v8_str("get"));
10337 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10338 x->Get(v8_str("get"));
10342 THREADED_TEST(Constructor) {
10343 LocalContext context;
10344 v8::Isolate* isolate = context->GetIsolate();
10345 v8::HandleScope handle_scope(isolate);
10346 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10347 templ->SetClassName(v8_str("Fun"));
10348 Local<Function> cons = templ->GetFunction();
10349 context->Global()->Set(v8_str("Fun"), cons);
10350 Local<v8::Object> inst = cons->NewInstance();
10351 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10352 CHECK(obj->IsJSObject());
10353 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10354 CHECK(value->BooleanValue());
10358 static void ConstructorCallback(
10359 const v8::FunctionCallbackInfo<v8::Value>& args) {
10360 ApiTestFuzzer::Fuzz();
10361 Local<Object> This;
10363 if (args.IsConstructCall()) {
10364 Local<Object> Holder = args.Holder();
10365 This = Object::New(args.GetIsolate());
10366 Local<Value> proto = Holder->GetPrototype();
10367 if (proto->IsObject()) {
10368 This->SetPrototype(proto);
10371 This = args.This();
10374 This->Set(v8_str("a"), args[0]);
10375 args.GetReturnValue().Set(This);
10379 static void FakeConstructorCallback(
10380 const v8::FunctionCallbackInfo<v8::Value>& args) {
10381 ApiTestFuzzer::Fuzz();
10382 args.GetReturnValue().Set(args[0]);
10386 THREADED_TEST(ConstructorForObject) {
10387 LocalContext context;
10388 v8::Isolate* isolate = context->GetIsolate();
10389 v8::HandleScope handle_scope(isolate);
10391 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10392 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10393 Local<Object> instance = instance_template->NewInstance();
10394 context->Global()->Set(v8_str("obj"), instance);
10395 v8::TryCatch try_catch;
10396 Local<Value> value;
10397 CHECK(!try_catch.HasCaught());
10399 // Call the Object's constructor with a 32-bit signed integer.
10400 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10401 CHECK(!try_catch.HasCaught());
10402 CHECK(value->IsInt32());
10403 CHECK_EQ(28, value->Int32Value());
10405 Local<Value> args1[] = { v8_num(28) };
10406 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10407 CHECK(value_obj1->IsObject());
10408 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10409 value = object1->Get(v8_str("a"));
10410 CHECK(value->IsInt32());
10411 CHECK(!try_catch.HasCaught());
10412 CHECK_EQ(28, value->Int32Value());
10414 // Call the Object's constructor with a String.
10415 value = CompileRun(
10416 "(function() { var o = new obj('tipli'); return o.a; })()");
10417 CHECK(!try_catch.HasCaught());
10418 CHECK(value->IsString());
10419 String::Utf8Value string_value1(value->ToString());
10420 CHECK_EQ("tipli", *string_value1);
10422 Local<Value> args2[] = { v8_str("tipli") };
10423 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10424 CHECK(value_obj2->IsObject());
10425 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10426 value = object2->Get(v8_str("a"));
10427 CHECK(!try_catch.HasCaught());
10428 CHECK(value->IsString());
10429 String::Utf8Value string_value2(value->ToString());
10430 CHECK_EQ("tipli", *string_value2);
10432 // Call the Object's constructor with a Boolean.
10433 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10434 CHECK(!try_catch.HasCaught());
10435 CHECK(value->IsBoolean());
10436 CHECK_EQ(true, value->BooleanValue());
10438 Handle<Value> args3[] = { v8::True(isolate) };
10439 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10440 CHECK(value_obj3->IsObject());
10441 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10442 value = object3->Get(v8_str("a"));
10443 CHECK(!try_catch.HasCaught());
10444 CHECK(value->IsBoolean());
10445 CHECK_EQ(true, value->BooleanValue());
10447 // Call the Object's constructor with undefined.
10448 Handle<Value> args4[] = { v8::Undefined(isolate) };
10449 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10450 CHECK(value_obj4->IsObject());
10451 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10452 value = object4->Get(v8_str("a"));
10453 CHECK(!try_catch.HasCaught());
10454 CHECK(value->IsUndefined());
10456 // Call the Object's constructor with null.
10457 Handle<Value> args5[] = { v8::Null(isolate) };
10458 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10459 CHECK(value_obj5->IsObject());
10460 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10461 value = object5->Get(v8_str("a"));
10462 CHECK(!try_catch.HasCaught());
10463 CHECK(value->IsNull());
10466 // Check exception handling when there is no constructor set for the Object.
10467 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10468 Local<Object> instance = instance_template->NewInstance();
10469 context->Global()->Set(v8_str("obj2"), instance);
10470 v8::TryCatch try_catch;
10471 Local<Value> value;
10472 CHECK(!try_catch.HasCaught());
10474 value = CompileRun("new obj2(28)");
10475 CHECK(try_catch.HasCaught());
10476 String::Utf8Value exception_value1(try_catch.Exception());
10477 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10480 Local<Value> args[] = { v8_num(29) };
10481 value = instance->CallAsConstructor(1, args);
10482 CHECK(try_catch.HasCaught());
10483 String::Utf8Value exception_value2(try_catch.Exception());
10484 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10488 // Check the case when constructor throws exception.
10489 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10490 instance_template->SetCallAsFunctionHandler(ThrowValue);
10491 Local<Object> instance = instance_template->NewInstance();
10492 context->Global()->Set(v8_str("obj3"), instance);
10493 v8::TryCatch try_catch;
10494 Local<Value> value;
10495 CHECK(!try_catch.HasCaught());
10497 value = CompileRun("new obj3(22)");
10498 CHECK(try_catch.HasCaught());
10499 String::Utf8Value exception_value1(try_catch.Exception());
10500 CHECK_EQ("22", *exception_value1);
10503 Local<Value> args[] = { v8_num(23) };
10504 value = instance->CallAsConstructor(1, args);
10505 CHECK(try_catch.HasCaught());
10506 String::Utf8Value exception_value2(try_catch.Exception());
10507 CHECK_EQ("23", *exception_value2);
10511 // Check whether constructor returns with an object or non-object.
10512 { Local<FunctionTemplate> function_template =
10513 FunctionTemplate::New(isolate, FakeConstructorCallback);
10514 Local<Function> function = function_template->GetFunction();
10515 Local<Object> instance1 = function;
10516 context->Global()->Set(v8_str("obj4"), instance1);
10517 v8::TryCatch try_catch;
10518 Local<Value> value;
10519 CHECK(!try_catch.HasCaught());
10521 CHECK(instance1->IsObject());
10522 CHECK(instance1->IsFunction());
10524 value = CompileRun("new obj4(28)");
10525 CHECK(!try_catch.HasCaught());
10526 CHECK(value->IsObject());
10528 Local<Value> args1[] = { v8_num(28) };
10529 value = instance1->CallAsConstructor(1, args1);
10530 CHECK(!try_catch.HasCaught());
10531 CHECK(value->IsObject());
10533 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10534 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10535 Local<Object> instance2 = instance_template->NewInstance();
10536 context->Global()->Set(v8_str("obj5"), instance2);
10537 CHECK(!try_catch.HasCaught());
10539 CHECK(instance2->IsObject());
10540 CHECK(!instance2->IsFunction());
10542 value = CompileRun("new obj5(28)");
10543 CHECK(!try_catch.HasCaught());
10544 CHECK(!value->IsObject());
10546 Local<Value> args2[] = { v8_num(28) };
10547 value = instance2->CallAsConstructor(1, args2);
10548 CHECK(!try_catch.HasCaught());
10549 CHECK(!value->IsObject());
10554 THREADED_TEST(FunctionDescriptorException) {
10555 LocalContext context;
10556 v8::Isolate* isolate = context->GetIsolate();
10557 v8::HandleScope handle_scope(isolate);
10558 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10559 templ->SetClassName(v8_str("Fun"));
10560 Local<Function> cons = templ->GetFunction();
10561 context->Global()->Set(v8_str("Fun"), cons);
10562 Local<Value> value = CompileRun(
10563 "function test() {"
10565 " (new Fun()).blah()"
10567 " var str = String(e);"
10568 // " if (str.indexOf('TypeError') == -1) return 1;"
10569 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10570 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10576 CHECK_EQ(0, value->Int32Value());
10580 THREADED_TEST(EvalAliasedDynamic) {
10581 LocalContext current;
10582 v8::HandleScope scope(current->GetIsolate());
10584 // Tests where aliased eval can only be resolved dynamically.
10585 Local<Script> script =
10586 Script::Compile(v8_str("function f(x) { "
10588 " with (x) { return eval('foo'); }"
10591 "result1 = f(new Object());"
10592 "result2 = f(this);"
10593 "var x = new Object();"
10594 "x.eval = function(x) { return 1; };"
10595 "result3 = f(x);"));
10597 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10598 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10599 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10601 v8::TryCatch try_catch;
10603 Script::Compile(v8_str("function f(x) { "
10605 " with (x) { return eval('bar'); }"
10607 "result4 = f(this)"));
10609 CHECK(!try_catch.HasCaught());
10610 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10616 THREADED_TEST(CrossEval) {
10617 v8::HandleScope scope(CcTest::isolate());
10618 LocalContext other;
10619 LocalContext current;
10621 Local<String> token = v8_str("<security token>");
10622 other->SetSecurityToken(token);
10623 current->SetSecurityToken(token);
10625 // Set up reference from current to other.
10626 current->Global()->Set(v8_str("other"), other->Global());
10628 // Check that new variables are introduced in other context.
10629 Local<Script> script =
10630 Script::Compile(v8_str("other.eval('var foo = 1234')"));
10632 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10633 CHECK_EQ(1234, foo->Int32Value());
10634 CHECK(!current->Global()->Has(v8_str("foo")));
10636 // Check that writing to non-existing properties introduces them in
10637 // the other context.
10639 Script::Compile(v8_str("other.eval('na = 1234')"));
10641 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10642 CHECK(!current->Global()->Has(v8_str("na")));
10644 // Check that global variables in current context are not visible in other
10646 v8::TryCatch try_catch;
10648 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10649 Local<Value> result = script->Run();
10650 CHECK(try_catch.HasCaught());
10653 // Check that local variables in current context are not visible in other
10656 Script::Compile(v8_str("(function() { "
10658 " return other.eval('baz');"
10660 result = script->Run();
10661 CHECK(try_catch.HasCaught());
10664 // Check that global variables in the other environment are visible
10665 // when evaluting code.
10666 other->Global()->Set(v8_str("bis"), v8_num(1234));
10667 script = Script::Compile(v8_str("other.eval('bis')"));
10668 CHECK_EQ(1234, script->Run()->Int32Value());
10669 CHECK(!try_catch.HasCaught());
10671 // Check that the 'this' pointer points to the global object evaluating
10673 other->Global()->Set(v8_str("t"), other->Global());
10674 script = Script::Compile(v8_str("other.eval('this == t')"));
10675 result = script->Run();
10676 CHECK(result->IsTrue());
10677 CHECK(!try_catch.HasCaught());
10679 // Check that variables introduced in with-statement are not visible in
10682 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10683 result = script->Run();
10684 CHECK(try_catch.HasCaught());
10687 // Check that you cannot use 'eval.call' with another object than the
10688 // current global object.
10690 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10691 result = script->Run();
10692 CHECK(try_catch.HasCaught());
10696 // Test that calling eval in a context which has been detached from
10697 // its global throws an exception. This behavior is consistent with
10698 // other JavaScript implementations.
10699 THREADED_TEST(EvalInDetachedGlobal) {
10700 v8::Isolate* isolate = CcTest::isolate();
10701 v8::HandleScope scope(isolate);
10703 v8::Local<Context> context0 = Context::New(isolate);
10704 v8::Local<Context> context1 = Context::New(isolate);
10706 // Set up function in context0 that uses eval from context0.
10708 v8::Handle<v8::Value> fun =
10709 CompileRun("var x = 42;"
10712 " return function(s) { return e(s); }"
10716 // Put the function into context1 and call it before and after
10717 // detaching the global. Before detaching, the call succeeds and
10718 // after detaching and exception is thrown.
10720 context1->Global()->Set(v8_str("fun"), fun);
10721 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10722 CHECK_EQ(42, x_value->Int32Value());
10723 context0->DetachGlobal();
10724 v8::TryCatch catcher;
10725 x_value = CompileRun("fun('x')");
10726 CHECK(x_value.IsEmpty());
10727 CHECK(catcher.HasCaught());
10732 THREADED_TEST(CrossLazyLoad) {
10733 v8::HandleScope scope(CcTest::isolate());
10734 LocalContext other;
10735 LocalContext current;
10737 Local<String> token = v8_str("<security token>");
10738 other->SetSecurityToken(token);
10739 current->SetSecurityToken(token);
10741 // Set up reference from current to other.
10742 current->Global()->Set(v8_str("other"), other->Global());
10744 // Trigger lazy loading in other context.
10745 Local<Script> script =
10746 Script::Compile(v8_str("other.eval('new Date(42)')"));
10747 Local<Value> value = script->Run();
10748 CHECK_EQ(42.0, value->NumberValue());
10752 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10753 ApiTestFuzzer::Fuzz();
10754 if (args.IsConstructCall()) {
10755 if (args[0]->IsInt32()) {
10756 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10761 args.GetReturnValue().Set(args[0]);
10765 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10766 args.GetReturnValue().Set(args.This());
10770 // Test that a call handler can be set for objects which will allow
10771 // non-function objects created through the API to be called as
10773 THREADED_TEST(CallAsFunction) {
10774 LocalContext context;
10775 v8::Isolate* isolate = context->GetIsolate();
10776 v8::HandleScope scope(isolate);
10778 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10779 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10780 instance_template->SetCallAsFunctionHandler(call_as_function);
10781 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10782 context->Global()->Set(v8_str("obj"), instance);
10783 v8::TryCatch try_catch;
10784 Local<Value> value;
10785 CHECK(!try_catch.HasCaught());
10787 value = CompileRun("obj(42)");
10788 CHECK(!try_catch.HasCaught());
10789 CHECK_EQ(42, value->Int32Value());
10791 value = CompileRun("(function(o){return o(49)})(obj)");
10792 CHECK(!try_catch.HasCaught());
10793 CHECK_EQ(49, value->Int32Value());
10795 // test special case of call as function
10796 value = CompileRun("[obj]['0'](45)");
10797 CHECK(!try_catch.HasCaught());
10798 CHECK_EQ(45, value->Int32Value());
10800 value = CompileRun("obj.call = Function.prototype.call;"
10801 "obj.call(null, 87)");
10802 CHECK(!try_catch.HasCaught());
10803 CHECK_EQ(87, value->Int32Value());
10805 // Regression tests for bug #1116356: Calling call through call/apply
10806 // must work for non-function receivers.
10807 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10808 value = CompileRun(apply_99);
10809 CHECK(!try_catch.HasCaught());
10810 CHECK_EQ(99, value->Int32Value());
10812 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10813 value = CompileRun(call_17);
10814 CHECK(!try_catch.HasCaught());
10815 CHECK_EQ(17, value->Int32Value());
10817 // Check that the call-as-function handler can be called through
10819 value = CompileRun("new obj(43)");
10820 CHECK(!try_catch.HasCaught());
10821 CHECK_EQ(-43, value->Int32Value());
10823 // Check that the call-as-function handler can be called through
10825 v8::Handle<Value> args[] = { v8_num(28) };
10826 value = instance->CallAsFunction(instance, 1, args);
10827 CHECK(!try_catch.HasCaught());
10828 CHECK_EQ(28, value->Int32Value());
10831 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10832 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10833 USE(instance_template);
10834 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10835 context->Global()->Set(v8_str("obj2"), instance);
10836 v8::TryCatch try_catch;
10837 Local<Value> value;
10838 CHECK(!try_catch.HasCaught());
10840 // Call an object without call-as-function handler through the JS
10841 value = CompileRun("obj2(28)");
10842 CHECK(value.IsEmpty());
10843 CHECK(try_catch.HasCaught());
10844 String::Utf8Value exception_value1(try_catch.Exception());
10845 // TODO(verwaest): Better message
10846 CHECK_EQ("TypeError: object is not a function",
10847 *exception_value1);
10850 // Call an object without call-as-function handler through the API
10851 value = CompileRun("obj2(28)");
10852 v8::Handle<Value> args[] = { v8_num(28) };
10853 value = instance->CallAsFunction(instance, 1, args);
10854 CHECK(value.IsEmpty());
10855 CHECK(try_catch.HasCaught());
10856 String::Utf8Value exception_value2(try_catch.Exception());
10857 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10861 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10862 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10863 instance_template->SetCallAsFunctionHandler(ThrowValue);
10864 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10865 context->Global()->Set(v8_str("obj3"), instance);
10866 v8::TryCatch try_catch;
10867 Local<Value> value;
10868 CHECK(!try_catch.HasCaught());
10870 // Catch the exception which is thrown by call-as-function handler
10871 value = CompileRun("obj3(22)");
10872 CHECK(try_catch.HasCaught());
10873 String::Utf8Value exception_value1(try_catch.Exception());
10874 CHECK_EQ("22", *exception_value1);
10877 v8::Handle<Value> args[] = { v8_num(23) };
10878 value = instance->CallAsFunction(instance, 1, args);
10879 CHECK(try_catch.HasCaught());
10880 String::Utf8Value exception_value2(try_catch.Exception());
10881 CHECK_EQ("23", *exception_value2);
10885 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10886 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10887 instance_template->SetCallAsFunctionHandler(ReturnThis);
10888 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10890 Local<v8::Value> a1 =
10891 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10892 CHECK(a1->StrictEquals(instance));
10893 Local<v8::Value> a2 =
10894 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10895 CHECK(a2->StrictEquals(instance));
10896 Local<v8::Value> a3 =
10897 instance->CallAsFunction(v8_num(42), 0, NULL);
10898 CHECK(a3->StrictEquals(instance));
10899 Local<v8::Value> a4 =
10900 instance->CallAsFunction(v8_str("hello"), 0, NULL);
10901 CHECK(a4->StrictEquals(instance));
10902 Local<v8::Value> a5 =
10903 instance->CallAsFunction(v8::True(isolate), 0, NULL);
10904 CHECK(a5->StrictEquals(instance));
10908 "function ReturnThisSloppy() {"
10911 "function ReturnThisStrict() {"
10915 Local<Function> ReturnThisSloppy =
10916 Local<Function>::Cast(
10917 context->Global()->Get(v8_str("ReturnThisSloppy")));
10918 Local<Function> ReturnThisStrict =
10919 Local<Function>::Cast(
10920 context->Global()->Get(v8_str("ReturnThisStrict")));
10922 Local<v8::Value> a1 =
10923 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10924 CHECK(a1->StrictEquals(context->Global()));
10925 Local<v8::Value> a2 =
10926 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10927 CHECK(a2->StrictEquals(context->Global()));
10928 Local<v8::Value> a3 =
10929 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10930 CHECK(a3->IsNumberObject());
10931 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10932 Local<v8::Value> a4 =
10933 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10934 CHECK(a4->IsStringObject());
10935 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10936 Local<v8::Value> a5 =
10937 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10938 CHECK(a5->IsBooleanObject());
10939 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10941 Local<v8::Value> a6 =
10942 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10943 CHECK(a6->IsUndefined());
10944 Local<v8::Value> a7 =
10945 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10946 CHECK(a7->IsNull());
10947 Local<v8::Value> a8 =
10948 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10949 CHECK(a8->StrictEquals(v8_num(42)));
10950 Local<v8::Value> a9 =
10951 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10952 CHECK(a9->StrictEquals(v8_str("hello")));
10953 Local<v8::Value> a10 =
10954 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10955 CHECK(a10->StrictEquals(v8::True(isolate)));
10960 // Check whether a non-function object is callable.
10961 THREADED_TEST(CallableObject) {
10962 LocalContext context;
10963 v8::Isolate* isolate = context->GetIsolate();
10964 v8::HandleScope scope(isolate);
10966 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10967 instance_template->SetCallAsFunctionHandler(call_as_function);
10968 Local<Object> instance = instance_template->NewInstance();
10969 v8::TryCatch try_catch;
10971 CHECK(instance->IsCallable());
10972 CHECK(!try_catch.HasCaught());
10975 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10976 Local<Object> instance = instance_template->NewInstance();
10977 v8::TryCatch try_catch;
10979 CHECK(!instance->IsCallable());
10980 CHECK(!try_catch.HasCaught());
10983 { Local<FunctionTemplate> function_template =
10984 FunctionTemplate::New(isolate, call_as_function);
10985 Local<Function> function = function_template->GetFunction();
10986 Local<Object> instance = function;
10987 v8::TryCatch try_catch;
10989 CHECK(instance->IsCallable());
10990 CHECK(!try_catch.HasCaught());
10993 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10994 Local<Function> function = function_template->GetFunction();
10995 Local<Object> instance = function;
10996 v8::TryCatch try_catch;
10998 CHECK(instance->IsCallable());
10999 CHECK(!try_catch.HasCaught());
11004 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11005 v8::HandleScope scope(isolate);
11006 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11007 for (int i = 0; i < iterations; i++) {
11008 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11010 return Recurse(isolate, depth - 1, iterations);
11014 THREADED_TEST(HandleIteration) {
11015 static const int kIterations = 500;
11016 static const int kNesting = 200;
11017 LocalContext context;
11018 v8::Isolate* isolate = context->GetIsolate();
11019 v8::HandleScope scope0(isolate);
11020 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11022 v8::HandleScope scope1(isolate);
11023 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11024 for (int i = 0; i < kIterations; i++) {
11025 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11026 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11029 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11031 v8::HandleScope scope2(CcTest::isolate());
11032 for (int j = 0; j < kIterations; j++) {
11033 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11034 CHECK_EQ(j + 1 + kIterations,
11035 v8::HandleScope::NumberOfHandles(isolate));
11038 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11040 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11041 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11045 static void InterceptorHasOwnPropertyGetter(
11046 Local<String> name,
11047 const v8::PropertyCallbackInfo<v8::Value>& info) {
11048 ApiTestFuzzer::Fuzz();
11052 THREADED_TEST(InterceptorHasOwnProperty) {
11053 LocalContext context;
11054 v8::Isolate* isolate = context->GetIsolate();
11055 v8::HandleScope scope(isolate);
11056 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11057 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11058 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11059 Local<Function> function = fun_templ->GetFunction();
11060 context->Global()->Set(v8_str("constructor"), function);
11061 v8::Handle<Value> value = CompileRun(
11062 "var o = new constructor();"
11063 "o.hasOwnProperty('ostehaps');");
11064 CHECK_EQ(false, value->BooleanValue());
11065 value = CompileRun(
11067 "o.hasOwnProperty('ostehaps');");
11068 CHECK_EQ(true, value->BooleanValue());
11069 value = CompileRun(
11070 "var p = new constructor();"
11071 "p.hasOwnProperty('ostehaps');");
11072 CHECK_EQ(false, value->BooleanValue());
11076 static void InterceptorHasOwnPropertyGetterGC(
11077 Local<String> name,
11078 const v8::PropertyCallbackInfo<v8::Value>& info) {
11079 ApiTestFuzzer::Fuzz();
11080 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11084 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11085 LocalContext context;
11086 v8::Isolate* isolate = context->GetIsolate();
11087 v8::HandleScope scope(isolate);
11088 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11089 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11090 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11091 Local<Function> function = fun_templ->GetFunction();
11092 context->Global()->Set(v8_str("constructor"), function);
11093 // Let's first make some stuff so we can be sure to get a good GC.
11095 "function makestr(size) {"
11097 " case 1: return 'f';"
11098 " case 2: return 'fo';"
11099 " case 3: return 'foo';"
11101 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11103 "var x = makestr(12345);"
11104 "x = makestr(31415);"
11105 "x = makestr(23456);");
11106 v8::Handle<Value> value = CompileRun(
11107 "var o = new constructor();"
11108 "o.__proto__ = new String(x);"
11109 "o.hasOwnProperty('ostehaps');");
11110 CHECK_EQ(false, value->BooleanValue());
11114 typedef void (*NamedPropertyGetter)(
11115 Local<String> property,
11116 const v8::PropertyCallbackInfo<v8::Value>& info);
11119 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11120 const char* source,
11122 v8::Isolate* isolate = CcTest::isolate();
11123 v8::HandleScope scope(isolate);
11124 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11125 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11126 LocalContext context;
11127 context->Global()->Set(v8_str("o"), templ->NewInstance());
11128 v8::Handle<Value> value = CompileRun(source);
11129 CHECK_EQ(expected, value->Int32Value());
11133 static void InterceptorLoadICGetter(
11134 Local<String> name,
11135 const v8::PropertyCallbackInfo<v8::Value>& info) {
11136 ApiTestFuzzer::Fuzz();
11137 v8::Isolate* isolate = CcTest::isolate();
11138 CHECK_EQ(isolate, info.GetIsolate());
11139 CHECK_EQ(v8_str("data"), info.Data());
11140 CHECK_EQ(v8_str("x"), name);
11141 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11145 // This test should hit the load IC for the interceptor case.
11146 THREADED_TEST(InterceptorLoadIC) {
11147 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11149 "for (var i = 0; i < 1000; i++) {"
11156 // Below go several tests which verify that JITing for various
11157 // configurations of interceptor and explicit fields works fine
11158 // (those cases are special cased to get better performance).
11160 static void InterceptorLoadXICGetter(
11161 Local<String> name,
11162 const v8::PropertyCallbackInfo<v8::Value>& info) {
11163 ApiTestFuzzer::Fuzz();
11164 info.GetReturnValue().Set(
11165 v8_str("x")->Equals(name) ?
11166 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11167 v8::Handle<v8::Value>());
11171 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11172 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11175 "for (var i = 0; i < 1000; i++) {"
11182 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11183 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11185 "o.__proto__ = { 'y': 239 };"
11186 "for (var i = 0; i < 1000; i++) {"
11187 " result = o.y + o.x;"
11193 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11194 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11196 "o.__proto__.y = 239;"
11197 "for (var i = 0; i < 1000; i++) {"
11198 " result = o.y + o.x;"
11204 THREADED_TEST(InterceptorLoadICUndefined) {
11205 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11207 "for (var i = 0; i < 1000; i++) {"
11208 " result = (o.y == undefined) ? 239 : 42;"
11214 THREADED_TEST(InterceptorLoadICWithOverride) {
11215 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11216 "fst = new Object(); fst.__proto__ = o;"
11217 "snd = new Object(); snd.__proto__ = fst;"
11219 "for (var i = 0; i < 1000; i++) {"
11220 " result1 = snd.x;"
11224 "for (var i = 0; i < 1000; i++) {"
11227 "result + result1",
11232 // Test the case when we stored field into
11233 // a stub, but interceptor produced value on its own.
11234 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11235 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11236 "proto = new Object();"
11237 "o.__proto__ = proto;"
11239 "for (var i = 0; i < 1000; i++) {"
11241 // Now it should be ICed and keep a reference to x defined on proto
11244 "for (var i = 0; i < 1000; i++) {"
11252 // Test the case when we stored field into
11253 // a stub, but it got invalidated later on.
11254 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11255 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11256 "proto1 = new Object();"
11257 "proto2 = new Object();"
11258 "o.__proto__ = proto1;"
11259 "proto1.__proto__ = proto2;"
11261 "for (var i = 0; i < 1000; i++) {"
11263 // Now it should be ICed and keep a reference to y defined on proto2
11267 "for (var i = 0; i < 1000; i++) {"
11275 static int interceptor_load_not_handled_calls = 0;
11276 static void InterceptorLoadNotHandled(
11277 Local<String> name,
11278 const v8::PropertyCallbackInfo<v8::Value>& info) {
11279 ++interceptor_load_not_handled_calls;
11283 // Test how post-interceptor lookups are done in the non-cacheable
11284 // case: the interceptor should not be invoked during this lookup.
11285 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11286 interceptor_load_not_handled_calls = 0;
11287 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11288 "receiver = new Object();"
11289 "receiver.__proto__ = o;"
11290 "proto = new Object();"
11291 "/* Make proto a slow-case object. */"
11292 "for (var i = 0; i < 1000; i++) {"
11293 " proto[\"xxxxxxxx\" + i] = [];"
11296 "o.__proto__ = proto;"
11298 "for (var i = 0; i < 1000; i++) {"
11299 " result += receiver.x;"
11303 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11307 // Test the case when we stored field into
11308 // a stub, but it got invalidated later on due to override on
11309 // global object which is between interceptor and fields' holders.
11310 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11311 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11312 "o.__proto__ = this;" // set a global to be a proto of o.
11313 "this.__proto__.y = 239;"
11314 "for (var i = 0; i < 10; i++) {"
11315 " if (o.y != 239) throw 'oops: ' + o.y;"
11316 // Now it should be ICed and keep a reference to y defined on field_holder.
11318 "this.y = 42;" // Assign on a global.
11320 "for (var i = 0; i < 10; i++) {"
11328 static void SetOnThis(Local<String> name,
11329 Local<Value> value,
11330 const v8::PropertyCallbackInfo<void>& info) {
11331 info.This()->ForceSet(name, value);
11335 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11336 v8::Isolate* isolate = CcTest::isolate();
11337 v8::HandleScope scope(isolate);
11338 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11339 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11340 templ->SetAccessor(v8_str("y"), Return239Callback);
11341 LocalContext context;
11342 context->Global()->Set(v8_str("o"), templ->NewInstance());
11344 // Check the case when receiver and interceptor's holder
11345 // are the same objects.
11346 v8::Handle<Value> value = CompileRun(
11348 "for (var i = 0; i < 7; i++) {"
11351 CHECK_EQ(239, value->Int32Value());
11353 // Check the case when interceptor's holder is in proto chain
11355 value = CompileRun(
11356 "r = { __proto__: o };"
11358 "for (var i = 0; i < 7; i++) {"
11361 CHECK_EQ(239, value->Int32Value());
11365 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11366 v8::Isolate* isolate = CcTest::isolate();
11367 v8::HandleScope scope(isolate);
11368 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11369 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11370 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11371 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11373 LocalContext context;
11374 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11375 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11377 // Check the case when receiver and interceptor's holder
11378 // are the same objects.
11379 v8::Handle<Value> value = CompileRun(
11382 "for (var i = 0; i < 7; i++) {"
11383 " result = o.x + o.y;"
11385 CHECK_EQ(239 + 42, value->Int32Value());
11387 // Check the case when interceptor's holder is in proto chain
11389 value = CompileRun(
11390 "r = { __proto__: o };"
11392 "for (var i = 0; i < 7; i++) {"
11393 " result = r.x + r.y;"
11395 CHECK_EQ(239 + 42, value->Int32Value());
11399 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11400 v8::Isolate* isolate = CcTest::isolate();
11401 v8::HandleScope scope(isolate);
11402 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11403 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11404 templ->SetAccessor(v8_str("y"), Return239Callback);
11406 LocalContext context;
11407 context->Global()->Set(v8_str("o"), templ->NewInstance());
11409 v8::Handle<Value> value = CompileRun(
11410 "fst = new Object(); fst.__proto__ = o;"
11411 "snd = new Object(); snd.__proto__ = fst;"
11413 "for (var i = 0; i < 7; i++) {"
11414 " result1 = snd.x;"
11418 "for (var i = 0; i < 7; i++) {"
11421 "result + result1");
11422 CHECK_EQ(239 + 42, value->Int32Value());
11426 // Test the case when we stored callback into
11427 // a stub, but interceptor produced value on its own.
11428 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11429 v8::Isolate* isolate = CcTest::isolate();
11430 v8::HandleScope scope(isolate);
11431 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11432 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11433 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11434 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11436 LocalContext context;
11437 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11438 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11440 v8::Handle<Value> value = CompileRun(
11442 "for (var i = 0; i < 7; i++) {"
11444 // Now it should be ICed and keep a reference to x defined on p
11447 "for (var i = 0; i < 7; i++) {"
11451 CHECK_EQ(42 * 7, value->Int32Value());
11455 // Test the case when we stored callback into
11456 // a stub, but it got invalidated later on.
11457 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11458 v8::Isolate* isolate = CcTest::isolate();
11459 v8::HandleScope scope(isolate);
11460 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11461 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11462 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11463 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11465 LocalContext context;
11466 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11467 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11469 v8::Handle<Value> value = CompileRun(
11470 "inbetween = new Object();"
11471 "o.__proto__ = inbetween;"
11472 "inbetween.__proto__ = p;"
11473 "for (var i = 0; i < 10; i++) {"
11475 // Now it should be ICed and keep a reference to y defined on p
11477 "inbetween.y = 42;"
11479 "for (var i = 0; i < 10; i++) {"
11483 CHECK_EQ(42 * 10, value->Int32Value());
11487 // Test the case when we stored callback into
11488 // a stub, but it got invalidated later on due to override on
11489 // global object which is between interceptor and callbacks' holders.
11490 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11491 v8::Isolate* isolate = CcTest::isolate();
11492 v8::HandleScope scope(isolate);
11493 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11494 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11495 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11496 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11498 LocalContext context;
11499 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11500 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11502 v8::Handle<Value> value = CompileRun(
11503 "o.__proto__ = this;"
11504 "this.__proto__ = p;"
11505 "for (var i = 0; i < 10; i++) {"
11506 " if (o.y != 239) throw 'oops: ' + o.y;"
11507 // Now it should be ICed and keep a reference to y defined on p
11511 "for (var i = 0; i < 10; i++) {"
11515 CHECK_EQ(42 * 10, value->Int32Value());
11519 static void InterceptorLoadICGetter0(
11520 Local<String> name,
11521 const v8::PropertyCallbackInfo<v8::Value>& info) {
11522 ApiTestFuzzer::Fuzz();
11523 CHECK(v8_str("x")->Equals(name));
11524 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11528 THREADED_TEST(InterceptorReturningZero) {
11529 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11530 "o.x == undefined ? 1 : 0",
11535 static void InterceptorStoreICSetter(
11537 Local<Value> value,
11538 const v8::PropertyCallbackInfo<v8::Value>& info) {
11539 CHECK(v8_str("x")->Equals(key));
11540 CHECK_EQ(42, value->Int32Value());
11541 info.GetReturnValue().Set(value);
11545 // This test should hit the store IC for the interceptor case.
11546 THREADED_TEST(InterceptorStoreIC) {
11547 v8::Isolate* isolate = CcTest::isolate();
11548 v8::HandleScope scope(isolate);
11549 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11550 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11551 InterceptorStoreICSetter,
11552 0, 0, 0, v8_str("data"));
11553 LocalContext context;
11554 context->Global()->Set(v8_str("o"), templ->NewInstance());
11556 "for (var i = 0; i < 1000; i++) {"
11562 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11563 v8::Isolate* isolate = CcTest::isolate();
11564 v8::HandleScope scope(isolate);
11565 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11566 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11567 LocalContext context;
11568 context->Global()->Set(v8_str("o"), templ->NewInstance());
11569 v8::Handle<Value> value = CompileRun(
11570 "for (var i = 0; i < 1000; i++) {"
11574 CHECK_EQ(239 + 42, value->Int32Value());
11580 v8::Handle<Value> call_ic_function;
11581 v8::Handle<Value> call_ic_function2;
11582 v8::Handle<Value> call_ic_function3;
11584 static void InterceptorCallICGetter(
11585 Local<String> name,
11586 const v8::PropertyCallbackInfo<v8::Value>& info) {
11587 ApiTestFuzzer::Fuzz();
11588 CHECK(v8_str("x")->Equals(name));
11589 info.GetReturnValue().Set(call_ic_function);
11593 // This test should hit the call IC for the interceptor case.
11594 THREADED_TEST(InterceptorCallIC) {
11595 v8::Isolate* isolate = CcTest::isolate();
11596 v8::HandleScope scope(isolate);
11597 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11598 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11599 LocalContext context;
11600 context->Global()->Set(v8_str("o"), templ->NewInstance());
11602 v8_compile("function f(x) { return x + 1; }; f")->Run();
11603 v8::Handle<Value> value = CompileRun(
11605 "for (var i = 0; i < 1000; i++) {"
11606 " result = o.x(41);"
11608 CHECK_EQ(42, value->Int32Value());
11612 // This test checks that if interceptor doesn't provide
11613 // a value, we can fetch regular value.
11614 THREADED_TEST(InterceptorCallICSeesOthers) {
11615 v8::Isolate* isolate = CcTest::isolate();
11616 v8::HandleScope scope(isolate);
11617 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11618 templ->SetNamedPropertyHandler(NoBlockGetterX);
11619 LocalContext context;
11620 context->Global()->Set(v8_str("o"), templ->NewInstance());
11621 v8::Handle<Value> value = CompileRun(
11622 "o.x = function f(x) { return x + 1; };"
11624 "for (var i = 0; i < 7; i++) {"
11625 " result = o.x(41);"
11627 CHECK_EQ(42, value->Int32Value());
11631 static v8::Handle<Value> call_ic_function4;
11632 static void InterceptorCallICGetter4(
11633 Local<String> name,
11634 const v8::PropertyCallbackInfo<v8::Value>& info) {
11635 ApiTestFuzzer::Fuzz();
11636 CHECK(v8_str("x")->Equals(name));
11637 info.GetReturnValue().Set(call_ic_function4);
11641 // This test checks that if interceptor provides a function,
11642 // even if we cached shadowed variant, interceptor's function
11644 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11645 v8::Isolate* isolate = CcTest::isolate();
11646 v8::HandleScope scope(isolate);
11647 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11648 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11649 LocalContext context;
11650 context->Global()->Set(v8_str("o"), templ->NewInstance());
11651 call_ic_function4 =
11652 v8_compile("function f(x) { return x - 1; }; f")->Run();
11653 v8::Handle<Value> value = CompileRun(
11654 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11656 "for (var i = 0; i < 1000; i++) {"
11657 " result = o.x(42);"
11659 CHECK_EQ(41, value->Int32Value());
11663 // Test the case when we stored cacheable lookup into
11664 // a stub, but it got invalidated later on
11665 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11666 v8::Isolate* isolate = CcTest::isolate();
11667 v8::HandleScope scope(isolate);
11668 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11669 templ->SetNamedPropertyHandler(NoBlockGetterX);
11670 LocalContext context;
11671 context->Global()->Set(v8_str("o"), templ->NewInstance());
11672 v8::Handle<Value> value = CompileRun(
11673 "proto1 = new Object();"
11674 "proto2 = new Object();"
11675 "o.__proto__ = proto1;"
11676 "proto1.__proto__ = proto2;"
11677 "proto2.y = function(x) { return x + 1; };"
11678 // Invoke it many times to compile a stub
11679 "for (var i = 0; i < 7; i++) {"
11682 "proto1.y = function(x) { return x - 1; };"
11684 "for (var i = 0; i < 7; i++) {"
11685 " result += o.y(42);"
11687 CHECK_EQ(41 * 7, value->Int32Value());
11691 // This test checks that if interceptor doesn't provide a function,
11692 // cached constant function is used
11693 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11694 v8::Isolate* isolate = CcTest::isolate();
11695 v8::HandleScope scope(isolate);
11696 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11697 templ->SetNamedPropertyHandler(NoBlockGetterX);
11698 LocalContext context;
11699 context->Global()->Set(v8_str("o"), templ->NewInstance());
11700 v8::Handle<Value> value = CompileRun(
11701 "function inc(x) { return x + 1; };"
11705 "for (var i = 0; i < 1000; i++) {"
11706 " result = o.x(42);"
11708 CHECK_EQ(43, value->Int32Value());
11712 static v8::Handle<Value> call_ic_function5;
11713 static void InterceptorCallICGetter5(
11714 Local<String> name,
11715 const v8::PropertyCallbackInfo<v8::Value>& info) {
11716 ApiTestFuzzer::Fuzz();
11717 if (v8_str("x")->Equals(name))
11718 info.GetReturnValue().Set(call_ic_function5);
11722 // This test checks that if interceptor provides a function,
11723 // even if we cached constant function, interceptor's function
11725 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11726 v8::Isolate* isolate = CcTest::isolate();
11727 v8::HandleScope scope(isolate);
11728 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11729 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11730 LocalContext context;
11731 context->Global()->Set(v8_str("o"), templ->NewInstance());
11732 call_ic_function5 =
11733 v8_compile("function f(x) { return x - 1; }; f")->Run();
11734 v8::Handle<Value> value = CompileRun(
11735 "function inc(x) { return x + 1; };"
11739 "for (var i = 0; i < 1000; i++) {"
11740 " result = o.x(42);"
11742 CHECK_EQ(41, value->Int32Value());
11746 static v8::Handle<Value> call_ic_function6;
11747 static void InterceptorCallICGetter6(
11748 Local<String> name,
11749 const v8::PropertyCallbackInfo<v8::Value>& info) {
11750 ApiTestFuzzer::Fuzz();
11751 if (v8_str("x")->Equals(name))
11752 info.GetReturnValue().Set(call_ic_function6);
11756 // Same test as above, except the code is wrapped in a function
11757 // to test the optimized compiler.
11758 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11759 i::FLAG_allow_natives_syntax = true;
11760 v8::Isolate* isolate = CcTest::isolate();
11761 v8::HandleScope scope(isolate);
11762 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11763 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11764 LocalContext context;
11765 context->Global()->Set(v8_str("o"), templ->NewInstance());
11766 call_ic_function6 =
11767 v8_compile("function f(x) { return x - 1; }; f")->Run();
11768 v8::Handle<Value> value = CompileRun(
11769 "function inc(x) { return x + 1; };"
11772 "function test() {"
11774 " for (var i = 0; i < 1000; i++) {"
11775 " result = o.x(42);"
11782 "%OptimizeFunctionOnNextCall(test);"
11784 CHECK_EQ(41, value->Int32Value());
11788 // Test the case when we stored constant function into
11789 // a stub, but it got invalidated later on
11790 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11791 v8::Isolate* isolate = CcTest::isolate();
11792 v8::HandleScope scope(isolate);
11793 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11794 templ->SetNamedPropertyHandler(NoBlockGetterX);
11795 LocalContext context;
11796 context->Global()->Set(v8_str("o"), templ->NewInstance());
11797 v8::Handle<Value> value = CompileRun(
11798 "function inc(x) { return x + 1; };"
11800 "proto1 = new Object();"
11801 "proto2 = new Object();"
11802 "o.__proto__ = proto1;"
11803 "proto1.__proto__ = proto2;"
11805 // Invoke it many times to compile a stub
11806 "for (var i = 0; i < 7; i++) {"
11809 "proto1.y = function(x) { return x - 1; };"
11811 "for (var i = 0; i < 7; i++) {"
11812 " result += o.y(42);"
11814 CHECK_EQ(41 * 7, value->Int32Value());
11818 // Test the case when we stored constant function into
11819 // a stub, but it got invalidated later on due to override on
11820 // global object which is between interceptor and constant function' holders.
11821 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11822 v8::Isolate* isolate = CcTest::isolate();
11823 v8::HandleScope scope(isolate);
11824 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11825 templ->SetNamedPropertyHandler(NoBlockGetterX);
11826 LocalContext context;
11827 context->Global()->Set(v8_str("o"), templ->NewInstance());
11828 v8::Handle<Value> value = CompileRun(
11829 "function inc(x) { return x + 1; };"
11831 "o.__proto__ = this;"
11832 "this.__proto__.y = inc;"
11833 // Invoke it many times to compile a stub
11834 "for (var i = 0; i < 7; i++) {"
11835 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11837 "this.y = function(x) { return x - 1; };"
11839 "for (var i = 0; i < 7; i++) {"
11840 " result += o.y(42);"
11842 CHECK_EQ(41 * 7, value->Int32Value());
11846 // Test the case when actual function to call sits on global object.
11847 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11848 v8::Isolate* isolate = CcTest::isolate();
11849 v8::HandleScope scope(isolate);
11850 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11851 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11853 LocalContext context;
11854 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11856 v8::Handle<Value> value = CompileRun(
11858 " o.__proto__ = this;"
11859 " for (var i = 0; i < 10; i++) {"
11860 " var v = o.parseFloat('239');"
11861 " if (v != 239) throw v;"
11862 // Now it should be ICed and keep a reference to parseFloat.
11865 " for (var i = 0; i < 10; i++) {"
11866 " result += o.parseFloat('239');"
11872 CHECK_EQ(239 * 10, value->Int32Value());
11875 static void InterceptorCallICFastApi(
11876 Local<String> name,
11877 const v8::PropertyCallbackInfo<v8::Value>& info) {
11878 ApiTestFuzzer::Fuzz();
11879 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11881 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11883 if ((*call_count) % 20 == 0) {
11884 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11888 static void FastApiCallback_TrivialSignature(
11889 const v8::FunctionCallbackInfo<v8::Value>& args) {
11890 ApiTestFuzzer::Fuzz();
11891 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11892 v8::Isolate* isolate = CcTest::isolate();
11893 CHECK_EQ(isolate, args.GetIsolate());
11894 CHECK_EQ(args.This(), args.Holder());
11895 CHECK(args.Data()->Equals(v8_str("method_data")));
11896 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11899 static void FastApiCallback_SimpleSignature(
11900 const v8::FunctionCallbackInfo<v8::Value>& args) {
11901 ApiTestFuzzer::Fuzz();
11902 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11903 v8::Isolate* isolate = CcTest::isolate();
11904 CHECK_EQ(isolate, args.GetIsolate());
11905 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11906 CHECK(args.Data()->Equals(v8_str("method_data")));
11907 // Note, we're using HasRealNamedProperty instead of Has to avoid
11908 // invoking the interceptor again.
11909 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11910 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11914 // Helper to maximize the odds of object moving.
11915 static void GenerateSomeGarbage() {
11918 "for (var i = 0; i < 1000; i++) {"
11919 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11921 "garbage = undefined;");
11925 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11926 static int count = 0;
11927 if (count++ % 3 == 0) {
11928 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11929 // This should move the stub
11930 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
11935 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11936 LocalContext context;
11937 v8::Isolate* isolate = context->GetIsolate();
11938 v8::HandleScope scope(isolate);
11939 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11940 v8::ObjectTemplate::New(isolate);
11941 nativeobject_templ->Set(isolate, "callback",
11942 v8::FunctionTemplate::New(isolate,
11943 DirectApiCallback));
11944 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11945 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11946 // call the api function multiple times to ensure direct call stub creation.
11949 " for (var i = 1; i <= 30; i++) {"
11950 " nativeobject.callback();"
11957 void ThrowingDirectApiCallback(
11958 const v8::FunctionCallbackInfo<v8::Value>& args) {
11959 args.GetIsolate()->ThrowException(v8_str("g"));
11963 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11964 LocalContext context;
11965 v8::Isolate* isolate = context->GetIsolate();
11966 v8::HandleScope scope(isolate);
11967 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11968 v8::ObjectTemplate::New(isolate);
11969 nativeobject_templ->Set(isolate, "callback",
11970 v8::FunctionTemplate::New(isolate,
11971 ThrowingDirectApiCallback));
11972 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11973 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11974 // call the api function multiple times to ensure direct call stub creation.
11975 v8::Handle<Value> result = CompileRun(
11978 " for (var i = 1; i <= 5; i++) {"
11979 " try { nativeobject.callback(); } catch (e) { result += e; }"
11983 CHECK_EQ(v8_str("ggggg"), result);
11987 static Handle<Value> DoDirectGetter() {
11988 if (++p_getter_count % 3 == 0) {
11989 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11990 GenerateSomeGarbage();
11992 return v8_str("Direct Getter Result");
11995 static void DirectGetterCallback(
11996 Local<String> name,
11997 const v8::PropertyCallbackInfo<v8::Value>& info) {
11998 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
11999 info.GetReturnValue().Set(DoDirectGetter());
12003 template<typename Accessor>
12004 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12005 LocalContext context;
12006 v8::Isolate* isolate = context->GetIsolate();
12007 v8::HandleScope scope(isolate);
12008 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12009 obj->SetAccessor(v8_str("p1"), accessor);
12010 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12011 p_getter_count = 0;
12012 v8::Handle<v8::Value> result = CompileRun(
12014 " for (var i = 0; i < 30; i++) o1.p1;"
12018 CHECK_EQ(v8_str("Direct Getter Result"), result);
12019 CHECK_EQ(31, p_getter_count);
12023 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12024 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12028 void ThrowingDirectGetterCallback(
12029 Local<String> name,
12030 const v8::PropertyCallbackInfo<v8::Value>& info) {
12031 info.GetIsolate()->ThrowException(v8_str("g"));
12035 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12036 LocalContext context;
12037 v8::Isolate* isolate = context->GetIsolate();
12038 v8::HandleScope scope(isolate);
12039 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12040 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12041 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12042 v8::Handle<Value> result = CompileRun(
12044 "for (var i = 0; i < 5; i++) {"
12045 " try { o1.p1; } catch (e) { result += e; }"
12048 CHECK_EQ(v8_str("ggggg"), result);
12052 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12053 int interceptor_call_count = 0;
12054 v8::Isolate* isolate = CcTest::isolate();
12055 v8::HandleScope scope(isolate);
12056 v8::Handle<v8::FunctionTemplate> fun_templ =
12057 v8::FunctionTemplate::New(isolate);
12058 v8::Handle<v8::FunctionTemplate> method_templ =
12059 v8::FunctionTemplate::New(isolate,
12060 FastApiCallback_TrivialSignature,
12061 v8_str("method_data"),
12062 v8::Handle<v8::Signature>());
12063 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12064 proto_templ->Set(v8_str("method"), method_templ);
12065 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12066 templ->SetNamedPropertyHandler(
12067 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12068 v8::External::New(isolate, &interceptor_call_count));
12069 LocalContext context;
12070 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12071 GenerateSomeGarbage();
12072 context->Global()->Set(v8_str("o"), fun->NewInstance());
12075 "for (var i = 0; i < 100; i++) {"
12076 " result = o.method(41);"
12078 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12079 CHECK_EQ(100, interceptor_call_count);
12083 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12084 int interceptor_call_count = 0;
12085 v8::Isolate* isolate = CcTest::isolate();
12086 v8::HandleScope scope(isolate);
12087 v8::Handle<v8::FunctionTemplate> fun_templ =
12088 v8::FunctionTemplate::New(isolate);
12089 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12090 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12091 v8::Signature::New(isolate, fun_templ));
12092 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12093 proto_templ->Set(v8_str("method"), method_templ);
12094 fun_templ->SetHiddenPrototype(true);
12095 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12096 templ->SetNamedPropertyHandler(
12097 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12098 v8::External::New(isolate, &interceptor_call_count));
12099 LocalContext context;
12100 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12101 GenerateSomeGarbage();
12102 context->Global()->Set(v8_str("o"), fun->NewInstance());
12105 "var receiver = {};"
12106 "receiver.__proto__ = o;"
12108 "for (var i = 0; i < 100; i++) {"
12109 " result = receiver.method(41);"
12111 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12112 CHECK_EQ(100, interceptor_call_count);
12116 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12117 int interceptor_call_count = 0;
12118 v8::Isolate* isolate = CcTest::isolate();
12119 v8::HandleScope scope(isolate);
12120 v8::Handle<v8::FunctionTemplate> fun_templ =
12121 v8::FunctionTemplate::New(isolate);
12122 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12123 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12124 v8::Signature::New(isolate, fun_templ));
12125 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12126 proto_templ->Set(v8_str("method"), method_templ);
12127 fun_templ->SetHiddenPrototype(true);
12128 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12129 templ->SetNamedPropertyHandler(
12130 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12131 v8::External::New(isolate, &interceptor_call_count));
12132 LocalContext context;
12133 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12134 GenerateSomeGarbage();
12135 context->Global()->Set(v8_str("o"), fun->NewInstance());
12138 "var receiver = {};"
12139 "receiver.__proto__ = o;"
12141 "var saved_result = 0;"
12142 "for (var i = 0; i < 100; i++) {"
12143 " result = receiver.method(41);"
12145 " saved_result = result;"
12146 " receiver = {method: function(x) { return x - 1 }};"
12149 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12150 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12151 CHECK_GE(interceptor_call_count, 50);
12155 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12156 int interceptor_call_count = 0;
12157 v8::Isolate* isolate = CcTest::isolate();
12158 v8::HandleScope scope(isolate);
12159 v8::Handle<v8::FunctionTemplate> fun_templ =
12160 v8::FunctionTemplate::New(isolate);
12161 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12162 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12163 v8::Signature::New(isolate, fun_templ));
12164 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12165 proto_templ->Set(v8_str("method"), method_templ);
12166 fun_templ->SetHiddenPrototype(true);
12167 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12168 templ->SetNamedPropertyHandler(
12169 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12170 v8::External::New(isolate, &interceptor_call_count));
12171 LocalContext context;
12172 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12173 GenerateSomeGarbage();
12174 context->Global()->Set(v8_str("o"), fun->NewInstance());
12177 "var receiver = {};"
12178 "receiver.__proto__ = o;"
12180 "var saved_result = 0;"
12181 "for (var i = 0; i < 100; i++) {"
12182 " result = receiver.method(41);"
12184 " saved_result = result;"
12185 " o.method = function(x) { return x - 1 };"
12188 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12189 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12190 CHECK_GE(interceptor_call_count, 50);
12194 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12195 int interceptor_call_count = 0;
12196 v8::Isolate* isolate = CcTest::isolate();
12197 v8::HandleScope scope(isolate);
12198 v8::Handle<v8::FunctionTemplate> fun_templ =
12199 v8::FunctionTemplate::New(isolate);
12200 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12201 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12202 v8::Signature::New(isolate, fun_templ));
12203 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12204 proto_templ->Set(v8_str("method"), method_templ);
12205 fun_templ->SetHiddenPrototype(true);
12206 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12207 templ->SetNamedPropertyHandler(
12208 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12209 v8::External::New(isolate, &interceptor_call_count));
12210 LocalContext context;
12211 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12212 GenerateSomeGarbage();
12213 context->Global()->Set(v8_str("o"), fun->NewInstance());
12214 v8::TryCatch try_catch;
12217 "var receiver = {};"
12218 "receiver.__proto__ = o;"
12220 "var saved_result = 0;"
12221 "for (var i = 0; i < 100; i++) {"
12222 " result = receiver.method(41);"
12224 " saved_result = result;"
12228 CHECK(try_catch.HasCaught());
12229 // TODO(verwaest): Adjust message.
12230 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12231 try_catch.Exception()->ToString());
12232 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12233 CHECK_GE(interceptor_call_count, 50);
12237 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12238 int interceptor_call_count = 0;
12239 v8::Isolate* isolate = CcTest::isolate();
12240 v8::HandleScope scope(isolate);
12241 v8::Handle<v8::FunctionTemplate> fun_templ =
12242 v8::FunctionTemplate::New(isolate);
12243 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12244 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12245 v8::Signature::New(isolate, fun_templ));
12246 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12247 proto_templ->Set(v8_str("method"), method_templ);
12248 fun_templ->SetHiddenPrototype(true);
12249 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12250 templ->SetNamedPropertyHandler(
12251 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12252 v8::External::New(isolate, &interceptor_call_count));
12253 LocalContext context;
12254 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12255 GenerateSomeGarbage();
12256 context->Global()->Set(v8_str("o"), fun->NewInstance());
12257 v8::TryCatch try_catch;
12260 "var receiver = {};"
12261 "receiver.__proto__ = o;"
12263 "var saved_result = 0;"
12264 "for (var i = 0; i < 100; i++) {"
12265 " result = receiver.method(41);"
12267 " saved_result = result;"
12268 " receiver = {method: receiver.method};"
12271 CHECK(try_catch.HasCaught());
12272 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12273 try_catch.Exception()->ToString());
12274 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12275 CHECK_GE(interceptor_call_count, 50);
12279 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12280 v8::Isolate* isolate = CcTest::isolate();
12281 v8::HandleScope scope(isolate);
12282 v8::Handle<v8::FunctionTemplate> fun_templ =
12283 v8::FunctionTemplate::New(isolate);
12284 v8::Handle<v8::FunctionTemplate> method_templ =
12285 v8::FunctionTemplate::New(isolate,
12286 FastApiCallback_TrivialSignature,
12287 v8_str("method_data"),
12288 v8::Handle<v8::Signature>());
12289 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12290 proto_templ->Set(v8_str("method"), method_templ);
12291 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12293 LocalContext context;
12294 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12295 GenerateSomeGarbage();
12296 context->Global()->Set(v8_str("o"), fun->NewInstance());
12299 "for (var i = 0; i < 100; i++) {"
12300 " result = o.method(41);"
12303 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12307 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12308 v8::Isolate* isolate = CcTest::isolate();
12309 v8::HandleScope scope(isolate);
12310 v8::Handle<v8::FunctionTemplate> fun_templ =
12311 v8::FunctionTemplate::New(isolate);
12312 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12313 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12314 v8::Signature::New(isolate, fun_templ));
12315 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12316 proto_templ->Set(v8_str("method"), method_templ);
12317 fun_templ->SetHiddenPrototype(true);
12318 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12319 CHECK(!templ.IsEmpty());
12320 LocalContext context;
12321 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12322 GenerateSomeGarbage();
12323 context->Global()->Set(v8_str("o"), fun->NewInstance());
12326 "var receiver = {};"
12327 "receiver.__proto__ = o;"
12329 "for (var i = 0; i < 100; i++) {"
12330 " result = receiver.method(41);"
12333 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12337 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12338 v8::Isolate* isolate = CcTest::isolate();
12339 v8::HandleScope scope(isolate);
12340 v8::Handle<v8::FunctionTemplate> fun_templ =
12341 v8::FunctionTemplate::New(isolate);
12342 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12343 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12344 v8::Signature::New(isolate, fun_templ));
12345 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12346 proto_templ->Set(v8_str("method"), method_templ);
12347 fun_templ->SetHiddenPrototype(true);
12348 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12349 CHECK(!templ.IsEmpty());
12350 LocalContext context;
12351 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12352 GenerateSomeGarbage();
12353 context->Global()->Set(v8_str("o"), fun->NewInstance());
12356 "var receiver = {};"
12357 "receiver.__proto__ = o;"
12359 "var saved_result = 0;"
12360 "for (var i = 0; i < 100; i++) {"
12361 " result = receiver.method(41);"
12363 " saved_result = result;"
12364 " receiver = {method: function(x) { return x - 1 }};"
12367 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12368 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12372 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12373 v8::Isolate* isolate = CcTest::isolate();
12374 v8::HandleScope scope(isolate);
12375 v8::Handle<v8::FunctionTemplate> fun_templ =
12376 v8::FunctionTemplate::New(isolate);
12377 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12378 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12379 v8::Signature::New(isolate, fun_templ));
12380 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12381 proto_templ->Set(v8_str("method"), method_templ);
12382 fun_templ->SetHiddenPrototype(true);
12383 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12384 CHECK(!templ.IsEmpty());
12385 LocalContext context;
12386 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12387 GenerateSomeGarbage();
12388 context->Global()->Set(v8_str("o"), fun->NewInstance());
12389 v8::TryCatch try_catch;
12392 "var receiver = {};"
12393 "receiver.__proto__ = o;"
12395 "var saved_result = 0;"
12396 "for (var i = 0; i < 100; i++) {"
12397 " result = receiver.method(41);"
12399 " saved_result = result;"
12403 CHECK(try_catch.HasCaught());
12404 // TODO(verwaest): Adjust message.
12405 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12406 try_catch.Exception()->ToString());
12407 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12411 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12412 v8::Isolate* isolate = CcTest::isolate();
12413 v8::HandleScope scope(isolate);
12414 v8::Handle<v8::FunctionTemplate> fun_templ =
12415 v8::FunctionTemplate::New(isolate);
12416 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12417 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12418 v8::Signature::New(isolate, fun_templ));
12419 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12420 proto_templ->Set(v8_str("method"), method_templ);
12421 fun_templ->SetHiddenPrototype(true);
12422 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12423 CHECK(!templ.IsEmpty());
12424 LocalContext context;
12425 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12426 GenerateSomeGarbage();
12427 context->Global()->Set(v8_str("o"), fun->NewInstance());
12428 v8::TryCatch try_catch;
12431 "var receiver = {};"
12432 "receiver.__proto__ = o;"
12434 "var saved_result = 0;"
12435 "for (var i = 0; i < 100; i++) {"
12436 " result = receiver.method(41);"
12438 " saved_result = result;"
12439 " receiver = Object.create(receiver);"
12442 CHECK(try_catch.HasCaught());
12443 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12444 try_catch.Exception()->ToString());
12445 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12449 v8::Handle<Value> keyed_call_ic_function;
12451 static void InterceptorKeyedCallICGetter(
12452 Local<String> name,
12453 const v8::PropertyCallbackInfo<v8::Value>& info) {
12454 ApiTestFuzzer::Fuzz();
12455 if (v8_str("x")->Equals(name)) {
12456 info.GetReturnValue().Set(keyed_call_ic_function);
12461 // Test the case when we stored cacheable lookup into
12462 // a stub, but the function name changed (to another cacheable function).
12463 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12464 v8::Isolate* isolate = CcTest::isolate();
12465 v8::HandleScope scope(isolate);
12466 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12467 templ->SetNamedPropertyHandler(NoBlockGetterX);
12468 LocalContext context;
12469 context->Global()->Set(v8_str("o"), templ->NewInstance());
12471 "proto = new Object();"
12472 "proto.y = function(x) { return x + 1; };"
12473 "proto.z = function(x) { return x - 1; };"
12474 "o.__proto__ = proto;"
12476 "var method = 'y';"
12477 "for (var i = 0; i < 10; i++) {"
12478 " if (i == 5) { method = 'z'; };"
12479 " result += o[method](41);"
12481 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12485 // Test the case when we stored cacheable lookup into
12486 // a stub, but the function name changed (and the new function is present
12487 // both before and after the interceptor in the prototype chain).
12488 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12489 v8::Isolate* isolate = CcTest::isolate();
12490 v8::HandleScope scope(isolate);
12491 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12492 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12493 LocalContext context;
12494 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12495 keyed_call_ic_function =
12496 v8_compile("function f(x) { return x - 1; }; f")->Run();
12498 "o = new Object();"
12499 "proto2 = new Object();"
12500 "o.y = function(x) { return x + 1; };"
12501 "proto2.y = function(x) { return x + 2; };"
12502 "o.__proto__ = proto1;"
12503 "proto1.__proto__ = proto2;"
12505 "var method = 'x';"
12506 "for (var i = 0; i < 10; i++) {"
12507 " if (i == 5) { method = 'y'; };"
12508 " result += o[method](41);"
12510 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12514 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12515 // on the global object.
12516 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12517 v8::Isolate* isolate = CcTest::isolate();
12518 v8::HandleScope scope(isolate);
12519 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12520 templ->SetNamedPropertyHandler(NoBlockGetterX);
12521 LocalContext context;
12522 context->Global()->Set(v8_str("o"), templ->NewInstance());
12524 "function inc(x) { return x + 1; };"
12526 "function dec(x) { return x - 1; };"
12528 "o.__proto__ = this;"
12529 "this.__proto__.x = inc;"
12530 "this.__proto__.y = dec;"
12532 "var method = 'x';"
12533 "for (var i = 0; i < 10; i++) {"
12534 " if (i == 5) { method = 'y'; };"
12535 " result += o[method](41);"
12537 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12541 // Test the case when actual function to call sits on global object.
12542 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12543 v8::Isolate* isolate = CcTest::isolate();
12544 v8::HandleScope scope(isolate);
12545 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12546 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12547 LocalContext context;
12548 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12551 "function len(x) { return x.length; };"
12552 "o.__proto__ = this;"
12553 "var m = 'parseFloat';"
12555 "for (var i = 0; i < 10; i++) {"
12558 " saved_result = result;"
12560 " result = o[m]('239');"
12562 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12563 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12567 // Test the map transition before the interceptor.
12568 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12569 v8::Isolate* isolate = CcTest::isolate();
12570 v8::HandleScope scope(isolate);
12571 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12572 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12573 LocalContext context;
12574 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12577 "var o = new Object();"
12578 "o.__proto__ = proto;"
12579 "o.method = function(x) { return x + 1; };"
12580 "var m = 'method';"
12582 "for (var i = 0; i < 10; i++) {"
12583 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12584 " result += o[m](41);"
12586 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12590 // Test the map transition after the interceptor.
12591 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12592 v8::Isolate* isolate = CcTest::isolate();
12593 v8::HandleScope scope(isolate);
12594 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12595 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12596 LocalContext context;
12597 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12600 "var proto = new Object();"
12601 "o.__proto__ = proto;"
12602 "proto.method = function(x) { return x + 1; };"
12603 "var m = 'method';"
12605 "for (var i = 0; i < 10; i++) {"
12606 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12607 " result += o[m](41);"
12609 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12613 static int interceptor_call_count = 0;
12615 static void InterceptorICRefErrorGetter(
12616 Local<String> name,
12617 const v8::PropertyCallbackInfo<v8::Value>& info) {
12618 ApiTestFuzzer::Fuzz();
12619 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12620 info.GetReturnValue().Set(call_ic_function2);
12625 // This test should hit load and call ICs for the interceptor case.
12626 // Once in a while, the interceptor will reply that a property was not
12627 // found in which case we should get a reference error.
12628 THREADED_TEST(InterceptorICReferenceErrors) {
12629 v8::Isolate* isolate = CcTest::isolate();
12630 v8::HandleScope scope(isolate);
12631 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12632 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12633 LocalContext context(0, templ, v8::Handle<Value>());
12634 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12635 v8::Handle<Value> value = CompileRun(
12637 " for (var i = 0; i < 1000; i++) {"
12638 " try { x; } catch(e) { return true; }"
12643 CHECK_EQ(true, value->BooleanValue());
12644 interceptor_call_count = 0;
12645 value = CompileRun(
12647 " for (var i = 0; i < 1000; i++) {"
12648 " try { x(42); } catch(e) { return true; }"
12653 CHECK_EQ(true, value->BooleanValue());
12657 static int interceptor_ic_exception_get_count = 0;
12659 static void InterceptorICExceptionGetter(
12660 Local<String> name,
12661 const v8::PropertyCallbackInfo<v8::Value>& info) {
12662 ApiTestFuzzer::Fuzz();
12663 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12664 info.GetReturnValue().Set(call_ic_function3);
12666 if (interceptor_ic_exception_get_count == 20) {
12667 info.GetIsolate()->ThrowException(v8_num(42));
12673 // Test interceptor load/call IC where the interceptor throws an
12674 // exception once in a while.
12675 THREADED_TEST(InterceptorICGetterExceptions) {
12676 interceptor_ic_exception_get_count = 0;
12677 v8::Isolate* isolate = CcTest::isolate();
12678 v8::HandleScope scope(isolate);
12679 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12680 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12681 LocalContext context(0, templ, v8::Handle<Value>());
12682 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12683 v8::Handle<Value> value = CompileRun(
12685 " for (var i = 0; i < 100; i++) {"
12686 " try { x; } catch(e) { return true; }"
12691 CHECK_EQ(true, value->BooleanValue());
12692 interceptor_ic_exception_get_count = 0;
12693 value = CompileRun(
12695 " for (var i = 0; i < 100; i++) {"
12696 " try { x(42); } catch(e) { return true; }"
12701 CHECK_EQ(true, value->BooleanValue());
12705 static int interceptor_ic_exception_set_count = 0;
12707 static void InterceptorICExceptionSetter(
12709 Local<Value> value,
12710 const v8::PropertyCallbackInfo<v8::Value>& info) {
12711 ApiTestFuzzer::Fuzz();
12712 if (++interceptor_ic_exception_set_count > 20) {
12713 info.GetIsolate()->ThrowException(v8_num(42));
12718 // Test interceptor store IC where the interceptor throws an exception
12719 // once in a while.
12720 THREADED_TEST(InterceptorICSetterExceptions) {
12721 interceptor_ic_exception_set_count = 0;
12722 v8::Isolate* isolate = CcTest::isolate();
12723 v8::HandleScope scope(isolate);
12724 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12725 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12726 LocalContext context(0, templ, v8::Handle<Value>());
12727 v8::Handle<Value> value = CompileRun(
12729 " for (var i = 0; i < 100; i++) {"
12730 " try { x = 42; } catch(e) { return true; }"
12735 CHECK_EQ(true, value->BooleanValue());
12739 // Test that we ignore null interceptors.
12740 THREADED_TEST(NullNamedInterceptor) {
12741 v8::Isolate* isolate = CcTest::isolate();
12742 v8::HandleScope scope(isolate);
12743 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12744 templ->SetNamedPropertyHandler(
12745 static_cast<v8::NamedPropertyGetterCallback>(0));
12746 LocalContext context;
12747 templ->Set(CcTest::isolate(), "x", v8_num(42));
12748 v8::Handle<v8::Object> obj = templ->NewInstance();
12749 context->Global()->Set(v8_str("obj"), obj);
12750 v8::Handle<Value> value = CompileRun("obj.x");
12751 CHECK(value->IsInt32());
12752 CHECK_EQ(42, value->Int32Value());
12756 // Test that we ignore null interceptors.
12757 THREADED_TEST(NullIndexedInterceptor) {
12758 v8::Isolate* isolate = CcTest::isolate();
12759 v8::HandleScope scope(isolate);
12760 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761 templ->SetIndexedPropertyHandler(
12762 static_cast<v8::IndexedPropertyGetterCallback>(0));
12763 LocalContext context;
12764 templ->Set(CcTest::isolate(), "42", 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[42]");
12768 CHECK(value->IsInt32());
12769 CHECK_EQ(42, value->Int32Value());
12773 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12774 v8::Isolate* isolate = CcTest::isolate();
12775 v8::HandleScope scope(isolate);
12776 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12777 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12779 env->Global()->Set(v8_str("obj"),
12780 templ->GetFunction()->NewInstance());
12781 ExpectTrue("obj.x === 42");
12782 ExpectTrue("!obj.propertyIsEnumerable('x')");
12786 static void ThrowingGetter(Local<String> name,
12787 const v8::PropertyCallbackInfo<v8::Value>& info) {
12788 ApiTestFuzzer::Fuzz();
12789 info.GetIsolate()->ThrowException(Handle<Value>());
12790 info.GetReturnValue().SetUndefined();
12794 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12795 LocalContext context;
12796 HandleScope scope(context->GetIsolate());
12798 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12799 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12800 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12802 Local<Object> instance = templ->GetFunction()->NewInstance();
12804 Local<Object> another = Object::New(context->GetIsolate());
12805 another->SetPrototype(instance);
12807 Local<Object> with_js_getter = CompileRun(
12809 "o.__defineGetter__('f', function() { throw undefined; });\n"
12810 "o\n").As<Object>();
12811 CHECK(!with_js_getter.IsEmpty());
12813 TryCatch try_catch;
12815 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12816 CHECK(try_catch.HasCaught());
12818 CHECK(result.IsEmpty());
12820 result = another->GetRealNamedProperty(v8_str("f"));
12821 CHECK(try_catch.HasCaught());
12823 CHECK(result.IsEmpty());
12825 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12826 CHECK(try_catch.HasCaught());
12828 CHECK(result.IsEmpty());
12830 result = another->Get(v8_str("f"));
12831 CHECK(try_catch.HasCaught());
12833 CHECK(result.IsEmpty());
12835 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12836 CHECK(try_catch.HasCaught());
12838 CHECK(result.IsEmpty());
12840 result = with_js_getter->Get(v8_str("f"));
12841 CHECK(try_catch.HasCaught());
12843 CHECK(result.IsEmpty());
12847 static void ThrowingCallbackWithTryCatch(
12848 const v8::FunctionCallbackInfo<v8::Value>& args) {
12849 TryCatch try_catch;
12850 // Verboseness is important: it triggers message delivery which can call into
12852 try_catch.SetVerbose(true);
12853 CompileRun("throw 'from JS';");
12854 CHECK(try_catch.HasCaught());
12855 CHECK(!CcTest::i_isolate()->has_pending_exception());
12856 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12860 static int call_depth;
12863 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12864 TryCatch try_catch;
12868 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12869 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12873 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12874 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12878 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12879 Handle<String> errorMessageString = message->Get();
12880 CHECK(!errorMessageString.IsEmpty());
12881 message->GetStackTrace();
12882 message->GetScriptResourceName();
12886 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12887 LocalContext context;
12888 v8::Isolate* isolate = context->GetIsolate();
12889 HandleScope scope(isolate);
12891 Local<Function> func =
12892 FunctionTemplate::New(isolate,
12893 ThrowingCallbackWithTryCatch)->GetFunction();
12894 context->Global()->Set(v8_str("func"), func);
12896 MessageCallback callbacks[] =
12897 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12898 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12899 MessageCallback callback = callbacks[i];
12900 if (callback != NULL) {
12901 V8::AddMessageListener(callback);
12903 // Some small number to control number of times message handler should
12904 // throw an exception.
12907 "var thrown = false;\n"
12908 "try { func(); } catch(e) { thrown = true; }\n"
12910 if (callback != NULL) {
12911 V8::RemoveMessageListeners(callback);
12917 static void ParentGetter(Local<String> name,
12918 const v8::PropertyCallbackInfo<v8::Value>& info) {
12919 ApiTestFuzzer::Fuzz();
12920 info.GetReturnValue().Set(v8_num(1));
12924 static void ChildGetter(Local<String> name,
12925 const v8::PropertyCallbackInfo<v8::Value>& info) {
12926 ApiTestFuzzer::Fuzz();
12927 info.GetReturnValue().Set(v8_num(42));
12931 THREADED_TEST(Overriding) {
12932 i::FLAG_es5_readonly = true;
12933 LocalContext context;
12934 v8::Isolate* isolate = context->GetIsolate();
12935 v8::HandleScope scope(isolate);
12937 // Parent template.
12938 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12939 Local<ObjectTemplate> parent_instance_templ =
12940 parent_templ->InstanceTemplate();
12941 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12943 // Template that inherits from the parent template.
12944 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12945 Local<ObjectTemplate> child_instance_templ =
12946 child_templ->InstanceTemplate();
12947 child_templ->Inherit(parent_templ);
12948 // Override 'f'. The child version of 'f' should get called for child
12950 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12951 // Add 'g' twice. The 'g' added last should get called for instances.
12952 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12953 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12955 // Add 'h' as an accessor to the proto template with ReadOnly attributes
12956 // so 'h' can be shadowed on the instance object.
12957 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12958 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12959 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12961 // Add 'i' as an accessor to the instance template with ReadOnly attributes
12962 // but the attribute does not have effect because it is duplicated with
12964 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12965 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12969 // Instantiate the child template.
12970 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12972 // Check that the child function overrides the parent one.
12973 context->Global()->Set(v8_str("o"), instance);
12974 Local<Value> value = v8_compile("o.f")->Run();
12975 // Check that the 'g' that was added last is hit.
12976 CHECK_EQ(42, value->Int32Value());
12977 value = v8_compile("o.g")->Run();
12978 CHECK_EQ(42, value->Int32Value());
12980 // Check that 'h' cannot be shadowed.
12981 value = v8_compile("o.h = 3; o.h")->Run();
12982 CHECK_EQ(1, value->Int32Value());
12984 // Check that 'i' cannot be shadowed or changed.
12985 value = v8_compile("o.i = 3; o.i")->Run();
12986 CHECK_EQ(42, value->Int32Value());
12990 static void IsConstructHandler(
12991 const v8::FunctionCallbackInfo<v8::Value>& args) {
12992 ApiTestFuzzer::Fuzz();
12993 args.GetReturnValue().Set(args.IsConstructCall());
12997 THREADED_TEST(IsConstructCall) {
12998 v8::Isolate* isolate = CcTest::isolate();
12999 v8::HandleScope scope(isolate);
13001 // Function template with call handler.
13002 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13003 templ->SetCallHandler(IsConstructHandler);
13005 LocalContext context;
13007 context->Global()->Set(v8_str("f"), templ->GetFunction());
13008 Local<Value> value = v8_compile("f()")->Run();
13009 CHECK(!value->BooleanValue());
13010 value = v8_compile("new f()")->Run();
13011 CHECK(value->BooleanValue());
13015 THREADED_TEST(ObjectProtoToString) {
13016 v8::Isolate* isolate = CcTest::isolate();
13017 v8::HandleScope scope(isolate);
13018 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13019 templ->SetClassName(v8_str("MyClass"));
13021 LocalContext context;
13023 Local<String> customized_tostring = v8_str("customized toString");
13025 // Replace Object.prototype.toString
13026 v8_compile("Object.prototype.toString = function() {"
13027 " return 'customized toString';"
13030 // Normal ToString call should call replaced Object.prototype.toString
13031 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13032 Local<String> value = instance->ToString();
13033 CHECK(value->IsString() && value->Equals(customized_tostring));
13035 // ObjectProtoToString should not call replace toString function.
13036 value = instance->ObjectProtoToString();
13037 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13040 value = context->Global()->ObjectProtoToString();
13041 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13043 // Check ordinary object
13044 Local<Value> object = v8_compile("new Object()")->Run();
13045 value = object.As<v8::Object>()->ObjectProtoToString();
13046 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13050 THREADED_TEST(ObjectGetConstructorName) {
13051 LocalContext context;
13052 v8::HandleScope scope(context->GetIsolate());
13053 v8_compile("function Parent() {};"
13054 "function Child() {};"
13055 "Child.prototype = new Parent();"
13056 "var outer = { inner: function() { } };"
13057 "var p = new Parent();"
13058 "var c = new Child();"
13059 "var x = new outer.inner();")->Run();
13061 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13062 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13063 v8_str("Parent")));
13065 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13066 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13069 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13070 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13071 v8_str("outer.inner")));
13075 bool ApiTestFuzzer::fuzzing_ = false;
13076 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13077 int ApiTestFuzzer::active_tests_;
13078 int ApiTestFuzzer::tests_being_run_;
13079 int ApiTestFuzzer::current_;
13082 // We are in a callback and want to switch to another thread (if we
13083 // are currently running the thread fuzzing test).
13084 void ApiTestFuzzer::Fuzz() {
13085 if (!fuzzing_) return;
13086 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13087 test->ContextSwitch();
13091 // Let the next thread go. Since it is also waiting on the V8 lock it may
13092 // not start immediately.
13093 bool ApiTestFuzzer::NextThread() {
13094 int test_position = GetNextTestNumber();
13095 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13096 if (test_position == current_) {
13098 printf("Stay with %s\n", test_name);
13101 if (kLogThreading) {
13102 printf("Switch from %s to %s\n",
13104 RegisterThreadedTest::nth(test_position)->name());
13106 current_ = test_position;
13107 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13112 void ApiTestFuzzer::Run() {
13113 // When it is our turn...
13116 // ... get the V8 lock and start running the test.
13117 v8::Locker locker(CcTest::isolate());
13120 // This test finished.
13123 // If it was the last then signal that fact.
13124 if (active_tests_ == 0) {
13125 all_tests_done_.Signal();
13127 // Otherwise select a new test and start that.
13133 static unsigned linear_congruential_generator;
13136 void ApiTestFuzzer::SetUp(PartOfTest part) {
13137 linear_congruential_generator = i::FLAG_testing_prng_seed;
13139 int count = RegisterThreadedTest::count();
13140 int start = count * part / (LAST_PART + 1);
13141 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13142 active_tests_ = tests_being_run_ = end - start + 1;
13143 for (int i = 0; i < tests_being_run_; i++) {
13144 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13146 for (int i = 0; i < active_tests_; i++) {
13147 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13152 static void CallTestNumber(int test_number) {
13153 (RegisterThreadedTest::nth(test_number)->callback())();
13157 void ApiTestFuzzer::RunAllTests() {
13158 // Set off the first test.
13161 // Wait till they are all done.
13162 all_tests_done_.Wait();
13166 int ApiTestFuzzer::GetNextTestNumber() {
13169 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13170 linear_congruential_generator *= 1664525u;
13171 linear_congruential_generator += 1013904223u;
13172 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13177 void ApiTestFuzzer::ContextSwitch() {
13178 // If the new thread is the same as the current thread there is nothing to do.
13179 if (NextThread()) {
13180 // Now it can start.
13181 v8::Unlocker unlocker(CcTest::isolate());
13182 // Wait till someone starts us again.
13189 void ApiTestFuzzer::TearDown() {
13191 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13192 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13193 if (fuzzer != NULL) fuzzer->Join();
13198 // Lets not be needlessly self-referential.
13200 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13201 ApiTestFuzzer::RunAllTests();
13202 ApiTestFuzzer::TearDown();
13207 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13208 ApiTestFuzzer::RunAllTests();
13209 ApiTestFuzzer::TearDown();
13214 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13215 ApiTestFuzzer::RunAllTests();
13216 ApiTestFuzzer::TearDown();
13221 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13222 ApiTestFuzzer::RunAllTests();
13223 ApiTestFuzzer::TearDown();
13227 void ApiTestFuzzer::CallTest() {
13228 v8::Isolate::Scope scope(CcTest::isolate());
13230 printf("Start test %d\n", test_number_);
13231 CallTestNumber(test_number_);
13233 printf("End test %d\n", test_number_);
13237 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13238 v8::Isolate* isolate = args.GetIsolate();
13239 CHECK(v8::Locker::IsLocked(isolate));
13240 ApiTestFuzzer::Fuzz();
13241 v8::Unlocker unlocker(isolate);
13242 const char* code = "throw 7;";
13244 v8::Locker nested_locker(isolate);
13245 v8::HandleScope scope(isolate);
13246 v8::Handle<Value> exception;
13247 { v8::TryCatch try_catch;
13248 v8::Handle<Value> value = CompileRun(code);
13249 CHECK(value.IsEmpty());
13250 CHECK(try_catch.HasCaught());
13251 // Make sure to wrap the exception in a new handle because
13252 // the handle returned from the TryCatch is destroyed
13253 // when the TryCatch is destroyed.
13254 exception = Local<Value>::New(isolate, try_catch.Exception());
13256 args.GetIsolate()->ThrowException(exception);
13261 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13262 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13263 ApiTestFuzzer::Fuzz();
13264 v8::Unlocker unlocker(CcTest::isolate());
13265 const char* code = "throw 7;";
13267 v8::Locker nested_locker(CcTest::isolate());
13268 v8::HandleScope scope(args.GetIsolate());
13269 v8::Handle<Value> value = CompileRun(code);
13270 CHECK(value.IsEmpty());
13271 args.GetReturnValue().Set(v8_str("foo"));
13276 // These are locking tests that don't need to be run again
13277 // as part of the locking aggregation tests.
13278 TEST(NestedLockers) {
13279 v8::Isolate* isolate = CcTest::isolate();
13280 v8::Locker locker(isolate);
13281 CHECK(v8::Locker::IsLocked(isolate));
13283 v8::HandleScope scope(env->GetIsolate());
13284 Local<v8::FunctionTemplate> fun_templ =
13285 v8::FunctionTemplate::New(isolate, ThrowInJS);
13286 Local<Function> fun = fun_templ->GetFunction();
13287 env->Global()->Set(v8_str("throw_in_js"), fun);
13288 Local<Script> script = v8_compile("(function () {"
13296 CHECK_EQ(91, script->Run()->Int32Value());
13300 // These are locking tests that don't need to be run again
13301 // as part of the locking aggregation tests.
13302 TEST(NestedLockersNoTryCatch) {
13303 v8::Locker locker(CcTest::isolate());
13305 v8::HandleScope scope(env->GetIsolate());
13306 Local<v8::FunctionTemplate> fun_templ =
13307 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13308 Local<Function> fun = fun_templ->GetFunction();
13309 env->Global()->Set(v8_str("throw_in_js"), fun);
13310 Local<Script> script = v8_compile("(function () {"
13318 CHECK_EQ(91, script->Run()->Int32Value());
13322 THREADED_TEST(RecursiveLocking) {
13323 v8::Locker locker(CcTest::isolate());
13325 v8::Locker locker2(CcTest::isolate());
13326 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13331 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13332 ApiTestFuzzer::Fuzz();
13333 v8::Unlocker unlocker(CcTest::isolate());
13337 THREADED_TEST(LockUnlockLock) {
13339 v8::Locker locker(CcTest::isolate());
13340 v8::HandleScope scope(CcTest::isolate());
13342 Local<v8::FunctionTemplate> fun_templ =
13343 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13344 Local<Function> fun = fun_templ->GetFunction();
13345 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13346 Local<Script> script = v8_compile("(function () {"
13347 " unlock_for_a_moment();"
13350 CHECK_EQ(42, script->Run()->Int32Value());
13353 v8::Locker locker(CcTest::isolate());
13354 v8::HandleScope scope(CcTest::isolate());
13356 Local<v8::FunctionTemplate> fun_templ =
13357 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13358 Local<Function> fun = fun_templ->GetFunction();
13359 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13360 Local<Script> script = v8_compile("(function () {"
13361 " unlock_for_a_moment();"
13364 CHECK_EQ(42, script->Run()->Int32Value());
13369 static int GetGlobalObjectsCount() {
13370 CcTest::heap()->EnsureHeapIsIterable();
13372 i::HeapIterator it(CcTest::heap());
13373 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13374 if (object->IsJSGlobalObject()) count++;
13379 static void CheckSurvivingGlobalObjectsCount(int expected) {
13380 // We need to collect all garbage twice to be sure that everything
13381 // has been collected. This is because inline caches are cleared in
13382 // the first garbage collection but some of the maps have already
13383 // been marked at that point. Therefore some of the maps are not
13384 // collected until the second garbage collection.
13385 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13386 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13387 int count = GetGlobalObjectsCount();
13389 if (count != expected) CcTest::heap()->TracePathToGlobal();
13391 CHECK_EQ(expected, count);
13395 TEST(DontLeakGlobalObjects) {
13396 // Regression test for issues 1139850 and 1174891.
13398 i::FLAG_expose_gc = true;
13399 v8::V8::Initialize();
13401 for (int i = 0; i < 5; i++) {
13402 { v8::HandleScope scope(CcTest::isolate());
13403 LocalContext context;
13405 v8::V8::ContextDisposedNotification();
13406 CheckSurvivingGlobalObjectsCount(0);
13408 { v8::HandleScope scope(CcTest::isolate());
13409 LocalContext context;
13410 v8_compile("Date")->Run();
13412 v8::V8::ContextDisposedNotification();
13413 CheckSurvivingGlobalObjectsCount(0);
13415 { v8::HandleScope scope(CcTest::isolate());
13416 LocalContext context;
13417 v8_compile("/aaa/")->Run();
13419 v8::V8::ContextDisposedNotification();
13420 CheckSurvivingGlobalObjectsCount(0);
13422 { v8::HandleScope scope(CcTest::isolate());
13423 const char* extension_list[] = { "v8/gc" };
13424 v8::ExtensionConfiguration extensions(1, extension_list);
13425 LocalContext context(&extensions);
13426 v8_compile("gc();")->Run();
13428 v8::V8::ContextDisposedNotification();
13429 CheckSurvivingGlobalObjectsCount(0);
13434 TEST(CopyablePersistent) {
13435 LocalContext context;
13436 v8::Isolate* isolate = context->GetIsolate();
13437 i::GlobalHandles* globals =
13438 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13439 int initial_handles = globals->global_handles_count();
13440 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13443 CopyableObject handle1;
13445 v8::HandleScope scope(isolate);
13446 handle1.Reset(isolate, v8::Object::New(isolate));
13448 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13449 CopyableObject handle2;
13451 CHECK(handle1 == handle2);
13452 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13453 CopyableObject handle3(handle2);
13454 CHECK(handle1 == handle3);
13455 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13457 // Verify autodispose
13458 CHECK_EQ(initial_handles, globals->global_handles_count());
13462 static void WeakApiCallback(
13463 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13464 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13465 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13466 data.GetParameter()->Reset();
13467 delete data.GetParameter();
13471 TEST(WeakCallbackApi) {
13472 LocalContext context;
13473 v8::Isolate* isolate = context->GetIsolate();
13474 i::GlobalHandles* globals =
13475 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13476 int initial_handles = globals->global_handles_count();
13478 v8::HandleScope scope(isolate);
13479 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13480 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13481 v8::Persistent<v8::Object>* handle =
13482 new v8::Persistent<v8::Object>(isolate, obj);
13483 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13486 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13487 CollectAllGarbage(i::Heap::kNoGCFlags);
13488 // Verify disposed.
13489 CHECK_EQ(initial_handles, globals->global_handles_count());
13493 v8::Persistent<v8::Object> some_object;
13494 v8::Persistent<v8::Object> bad_handle;
13496 void NewPersistentHandleCallback(
13497 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13498 v8::HandleScope scope(data.GetIsolate());
13499 bad_handle.Reset(data.GetIsolate(), some_object);
13500 data.GetParameter()->Reset();
13504 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13505 LocalContext context;
13506 v8::Isolate* isolate = context->GetIsolate();
13508 v8::Persistent<v8::Object> handle1, handle2;
13510 v8::HandleScope scope(isolate);
13511 some_object.Reset(isolate, v8::Object::New(isolate));
13512 handle1.Reset(isolate, v8::Object::New(isolate));
13513 handle2.Reset(isolate, v8::Object::New(isolate));
13515 // Note: order is implementation dependent alas: currently
13516 // global handle nodes are processed by PostGarbageCollectionProcessing
13517 // in reverse allocation order, so if second allocated handle is deleted,
13518 // weak callback of the first handle would be able to 'reallocate' it.
13519 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13521 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13525 v8::Persistent<v8::Object> to_be_disposed;
13527 void DisposeAndForceGcCallback(
13528 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13529 to_be_disposed.Reset();
13530 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13531 data.GetParameter()->Reset();
13535 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13536 LocalContext context;
13537 v8::Isolate* isolate = context->GetIsolate();
13539 v8::Persistent<v8::Object> handle1, handle2;
13541 v8::HandleScope scope(isolate);
13542 handle1.Reset(isolate, v8::Object::New(isolate));
13543 handle2.Reset(isolate, v8::Object::New(isolate));
13545 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13546 to_be_disposed.Reset(isolate, handle2);
13547 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13550 void DisposingCallback(
13551 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13552 data.GetParameter()->Reset();
13555 void HandleCreatingCallback(
13556 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13557 v8::HandleScope scope(data.GetIsolate());
13558 v8::Persistent<v8::Object>(data.GetIsolate(),
13559 v8::Object::New(data.GetIsolate()));
13560 data.GetParameter()->Reset();
13564 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13565 LocalContext context;
13566 v8::Isolate* isolate = context->GetIsolate();
13568 v8::Persistent<v8::Object> handle1, handle2, handle3;
13570 v8::HandleScope scope(isolate);
13571 handle3.Reset(isolate, v8::Object::New(isolate));
13572 handle2.Reset(isolate, v8::Object::New(isolate));
13573 handle1.Reset(isolate, v8::Object::New(isolate));
13575 handle2.SetWeak(&handle2, DisposingCallback);
13576 handle3.SetWeak(&handle3, HandleCreatingCallback);
13577 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13581 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13582 v8::V8::Initialize();
13585 const char* sources[nof] = {
13586 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13590 for (int i = 0; i < nof; i++) {
13591 const char* source = sources[i];
13592 { v8::HandleScope scope(CcTest::isolate());
13593 LocalContext context;
13594 CompileRun(source);
13596 { v8::HandleScope scope(CcTest::isolate());
13597 LocalContext context;
13598 CompileRun(source);
13604 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13605 v8::EscapableHandleScope inner(env->GetIsolate());
13607 v8::Local<Value> three = v8_num(3);
13608 v8::Local<Value> value = inner.Escape(three);
13614 THREADED_TEST(NestedHandleScopeAndContexts) {
13615 v8::Isolate* isolate = CcTest::isolate();
13616 v8::HandleScope outer(isolate);
13617 v8::Local<Context> env = Context::New(isolate);
13619 v8::Handle<Value> value = NestedScope(env);
13620 v8::Handle<String> str(value->ToString());
13621 CHECK(!str.IsEmpty());
13626 static bool MatchPointers(void* key1, void* key2) {
13627 return key1 == key2;
13631 struct SymbolInfo {
13638 class SetFunctionEntryHookTest {
13640 SetFunctionEntryHookTest() {
13641 CHECK(instance_ == NULL);
13644 ~SetFunctionEntryHookTest() {
13645 CHECK(instance_ == this);
13650 symbol_locations_.clear();
13651 invocations_.clear();
13654 void OnJitEvent(const v8::JitCodeEvent* event);
13655 static void JitEvent(const v8::JitCodeEvent* event) {
13656 CHECK(instance_ != NULL);
13657 instance_->OnJitEvent(event);
13660 void OnEntryHook(uintptr_t function,
13661 uintptr_t return_addr_location);
13662 static void EntryHook(uintptr_t function,
13663 uintptr_t return_addr_location) {
13664 CHECK(instance_ != NULL);
13665 instance_->OnEntryHook(function, return_addr_location);
13668 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13669 CHECK(instance_ != NULL);
13670 args.GetReturnValue().Set(v8_num(42));
13672 void RunLoopInNewEnv(v8::Isolate* isolate);
13674 // Records addr as location of symbol.
13675 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13677 // Finds the symbol containing addr
13678 SymbolInfo* FindSymbolForAddr(i::Address addr);
13679 // Returns the number of invocations where the caller name contains
13680 // \p caller_name and the function name contains \p function_name.
13681 int CountInvocations(const char* caller_name,
13682 const char* function_name);
13684 i::Handle<i::JSFunction> foo_func_;
13685 i::Handle<i::JSFunction> bar_func_;
13687 typedef std::map<size_t, SymbolInfo> SymbolMap;
13688 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13689 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13690 SymbolMap symbols_;
13691 SymbolLocationMap symbol_locations_;
13692 InvocationMap invocations_;
13694 static SetFunctionEntryHookTest* instance_;
13696 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13699 // Returns true if addr is in the range [start, start+len).
13700 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13701 if (start <= addr && start + len > addr)
13707 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13708 SymbolInfo* symbol) {
13709 // Insert the symbol at the new location.
13710 SymbolLocationMap::iterator it =
13711 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13712 // Now erase symbols to the left and right that overlap this one.
13713 while (it != symbol_locations_.begin()) {
13714 SymbolLocationMap::iterator left = it;
13716 if (!Overlaps(left->first, left->second->size, addr))
13718 symbol_locations_.erase(left);
13721 // Now erase symbols to the left and right that overlap this one.
13723 SymbolLocationMap::iterator right = it;
13725 if (right == symbol_locations_.end())
13727 if (!Overlaps(addr, symbol->size, right->first))
13729 symbol_locations_.erase(right);
13734 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13735 switch (event->type) {
13736 case v8::JitCodeEvent::CODE_ADDED: {
13737 CHECK(event->code_start != NULL);
13738 CHECK_NE(0, static_cast<int>(event->code_len));
13739 CHECK(event->name.str != NULL);
13740 size_t symbol_id = symbols_.size();
13742 // Record the new symbol.
13743 SymbolInfo& info = symbols_[symbol_id];
13744 info.id = symbol_id;
13745 info.size = event->code_len;
13746 info.name.assign(event->name.str, event->name.str + event->name.len);
13748 // And record it's location.
13749 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13753 case v8::JitCodeEvent::CODE_MOVED: {
13754 // We would like to never see code move that we haven't seen before,
13755 // but the code creation event does not happen until the line endings
13756 // have been calculated (this is so that we can report the line in the
13757 // script at which the function source is found, see
13758 // Compiler::RecordFunctionCompilation) and the line endings
13759 // calculations can cause a GC, which can move the newly created code
13760 // before its existence can be logged.
13761 SymbolLocationMap::iterator it(
13762 symbol_locations_.find(
13763 reinterpret_cast<i::Address>(event->code_start)));
13764 if (it != symbol_locations_.end()) {
13765 // Found a symbol at this location, move it.
13766 SymbolInfo* info = it->second;
13767 symbol_locations_.erase(it);
13768 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13777 void SetFunctionEntryHookTest::OnEntryHook(
13778 uintptr_t function, uintptr_t return_addr_location) {
13779 // Get the function's code object.
13780 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13781 reinterpret_cast<i::Address>(function));
13782 CHECK(function_code != NULL);
13784 // Then try and look up the caller's code object.
13785 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13787 // Count the invocation.
13788 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13789 SymbolInfo* function_symbol =
13790 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13791 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13793 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13794 // Check that we have a symbol for the "bar" function at the right location.
13795 SymbolLocationMap::iterator it(
13796 symbol_locations_.find(function_code->instruction_start()));
13797 CHECK(it != symbol_locations_.end());
13800 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13801 // Check that we have a symbol for "foo" at the right location.
13802 SymbolLocationMap::iterator it(
13803 symbol_locations_.find(function_code->instruction_start()));
13804 CHECK(it != symbol_locations_.end());
13809 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13810 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13811 // Do we have a direct hit on a symbol?
13812 if (it != symbol_locations_.end()) {
13813 if (it->first == addr)
13817 // If not a direct hit, it'll have to be the previous symbol.
13818 if (it == symbol_locations_.begin())
13822 size_t offs = addr - it->first;
13823 if (offs < it->second->size)
13830 int SetFunctionEntryHookTest::CountInvocations(
13831 const char* caller_name, const char* function_name) {
13832 InvocationMap::iterator it(invocations_.begin());
13833 int invocations = 0;
13834 for (; it != invocations_.end(); ++it) {
13835 SymbolInfo* caller = it->first.first;
13836 SymbolInfo* function = it->first.second;
13838 // Filter out non-matching functions.
13839 if (function_name != NULL) {
13840 if (function->name.find(function_name) == std::string::npos)
13844 // Filter out non-matching callers.
13845 if (caller_name != NULL) {
13846 if (caller == NULL)
13848 if (caller->name.find(caller_name) == std::string::npos)
13852 // It matches add the invocation count to the tally.
13853 invocations += it->second;
13856 return invocations;
13860 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13861 v8::HandleScope outer(isolate);
13862 v8::Local<Context> env = Context::New(isolate);
13865 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13866 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13867 env->Global()->Set(v8_str("obj"), t->NewInstance());
13869 const char* script =
13870 "function bar() {\n"
13872 " for (i = 0; i < 100; ++i)\n"
13876 "function foo(i) { return i * i; }\n"
13877 "// Invoke on the runtime function.\n"
13879 CompileRun(script);
13880 bar_func_ = i::Handle<i::JSFunction>::cast(
13881 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13882 ASSERT(!bar_func_.is_null());
13885 i::Handle<i::JSFunction>::cast(
13886 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13887 ASSERT(!foo_func_.is_null());
13889 v8::Handle<v8::Value> value = CompileRun("bar();");
13890 CHECK(value->IsNumber());
13891 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13893 // Test the optimized codegen path.
13894 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13896 CHECK(value->IsNumber());
13897 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13903 void SetFunctionEntryHookTest::RunTest() {
13904 // Work in a new isolate throughout.
13905 v8::Isolate* isolate = v8::Isolate::New();
13907 // Test setting the entry hook on the new isolate.
13908 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13910 // Replacing the hook, once set should fail.
13911 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13914 v8::Isolate::Scope scope(isolate);
13916 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13918 RunLoopInNewEnv(isolate);
13920 // Check the exepected invocation counts.
13921 CHECK_EQ(2, CountInvocations(NULL, "bar"));
13922 CHECK_EQ(200, CountInvocations("bar", "foo"));
13923 CHECK_EQ(200, CountInvocations(NULL, "foo"));
13925 // Verify that we have an entry hook on some specific stubs.
13926 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13927 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13928 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13930 isolate->Dispose();
13934 // Make sure a second isolate is unaffected by the previous entry hook.
13935 isolate = v8::Isolate::New();
13937 v8::Isolate::Scope scope(isolate);
13939 // Reset the entry count to zero and set the entry hook.
13940 RunLoopInNewEnv(isolate);
13942 // We should record no invocations in this isolate.
13943 CHECK_EQ(0, static_cast<int>(invocations_.size()));
13945 // Since the isolate has been used, we shouldn't be able to set an entry
13947 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13949 isolate->Dispose();
13953 TEST(SetFunctionEntryHook) {
13954 // FunctionEntryHook does not work well with experimental natives.
13955 // Experimental natives are compiled during snapshot deserialization.
13956 // This test breaks because InstallGetter (function from snapshot that
13957 // only gets called from experimental natives) is compiled with entry hooks.
13958 i::FLAG_allow_natives_syntax = true;
13959 i::FLAG_use_inlining = false;
13961 SetFunctionEntryHookTest test;
13966 static i::HashMap* code_map = NULL;
13967 static i::HashMap* jitcode_line_info = NULL;
13968 static int saw_bar = 0;
13969 static int move_events = 0;
13972 static bool FunctionNameIs(const char* expected,
13973 const v8::JitCodeEvent* event) {
13974 // Log lines for functions are of the general form:
13975 // "LazyCompile:<type><function_name>", where the type is one of
13977 static const char kPreamble[] = "LazyCompile:";
13978 static size_t kPreambleLen = sizeof(kPreamble) - 1;
13980 if (event->name.len < sizeof(kPreamble) - 1 ||
13981 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13985 const char* tail = event->name.str + kPreambleLen;
13986 size_t tail_len = event->name.len - kPreambleLen;
13987 size_t expected_len = strlen(expected);
13988 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13993 // Check for tails like 'bar :1'.
13994 if (tail_len > expected_len + 2 &&
13995 tail[expected_len] == ' ' &&
13996 tail[expected_len + 1] == ':' &&
13997 tail[expected_len + 2] &&
13998 !strncmp(tail, expected, expected_len)) {
14002 if (tail_len != expected_len)
14005 return strncmp(tail, expected, expected_len) == 0;
14009 static void event_handler(const v8::JitCodeEvent* event) {
14010 CHECK(event != NULL);
14011 CHECK(code_map != NULL);
14012 CHECK(jitcode_line_info != NULL);
14014 class DummyJitCodeLineInfo {
14017 switch (event->type) {
14018 case v8::JitCodeEvent::CODE_ADDED: {
14019 CHECK(event->code_start != NULL);
14020 CHECK_NE(0, static_cast<int>(event->code_len));
14021 CHECK(event->name.str != NULL);
14022 i::HashMap::Entry* entry =
14023 code_map->Lookup(event->code_start,
14024 i::ComputePointerHash(event->code_start),
14026 entry->value = reinterpret_cast<void*>(event->code_len);
14028 if (FunctionNameIs("bar", event)) {
14034 case v8::JitCodeEvent::CODE_MOVED: {
14035 uint32_t hash = i::ComputePointerHash(event->code_start);
14036 // We would like to never see code move that we haven't seen before,
14037 // but the code creation event does not happen until the line endings
14038 // have been calculated (this is so that we can report the line in the
14039 // script at which the function source is found, see
14040 // Compiler::RecordFunctionCompilation) and the line endings
14041 // calculations can cause a GC, which can move the newly created code
14042 // before its existence can be logged.
14043 i::HashMap::Entry* entry =
14044 code_map->Lookup(event->code_start, hash, false);
14045 if (entry != NULL) {
14048 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14049 code_map->Remove(event->code_start, hash);
14051 entry = code_map->Lookup(event->new_code_start,
14052 i::ComputePointerHash(event->new_code_start),
14054 CHECK(entry != NULL);
14055 entry->value = reinterpret_cast<void*>(event->code_len);
14060 case v8::JitCodeEvent::CODE_REMOVED:
14061 // Object/code removal events are currently not dispatched from the GC.
14065 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14066 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14067 // record it in jitcode_line_info.
14068 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14069 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14070 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14071 temp_event->user_data = line_info;
14072 i::HashMap::Entry* entry =
14073 jitcode_line_info->Lookup(line_info,
14074 i::ComputePointerHash(line_info),
14076 entry->value = reinterpret_cast<void*>(line_info);
14079 // For these two events, we will check whether the event->user_data
14080 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14081 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14082 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14083 CHECK(event->user_data != NULL);
14084 uint32_t hash = i::ComputePointerHash(event->user_data);
14085 i::HashMap::Entry* entry =
14086 jitcode_line_info->Lookup(event->user_data, hash, false);
14087 CHECK(entry != NULL);
14088 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14092 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14093 CHECK(event->user_data != NULL);
14094 uint32_t hash = i::ComputePointerHash(event->user_data);
14095 i::HashMap::Entry* entry =
14096 jitcode_line_info->Lookup(event->user_data, hash, false);
14097 CHECK(entry != NULL);
14102 // Impossible event.
14109 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14110 i::FLAG_stress_compaction = true;
14111 i::FLAG_incremental_marking = false;
14112 const char* script =
14115 " for (i = 0; i < 100; ++i)"
14119 "function foo(i) { return i * i; };"
14122 // Run this test in a new isolate to make sure we don't
14123 // have remnants of state from other code.
14124 v8::Isolate* isolate = v8::Isolate::New();
14126 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
14129 v8::HandleScope scope(isolate);
14130 i::HashMap code(MatchPointers);
14133 i::HashMap lineinfo(MatchPointers);
14134 jitcode_line_info = &lineinfo;
14139 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14141 // Generate new code objects sparsely distributed across several
14142 // different fragmented code-space pages.
14143 const int kIterations = 10;
14144 for (int i = 0; i < kIterations; ++i) {
14145 LocalContext env(isolate);
14146 i::AlwaysAllocateScope always_allocate;
14147 SimulateFullSpace(heap->code_space());
14148 CompileRun(script);
14150 // Keep a strong reference to the code object in the handle scope.
14151 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14152 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14153 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14154 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14156 // Clear the compilation cache to get more wastage.
14157 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14160 // Force code movement.
14161 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14163 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14165 CHECK_LE(kIterations, saw_bar);
14166 CHECK_LT(0, move_events);
14169 jitcode_line_info = NULL;
14173 isolate->Dispose();
14175 // Do this in a new isolate.
14176 isolate = v8::Isolate::New();
14179 // Verify that we get callbacks for existing code objects when we
14180 // request enumeration of existing code.
14182 v8::HandleScope scope(isolate);
14183 LocalContext env(isolate);
14184 CompileRun(script);
14186 // Now get code through initial iteration.
14187 i::HashMap code(MatchPointers);
14190 i::HashMap lineinfo(MatchPointers);
14191 jitcode_line_info = &lineinfo;
14193 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14194 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14196 jitcode_line_info = NULL;
14197 // We expect that we got some events. Note that if we could get code removal
14198 // notifications, we could compare two collections, one created by listening
14199 // from the time of creation of an isolate, and the other by subscribing
14200 // with EnumExisting.
14201 CHECK_LT(0, code.occupancy());
14207 isolate->Dispose();
14211 THREADED_TEST(ExternalAllocatedMemory) {
14212 v8::Isolate* isolate = CcTest::isolate();
14213 v8::HandleScope outer(isolate);
14214 v8::Local<Context> env(Context::New(isolate));
14215 CHECK(!env.IsEmpty());
14216 const int64_t kSize = 1024*1024;
14217 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14218 CHECK_EQ(baseline + kSize,
14219 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14221 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14225 // Regression test for issue 54, object templates with internal fields
14226 // but no accessors or interceptors did not get their internal field
14227 // count set on instances.
14228 THREADED_TEST(Regress54) {
14229 LocalContext context;
14230 v8::Isolate* isolate = context->GetIsolate();
14231 v8::HandleScope outer(isolate);
14232 static v8::Persistent<v8::ObjectTemplate> templ;
14233 if (templ.IsEmpty()) {
14234 v8::EscapableHandleScope inner(isolate);
14235 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14236 local->SetInternalFieldCount(1);
14237 templ.Reset(isolate, inner.Escape(local));
14239 v8::Handle<v8::Object> result =
14240 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14241 CHECK_EQ(1, result->InternalFieldCount());
14245 // If part of the threaded tests, this test makes ThreadingTest fail
14247 TEST(CatchStackOverflow) {
14248 LocalContext context;
14249 v8::HandleScope scope(context->GetIsolate());
14250 v8::TryCatch try_catch;
14251 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8(
14252 context->GetIsolate(),
14258 v8::Handle<v8::Value> result = script->Run();
14259 CHECK(result.IsEmpty());
14263 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14264 const char* resource_name,
14266 v8::HandleScope scope(CcTest::isolate());
14267 v8::TryCatch try_catch;
14268 v8::Handle<v8::Value> result = script->Run();
14269 CHECK(result.IsEmpty());
14270 CHECK(try_catch.HasCaught());
14271 v8::Handle<v8::Message> message = try_catch.Message();
14272 CHECK(!message.IsEmpty());
14273 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14274 CHECK_EQ(91, message->GetStartPosition());
14275 CHECK_EQ(92, message->GetEndPosition());
14276 CHECK_EQ(2, message->GetStartColumn());
14277 CHECK_EQ(3, message->GetEndColumn());
14278 v8::String::Utf8Value line(message->GetSourceLine());
14279 CHECK_EQ(" throw 'nirk';", *line);
14280 v8::String::Utf8Value name(message->GetScriptResourceName());
14281 CHECK_EQ(resource_name, *name);
14285 THREADED_TEST(TryCatchSourceInfo) {
14286 LocalContext context;
14287 v8::HandleScope scope(context->GetIsolate());
14288 v8::Handle<v8::String> source = v8::String::NewFromUtf8(
14289 context->GetIsolate(),
14290 "function Foo() {\n"
14294 "function Bar() {\n"
14298 "function Baz() {\n"
14304 const char* resource_name;
14305 v8::Handle<v8::Script> script;
14306 resource_name = "test.js";
14307 script = v8::Script::Compile(
14308 source, v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14309 CheckTryCatchSourceInfo(script, resource_name, 0);
14311 resource_name = "test1.js";
14312 v8::ScriptOrigin origin1(
14313 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14314 script = v8::Script::Compile(source, &origin1);
14315 CheckTryCatchSourceInfo(script, resource_name, 0);
14317 resource_name = "test2.js";
14318 v8::ScriptOrigin origin2(
14319 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14320 v8::Integer::New(context->GetIsolate(), 7));
14321 script = v8::Script::Compile(source, &origin2);
14322 CheckTryCatchSourceInfo(script, resource_name, 7);
14326 THREADED_TEST(CompilationCache) {
14327 LocalContext context;
14328 v8::HandleScope scope(context->GetIsolate());
14329 v8::Handle<v8::String> source0 =
14330 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14331 v8::Handle<v8::String> source1 =
14332 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14333 v8::Handle<v8::Script> script0 = v8::Script::Compile(
14334 source0, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14335 v8::Handle<v8::Script> script1 = v8::Script::Compile(
14336 source1, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14337 v8::Handle<v8::Script> script2 =
14338 v8::Script::Compile(source0); // different origin
14339 CHECK_EQ(1234, script0->Run()->Int32Value());
14340 CHECK_EQ(1234, script1->Run()->Int32Value());
14341 CHECK_EQ(1234, script2->Run()->Int32Value());
14345 static void FunctionNameCallback(
14346 const v8::FunctionCallbackInfo<v8::Value>& args) {
14347 ApiTestFuzzer::Fuzz();
14348 args.GetReturnValue().Set(v8_num(42));
14352 THREADED_TEST(CallbackFunctionName) {
14353 LocalContext context;
14354 v8::Isolate* isolate = context->GetIsolate();
14355 v8::HandleScope scope(isolate);
14356 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14357 t->Set(v8_str("asdf"),
14358 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14359 context->Global()->Set(v8_str("obj"), t->NewInstance());
14360 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14361 CHECK(value->IsString());
14362 v8::String::Utf8Value name(value);
14363 CHECK_EQ("asdf", *name);
14367 THREADED_TEST(DateAccess) {
14368 LocalContext context;
14369 v8::HandleScope scope(context->GetIsolate());
14370 v8::Handle<v8::Value> date =
14371 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14372 CHECK(date->IsDate());
14373 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14377 void CheckProperties(v8::Isolate* isolate,
14378 v8::Handle<v8::Value> val,
14380 const char* elmv[]) {
14381 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14382 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14383 CHECK_EQ(elmc, props->Length());
14384 for (int i = 0; i < elmc; i++) {
14385 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14386 CHECK_EQ(elmv[i], *elm);
14391 void CheckOwnProperties(v8::Isolate* isolate,
14392 v8::Handle<v8::Value> val,
14394 const char* elmv[]) {
14395 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14396 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14397 CHECK_EQ(elmc, props->Length());
14398 for (int i = 0; i < elmc; i++) {
14399 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14400 CHECK_EQ(elmv[i], *elm);
14405 THREADED_TEST(PropertyEnumeration) {
14406 LocalContext context;
14407 v8::Isolate* isolate = context->GetIsolate();
14408 v8::HandleScope scope(isolate);
14409 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14410 context->GetIsolate(),
14413 "result[1] = {a: 1, b: 2};"
14414 "result[2] = [1, 2, 3];"
14415 "var proto = {x: 1, y: 2, z: 3};"
14416 "var x = { __proto__: proto, w: 0, z: 1 };"
14418 "result;"))->Run();
14419 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14420 CHECK_EQ(4, elms->Length());
14422 const char** elmv0 = NULL;
14424 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14425 CheckOwnProperties(
14426 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14428 const char* elmv1[] = {"a", "b"};
14430 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14431 CheckOwnProperties(
14432 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14434 const char* elmv2[] = {"0", "1", "2"};
14436 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14437 CheckOwnProperties(
14438 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14440 const char* elmv3[] = {"w", "z", "x", "y"};
14442 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14444 const char* elmv4[] = {"w", "z"};
14445 CheckOwnProperties(
14446 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14450 THREADED_TEST(PropertyEnumeration2) {
14451 LocalContext context;
14452 v8::Isolate* isolate = context->GetIsolate();
14453 v8::HandleScope scope(isolate);
14454 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14455 context->GetIsolate(),
14458 "result[1] = {a: 1, b: 2};"
14459 "result[2] = [1, 2, 3];"
14460 "var proto = {x: 1, y: 2, z: 3};"
14461 "var x = { __proto__: proto, w: 0, z: 1 };"
14463 "result;"))->Run();
14464 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14465 CHECK_EQ(4, elms->Length());
14467 const char** elmv0 = NULL;
14468 CheckProperties(isolate,
14469 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14471 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14472 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14473 CHECK_EQ(0, props->Length());
14474 for (uint32_t i = 0; i < props->Length(); i++) {
14475 printf("p[%d]\n", i);
14479 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14481 v8::AccessType type,
14482 Local<Value> data) {
14483 return type != v8::ACCESS_SET;
14487 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14489 v8::AccessType type,
14490 Local<Value> data) {
14491 return type != v8::ACCESS_SET;
14495 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14496 LocalContext context;
14497 v8::Isolate* isolate = context->GetIsolate();
14498 v8::HandleScope scope(isolate);
14499 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14500 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14501 IndexedSetAccessBlocker);
14502 templ->Set(v8_str("x"), v8::True(isolate));
14503 Local<v8::Object> instance = templ->NewInstance();
14504 context->Global()->Set(v8_str("obj"), instance);
14505 Local<Value> value = CompileRun("obj.x");
14506 CHECK(value->BooleanValue());
14510 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14512 v8::AccessType type,
14513 Local<Value> data) {
14518 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14520 v8::AccessType type,
14521 Local<Value> data) {
14527 THREADED_TEST(AccessChecksReenabledCorrectly) {
14528 LocalContext context;
14529 v8::Isolate* isolate = context->GetIsolate();
14530 v8::HandleScope scope(isolate);
14531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14532 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14533 IndexedGetAccessBlocker);
14534 templ->Set(v8_str("a"), v8_str("a"));
14535 // Add more than 8 (see kMaxFastProperties) properties
14536 // so that the constructor will force copying map.
14537 // Cannot sprintf, gcc complains unsafety.
14539 for (char i = '0'; i <= '9' ; i++) {
14541 for (char j = '0'; j <= '9'; j++) {
14543 for (char k = '0'; k <= '9'; k++) {
14546 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14551 Local<v8::Object> instance_1 = templ->NewInstance();
14552 context->Global()->Set(v8_str("obj_1"), instance_1);
14554 Local<Value> value_1 = CompileRun("obj_1.a");
14555 CHECK(value_1->IsUndefined());
14557 Local<v8::Object> instance_2 = templ->NewInstance();
14558 context->Global()->Set(v8_str("obj_2"), instance_2);
14560 Local<Value> value_2 = CompileRun("obj_2.a");
14561 CHECK(value_2->IsUndefined());
14565 // This tests that access check information remains on the global
14566 // object template when creating contexts.
14567 THREADED_TEST(AccessControlRepeatedContextCreation) {
14568 v8::Isolate* isolate = CcTest::isolate();
14569 v8::HandleScope handle_scope(isolate);
14570 v8::Handle<v8::ObjectTemplate> global_template =
14571 v8::ObjectTemplate::New(isolate);
14572 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14573 IndexedSetAccessBlocker);
14574 i::Handle<i::ObjectTemplateInfo> internal_template =
14575 v8::Utils::OpenHandle(*global_template);
14576 CHECK(!internal_template->constructor()->IsUndefined());
14577 i::Handle<i::FunctionTemplateInfo> constructor(
14578 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14579 CHECK(!constructor->access_check_info()->IsUndefined());
14580 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14581 CHECK(!context0.IsEmpty());
14582 CHECK(!constructor->access_check_info()->IsUndefined());
14586 THREADED_TEST(TurnOnAccessCheck) {
14587 v8::Isolate* isolate = CcTest::isolate();
14588 v8::HandleScope handle_scope(isolate);
14590 // Create an environment with access check to the global object disabled by
14592 v8::Handle<v8::ObjectTemplate> global_template =
14593 v8::ObjectTemplate::New(isolate);
14594 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14595 IndexedGetAccessBlocker,
14596 v8::Handle<v8::Value>(),
14598 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14599 Context::Scope context_scope(context);
14601 // Set up a property and a number of functions.
14602 context->Global()->Set(v8_str("a"), v8_num(1));
14603 CompileRun("function f1() {return a;}"
14604 "function f2() {return a;}"
14605 "function g1() {return h();}"
14606 "function g2() {return h();}"
14607 "function h() {return 1;}");
14608 Local<Function> f1 =
14609 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14610 Local<Function> f2 =
14611 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14612 Local<Function> g1 =
14613 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14614 Local<Function> g2 =
14615 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14616 Local<Function> h =
14617 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14619 // Get the global object.
14620 v8::Handle<v8::Object> global = context->Global();
14622 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14623 // uses the runtime system to retreive property a whereas f2 uses global load
14625 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14626 for (int i = 0; i < 4; i++) {
14627 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14630 // Same for g1 and g2.
14631 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14632 for (int i = 0; i < 4; i++) {
14633 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14636 // Detach the global and turn on access check.
14637 Local<Object> hidden_global = Local<Object>::Cast(
14638 context->Global()->GetPrototype());
14639 context->DetachGlobal();
14640 hidden_global->TurnOnAccessCheck();
14642 // Failing access check to property get results in undefined.
14643 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14644 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14646 // Failing access check to function call results in exception.
14647 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14648 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14650 // No failing access check when just returning a constant.
14651 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14655 static const char* kPropertyA = "a";
14656 static const char* kPropertyH = "h";
14658 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14660 v8::AccessType type,
14661 Local<Value> data) {
14662 if (!name->IsString()) return false;
14663 i::Handle<i::String> name_handle =
14664 v8::Utils::OpenHandle(String::Cast(*name));
14665 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14666 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14670 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14671 v8::Isolate* isolate = CcTest::isolate();
14672 v8::HandleScope handle_scope(isolate);
14674 // Create an environment with access check to the global object disabled by
14675 // default. When the registered access checker will block access to properties
14677 v8::Handle<v8::ObjectTemplate> global_template =
14678 v8::ObjectTemplate::New(isolate);
14679 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14680 IndexedGetAccessBlocker,
14681 v8::Handle<v8::Value>(),
14683 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14684 Context::Scope context_scope(context);
14686 // Set up a property and a number of functions.
14687 context->Global()->Set(v8_str("a"), v8_num(1));
14688 static const char* source = "function f1() {return a;}"
14689 "function f2() {return a;}"
14690 "function g1() {return h();}"
14691 "function g2() {return h();}"
14692 "function h() {return 1;}";
14694 CompileRun(source);
14695 Local<Function> f1;
14696 Local<Function> f2;
14697 Local<Function> g1;
14698 Local<Function> g2;
14700 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14701 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14702 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14703 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14704 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14706 // Get the global object.
14707 v8::Handle<v8::Object> global = context->Global();
14709 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14710 // uses the runtime system to retreive property a whereas f2 uses global load
14712 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14713 for (int i = 0; i < 4; i++) {
14714 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14717 // Same for g1 and g2.
14718 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14719 for (int i = 0; i < 4; i++) {
14720 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14723 // Detach the global and turn on access check now blocking access to property
14724 // a and function h.
14725 Local<Object> hidden_global = Local<Object>::Cast(
14726 context->Global()->GetPrototype());
14727 context->DetachGlobal();
14728 hidden_global->TurnOnAccessCheck();
14730 // Failing access check to property get results in undefined.
14731 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14732 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14734 // Failing access check to function call results in exception.
14735 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14736 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14738 // No failing access check when just returning a constant.
14739 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14741 // Now compile the source again. And get the newly compiled functions, except
14742 // for h for which access is blocked.
14743 CompileRun(source);
14744 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14745 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14746 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14747 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14748 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14750 // Failing access check to property get results in undefined.
14751 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14752 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14754 // Failing access check to function call results in exception.
14755 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14756 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14760 // This test verifies that pre-compilation (aka preparsing) can be called
14761 // without initializing the whole VM. Thus we cannot run this test in a
14762 // multi-threaded setup.
14764 // TODO(155): This test would break without the initialization of V8. This is
14765 // a workaround for now to make this test not fail.
14766 v8::V8::Initialize();
14767 v8::Isolate* isolate = CcTest::isolate();
14768 HandleScope handle_scope(isolate);
14769 const char* script = "function foo(a) { return a+1; }";
14770 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14771 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14772 CHECK_NE(sd->Length(), 0);
14773 CHECK_NE(sd->Data(), NULL);
14774 CHECK(!sd->HasError());
14779 TEST(PreCompileWithError) {
14780 v8::V8::Initialize();
14781 v8::Isolate* isolate = CcTest::isolate();
14782 HandleScope handle_scope(isolate);
14783 const char* script = "function foo(a) { return 1 * * 2; }";
14784 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14785 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14786 CHECK(sd->HasError());
14791 TEST(Regress31661) {
14792 v8::V8::Initialize();
14793 v8::Isolate* isolate = CcTest::isolate();
14794 HandleScope handle_scope(isolate);
14795 const char* script = " The Definintive Guide";
14796 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14797 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14798 CHECK(sd->HasError());
14803 // Tests that ScriptData can be serialized and deserialized.
14804 TEST(PreCompileSerialization) {
14805 v8::V8::Initialize();
14806 v8::Isolate* isolate = CcTest::isolate();
14807 HandleScope handle_scope(isolate);
14808 const char* script = "function foo(a) { return a+1; }";
14809 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14810 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14813 int serialized_data_length = sd->Length();
14814 char* serialized_data = i::NewArray<char>(serialized_data_length);
14815 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14818 v8::ScriptData* deserialized_sd =
14819 v8::ScriptData::New(serialized_data, serialized_data_length);
14821 // Verify that the original is the same as the deserialized.
14822 CHECK_EQ(sd->Length(), deserialized_sd->Length());
14823 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14824 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14827 delete deserialized_sd;
14828 i::DeleteArray(serialized_data);
14832 // Attempts to deserialize bad data.
14833 TEST(PreCompileDeserializationError) {
14834 v8::V8::Initialize();
14835 const char* data = "DONT CARE";
14836 int invalid_size = 3;
14837 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14839 CHECK_EQ(0, sd->Length());
14845 // Attempts to deserialize bad data.
14846 TEST(PreCompileInvalidPreparseDataError) {
14847 v8::V8::Initialize();
14848 v8::Isolate* isolate = CcTest::isolate();
14849 LocalContext context;
14850 v8::HandleScope scope(context->GetIsolate());
14852 const char* script = "function foo(){ return 5;}\n"
14853 "function bar(){ return 6 + 7;} foo();";
14854 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14855 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14856 CHECK(!sd->HasError());
14857 // ScriptDataImpl private implementation details
14858 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14859 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14860 const int kFunctionEntryStartOffset = 0;
14861 const int kFunctionEntryEndOffset = 1;
14862 unsigned* sd_data =
14863 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14865 // Overwrite function bar's end position with 0.
14866 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14867 v8::TryCatch try_catch;
14869 Local<String> source = String::NewFromUtf8(isolate, script);
14870 Local<Script> compiled_script = Script::New(source, NULL, sd);
14871 CHECK(try_catch.HasCaught());
14872 String::Utf8Value exception_value(try_catch.Message()->Get());
14873 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14879 // Overwrite function bar's start position with 200. The function entry
14880 // will not be found when searching for it by position and we should fall
14881 // back on eager compilation.
14882 sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14883 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14884 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14885 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14887 compiled_script = Script::New(source, NULL, sd);
14888 CHECK(!try_catch.HasCaught());
14894 // This tests that we do not allow dictionary load/call inline caches
14895 // to use functions that have not yet been compiled. The potential
14896 // problem of loading a function that has not yet been compiled can
14897 // arise because we share code between contexts via the compilation
14899 THREADED_TEST(DictionaryICLoadedFunction) {
14900 v8::HandleScope scope(CcTest::isolate());
14902 for (int i = 0; i < 2; i++) {
14903 LocalContext context;
14904 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14905 context->Global()->Delete(v8_str("tmp"));
14906 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14909 for (int i = 0; i < 2; i++) {
14910 LocalContext context;
14911 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14912 context->Global()->Delete(v8_str("tmp"));
14913 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14918 // Test that cross-context new calls use the context of the callee to
14919 // create the new JavaScript object.
14920 THREADED_TEST(CrossContextNew) {
14921 v8::Isolate* isolate = CcTest::isolate();
14922 v8::HandleScope scope(isolate);
14923 v8::Local<Context> context0 = Context::New(isolate);
14924 v8::Local<Context> context1 = Context::New(isolate);
14926 // Allow cross-domain access.
14927 Local<String> token = v8_str("<security token>");
14928 context0->SetSecurityToken(token);
14929 context1->SetSecurityToken(token);
14931 // Set an 'x' property on the Object prototype and define a
14932 // constructor function in context0.
14934 CompileRun("Object.prototype.x = 42; function C() {};");
14937 // Call the constructor function from context0 and check that the
14938 // result has the 'x' property.
14940 context1->Global()->Set(v8_str("other"), context0->Global());
14941 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14942 CHECK(value->IsInt32());
14943 CHECK_EQ(42, value->Int32Value());
14948 // Verify that we can clone an object
14949 TEST(ObjectClone) {
14951 v8::Isolate* isolate = env->GetIsolate();
14952 v8::HandleScope scope(isolate);
14954 const char* sample =
14956 "rv.alpha = 'hello';" \
14960 // Create an object, verify basics.
14961 Local<Value> val = CompileRun(sample);
14962 CHECK(val->IsObject());
14963 Local<v8::Object> obj = val.As<v8::Object>();
14964 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14966 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14967 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14968 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14971 Local<v8::Object> clone = obj->Clone();
14972 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14973 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14974 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14976 // Set a property on the clone, verify each object.
14977 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
14978 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14979 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
14983 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14985 explicit AsciiVectorResource(i::Vector<const char> vector)
14987 virtual ~AsciiVectorResource() {}
14988 virtual size_t length() const { return data_.length(); }
14989 virtual const char* data() const { return data_.start(); }
14991 i::Vector<const char> data_;
14995 class UC16VectorResource : public v8::String::ExternalStringResource {
14997 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14999 virtual ~UC16VectorResource() {}
15000 virtual size_t length() const { return data_.length(); }
15001 virtual const i::uc16* data() const { return data_.start(); }
15003 i::Vector<const i::uc16> data_;
15007 static void MorphAString(i::String* string,
15008 AsciiVectorResource* ascii_resource,
15009 UC16VectorResource* uc16_resource) {
15010 CHECK(i::StringShape(string).IsExternal());
15011 if (string->IsOneByteRepresentation()) {
15012 // Check old map is not internalized or long.
15013 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15014 // Morph external string to be TwoByte string.
15015 string->set_map(CcTest::heap()->external_string_map());
15016 i::ExternalTwoByteString* morphed =
15017 i::ExternalTwoByteString::cast(string);
15018 morphed->set_resource(uc16_resource);
15020 // Check old map is not internalized or long.
15021 CHECK(string->map() == CcTest::heap()->external_string_map());
15022 // Morph external string to be ASCII string.
15023 string->set_map(CcTest::heap()->external_ascii_string_map());
15024 i::ExternalAsciiString* morphed =
15025 i::ExternalAsciiString::cast(string);
15026 morphed->set_resource(ascii_resource);
15031 // Test that we can still flatten a string if the components it is built up
15032 // from have been turned into 16 bit strings in the mean time.
15033 THREADED_TEST(MorphCompositeStringTest) {
15034 char utf_buffer[129];
15035 const char* c_string = "Now is the time for all good men"
15036 " to come to the aid of the party";
15037 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15040 i::Factory* factory = CcTest::i_isolate()->factory();
15041 v8::HandleScope scope(env->GetIsolate());
15042 AsciiVectorResource ascii_resource(
15043 i::Vector<const char>(c_string, i::StrLength(c_string)));
15044 UC16VectorResource uc16_resource(
15045 i::Vector<const uint16_t>(two_byte_string,
15046 i::StrLength(c_string)));
15048 Local<String> lhs(v8::Utils::ToLocal(
15049 factory->NewExternalStringFromAscii(&ascii_resource)));
15050 Local<String> rhs(v8::Utils::ToLocal(
15051 factory->NewExternalStringFromAscii(&ascii_resource)));
15053 env->Global()->Set(v8_str("lhs"), lhs);
15054 env->Global()->Set(v8_str("rhs"), rhs);
15057 "var cons = lhs + rhs;"
15058 "var slice = lhs.substring(1, lhs.length - 1);"
15059 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15061 CHECK(lhs->IsOneByte());
15062 CHECK(rhs->IsOneByte());
15064 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15065 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15067 // This should UTF-8 without flattening, since everything is ASCII.
15068 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15069 CHECK_EQ(128, cons->Utf8Length());
15071 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15072 CHECK_EQ(128, nchars);
15073 CHECK_EQ(0, strcmp(
15075 "Now is the time for all good men to come to the aid of the party"
15076 "Now is the time for all good men to come to the aid of the party"));
15078 // Now do some stuff to make sure the strings are flattened, etc.
15080 "/[^a-z]/.test(cons);"
15081 "/[^a-z]/.test(slice);"
15082 "/[^a-z]/.test(slice_on_cons);");
15083 const char* expected_cons =
15084 "Now is the time for all good men to come to the aid of the party"
15085 "Now is the time for all good men to come to the aid of the party";
15086 const char* expected_slice =
15087 "ow is the time for all good men to come to the aid of the part";
15088 const char* expected_slice_on_cons =
15089 "ow is the time for all good men to come to the aid of the party"
15090 "Now is the time for all good men to come to the aid of the part";
15091 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15092 env->Global()->Get(v8_str("cons")));
15093 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15094 env->Global()->Get(v8_str("slice")));
15095 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15096 env->Global()->Get(v8_str("slice_on_cons")));
15098 i::DeleteArray(two_byte_string);
15102 TEST(CompileExternalTwoByteSource) {
15103 LocalContext context;
15104 v8::HandleScope scope(context->GetIsolate());
15106 // This is a very short list of sources, which currently is to check for a
15107 // regression caused by r2703.
15108 const char* ascii_sources[] = {
15110 "-0.5", // This mainly testes PushBack in the Scanner.
15111 "--0.5", // This mainly testes PushBack in the Scanner.
15115 // Compile the sources as external two byte strings.
15116 for (int i = 0; ascii_sources[i] != NULL; i++) {
15117 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15118 TestResource* uc16_resource = new TestResource(two_byte_string);
15119 v8::Local<v8::String> source =
15120 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15121 v8::Script::Compile(source);
15126 #ifndef V8_INTERPRETED_REGEXP
15128 struct RegExpInterruptionData {
15130 UC16VectorResource* string_resource;
15131 v8::Persistent<v8::String> string;
15132 } regexp_interruption_data;
15135 class RegExpInterruptionThread : public i::Thread {
15137 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15138 : Thread("TimeoutThread"), isolate_(isolate) {}
15140 virtual void Run() {
15141 for (regexp_interruption_data.loop_count = 0;
15142 regexp_interruption_data.loop_count < 7;
15143 regexp_interruption_data.loop_count++) {
15144 i::OS::Sleep(50); // Wait a bit before requesting GC.
15145 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15147 i::OS::Sleep(50); // Wait a bit before terminating.
15148 v8::V8::TerminateExecution(isolate_);
15152 v8::Isolate* isolate_;
15156 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15157 if (regexp_interruption_data.loop_count != 2) return;
15158 v8::HandleScope scope(CcTest::isolate());
15159 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15160 CcTest::isolate(), regexp_interruption_data.string);
15161 string->MakeExternal(regexp_interruption_data.string_resource);
15165 // Test that RegExp execution can be interrupted. Specifically, we test
15166 // * interrupting with GC
15167 // * turn the subject string from one-byte internal to two-byte external string
15168 // * force termination
15169 TEST(RegExpInterruption) {
15170 v8::HandleScope scope(CcTest::isolate());
15173 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15175 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15176 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15177 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15178 v8::Local<v8::String> string = v8_str(ascii_content);
15180 CcTest::global()->Set(v8_str("a"), string);
15181 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15182 regexp_interruption_data.string_resource = new UC16VectorResource(
15183 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15185 v8::TryCatch try_catch;
15186 timeout_thread.Start();
15188 CompileRun("/((a*)*)*b/.exec(a)");
15189 CHECK(try_catch.HasTerminated());
15191 timeout_thread.Join();
15193 regexp_interruption_data.string.Reset();
15194 i::DeleteArray(uc16_content);
15197 #endif // V8_INTERPRETED_REGEXP
15200 // Test that we cannot set a property on the global object if there
15201 // is a read-only property in the prototype chain.
15202 TEST(ReadOnlyPropertyInGlobalProto) {
15203 i::FLAG_es5_readonly = true;
15204 v8::Isolate* isolate = CcTest::isolate();
15205 v8::HandleScope scope(isolate);
15206 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15207 LocalContext context(0, templ);
15208 v8::Handle<v8::Object> global = context->Global();
15209 v8::Handle<v8::Object> global_proto =
15210 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15211 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15212 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15213 // Check without 'eval' or 'with'.
15214 v8::Handle<v8::Value> res =
15215 CompileRun("function f() { x = 42; return x; }; f()");
15216 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15217 // Check with 'eval'.
15218 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15219 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15220 // Check with 'with'.
15221 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15222 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15225 static int force_set_set_count = 0;
15226 static int force_set_get_count = 0;
15227 bool pass_on_get = false;
15229 static void ForceSetGetter(v8::Local<v8::String> name,
15230 const v8::PropertyCallbackInfo<v8::Value>& info) {
15231 force_set_get_count++;
15235 info.GetReturnValue().Set(3);
15238 static void ForceSetSetter(v8::Local<v8::String> name,
15239 v8::Local<v8::Value> value,
15240 const v8::PropertyCallbackInfo<void>& info) {
15241 force_set_set_count++;
15244 static void ForceSetInterceptSetter(
15245 v8::Local<v8::String> name,
15246 v8::Local<v8::Value> value,
15247 const v8::PropertyCallbackInfo<v8::Value>& info) {
15248 force_set_set_count++;
15249 info.GetReturnValue().SetUndefined();
15254 force_set_get_count = 0;
15255 force_set_set_count = 0;
15256 pass_on_get = false;
15258 v8::Isolate* isolate = CcTest::isolate();
15259 v8::HandleScope scope(isolate);
15260 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15261 v8::Handle<v8::String> access_property =
15262 v8::String::NewFromUtf8(isolate, "a");
15263 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15264 LocalContext context(NULL, templ);
15265 v8::Handle<v8::Object> global = context->Global();
15267 // Ordinary properties
15268 v8::Handle<v8::String> simple_property =
15269 v8::String::NewFromUtf8(isolate, "p");
15270 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15271 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15272 // This should fail because the property is read-only
15273 global->Set(simple_property, v8::Int32::New(isolate, 5));
15274 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15275 // This should succeed even though the property is read-only
15276 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15277 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15280 CHECK_EQ(0, force_set_set_count);
15281 CHECK_EQ(0, force_set_get_count);
15282 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15283 // CHECK_EQ the property shouldn't override it, just call the setter
15284 // which in this case does nothing.
15285 global->Set(access_property, v8::Int32::New(isolate, 7));
15286 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15287 CHECK_EQ(1, force_set_set_count);
15288 CHECK_EQ(2, force_set_get_count);
15289 // Forcing the property to be set should override the accessor without
15291 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15292 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15293 CHECK_EQ(1, force_set_set_count);
15294 CHECK_EQ(2, force_set_get_count);
15298 TEST(ForceSetWithInterceptor) {
15299 force_set_get_count = 0;
15300 force_set_set_count = 0;
15301 pass_on_get = false;
15303 v8::Isolate* isolate = CcTest::isolate();
15304 v8::HandleScope scope(isolate);
15305 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15306 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15307 LocalContext context(NULL, templ);
15308 v8::Handle<v8::Object> global = context->Global();
15310 v8::Handle<v8::String> some_property =
15311 v8::String::NewFromUtf8(isolate, "a");
15312 CHECK_EQ(0, force_set_set_count);
15313 CHECK_EQ(0, force_set_get_count);
15314 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15315 // Setting the property shouldn't override it, just call the setter
15316 // which in this case does nothing.
15317 global->Set(some_property, v8::Int32::New(isolate, 7));
15318 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15319 CHECK_EQ(1, force_set_set_count);
15320 CHECK_EQ(2, force_set_get_count);
15321 // Getting the property when the interceptor returns an empty handle
15322 // should yield undefined, since the property isn't present on the
15323 // object itself yet.
15324 pass_on_get = true;
15325 CHECK(global->Get(some_property)->IsUndefined());
15326 CHECK_EQ(1, force_set_set_count);
15327 CHECK_EQ(3, force_set_get_count);
15328 // Forcing the property to be set should cause the value to be
15329 // set locally without calling the interceptor.
15330 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15331 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15332 CHECK_EQ(1, force_set_set_count);
15333 CHECK_EQ(4, force_set_get_count);
15334 // Reenabling the interceptor should cause it to take precedence over
15336 pass_on_get = false;
15337 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15338 CHECK_EQ(1, force_set_set_count);
15339 CHECK_EQ(5, force_set_get_count);
15340 // The interceptor should also work for other properties
15341 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15343 CHECK_EQ(1, force_set_set_count);
15344 CHECK_EQ(6, force_set_get_count);
15348 THREADED_TEST(ForceDelete) {
15349 v8::Isolate* isolate = CcTest::isolate();
15350 v8::HandleScope scope(isolate);
15351 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15352 LocalContext context(NULL, templ);
15353 v8::Handle<v8::Object> global = context->Global();
15355 // Ordinary properties
15356 v8::Handle<v8::String> simple_property =
15357 v8::String::NewFromUtf8(isolate, "p");
15358 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15359 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15360 // This should fail because the property is dont-delete.
15361 CHECK(!global->Delete(simple_property));
15362 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15363 // This should succeed even though the property is dont-delete.
15364 CHECK(global->ForceDelete(simple_property));
15365 CHECK(global->Get(simple_property)->IsUndefined());
15369 static int force_delete_interceptor_count = 0;
15370 static bool pass_on_delete = false;
15373 static void ForceDeleteDeleter(
15374 v8::Local<v8::String> name,
15375 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15376 force_delete_interceptor_count++;
15377 if (pass_on_delete) return;
15378 info.GetReturnValue().Set(true);
15382 THREADED_TEST(ForceDeleteWithInterceptor) {
15383 force_delete_interceptor_count = 0;
15384 pass_on_delete = false;
15386 v8::Isolate* isolate = CcTest::isolate();
15387 v8::HandleScope scope(isolate);
15388 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15389 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15390 LocalContext context(NULL, templ);
15391 v8::Handle<v8::Object> global = context->Global();
15393 v8::Handle<v8::String> some_property =
15394 v8::String::NewFromUtf8(isolate, "a");
15395 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15397 // Deleting a property should get intercepted and nothing should
15399 CHECK_EQ(0, force_delete_interceptor_count);
15400 CHECK(global->Delete(some_property));
15401 CHECK_EQ(1, force_delete_interceptor_count);
15402 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15403 // Deleting the property when the interceptor returns an empty
15404 // handle should not delete the property since it is DontDelete.
15405 pass_on_delete = true;
15406 CHECK(!global->Delete(some_property));
15407 CHECK_EQ(2, force_delete_interceptor_count);
15408 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15409 // Forcing the property to be deleted should delete the value
15410 // without calling the interceptor.
15411 CHECK(global->ForceDelete(some_property));
15412 CHECK(global->Get(some_property)->IsUndefined());
15413 CHECK_EQ(2, force_delete_interceptor_count);
15417 // Make sure that forcing a delete invalidates any IC stubs, so we
15418 // don't read the hole value.
15419 THREADED_TEST(ForceDeleteIC) {
15420 LocalContext context;
15421 v8::HandleScope scope(context->GetIsolate());
15422 // Create a DontDelete variable on the global object.
15423 CompileRun("this.__proto__ = { foo: 'horse' };"
15424 "var foo = 'fish';"
15425 "function f() { return foo.length; }");
15426 // Initialize the IC for foo in f.
15427 CompileRun("for (var i = 0; i < 4; i++) f();");
15428 // Make sure the value of foo is correct before the deletion.
15429 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15430 // Force the deletion of foo.
15431 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15432 // Make sure the value for foo is read from the prototype, and that
15433 // we don't get in trouble with reading the deleted cell value
15435 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15439 TEST(InlinedFunctionAcrossContexts) {
15440 i::FLAG_allow_natives_syntax = true;
15441 v8::Isolate* isolate = CcTest::isolate();
15442 v8::HandleScope outer_scope(isolate);
15443 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15444 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15448 v8::HandleScope inner_scope(CcTest::isolate());
15449 CompileRun("var G = 42; function foo() { return G; }");
15450 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15452 ctx2->Global()->Set(v8_str("o"), foo);
15453 v8::Local<v8::Value> res = CompileRun(
15454 "function f() { return o(); }"
15455 "for (var i = 0; i < 10; ++i) f();"
15456 "%OptimizeFunctionOnNextCall(f);"
15458 CHECK_EQ(42, res->Int32Value());
15460 v8::Handle<v8::String> G_property =
15461 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15462 CHECK(ctx1->Global()->ForceDelete(G_property));
15469 " return e.toString();"
15472 "ReferenceError: G is not defined");
15479 static v8::Local<Context> calling_context0;
15480 static v8::Local<Context> calling_context1;
15481 static v8::Local<Context> calling_context2;
15484 // Check that the call to the callback is initiated in
15485 // calling_context2, the directly calling context is calling_context1
15486 // and the callback itself is in calling_context0.
15487 static void GetCallingContextCallback(
15488 const v8::FunctionCallbackInfo<v8::Value>& args) {
15489 ApiTestFuzzer::Fuzz();
15490 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15491 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15492 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15493 args.GetReturnValue().Set(42);
15497 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15498 i::Isolate* isolate = CcTest::i_isolate();
15499 CHECK(isolate != NULL);
15500 CHECK(isolate->context() == NULL);
15501 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15502 v8::HandleScope scope(v8_isolate);
15503 // The following should not crash, but return an empty handle.
15504 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15505 CHECK(current.IsEmpty());
15509 THREADED_TEST(GetCallingContext) {
15510 v8::Isolate* isolate = CcTest::isolate();
15511 v8::HandleScope scope(isolate);
15513 Local<Context> calling_context0(Context::New(isolate));
15514 Local<Context> calling_context1(Context::New(isolate));
15515 Local<Context> calling_context2(Context::New(isolate));
15516 ::calling_context0 = calling_context0;
15517 ::calling_context1 = calling_context1;
15518 ::calling_context2 = calling_context2;
15520 // Allow cross-domain access.
15521 Local<String> token = v8_str("<security token>");
15522 calling_context0->SetSecurityToken(token);
15523 calling_context1->SetSecurityToken(token);
15524 calling_context2->SetSecurityToken(token);
15526 // Create an object with a C++ callback in context0.
15527 calling_context0->Enter();
15528 Local<v8::FunctionTemplate> callback_templ =
15529 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15530 calling_context0->Global()->Set(v8_str("callback"),
15531 callback_templ->GetFunction());
15532 calling_context0->Exit();
15534 // Expose context0 in context1 and set up a function that calls the
15535 // callback function.
15536 calling_context1->Enter();
15537 calling_context1->Global()->Set(v8_str("context0"),
15538 calling_context0->Global());
15539 CompileRun("function f() { context0.callback() }");
15540 calling_context1->Exit();
15542 // Expose context1 in context2 and call the callback function in
15543 // context0 indirectly through f in context1.
15544 calling_context2->Enter();
15545 calling_context2->Global()->Set(v8_str("context1"),
15546 calling_context1->Global());
15547 CompileRun("context1.f()");
15548 calling_context2->Exit();
15549 ::calling_context0.Clear();
15550 ::calling_context1.Clear();
15551 ::calling_context2.Clear();
15555 // Check that a variable declaration with no explicit initialization
15556 // value does shadow an existing property in the prototype chain.
15557 THREADED_TEST(InitGlobalVarInProtoChain) {
15558 i::FLAG_es52_globals = true;
15559 LocalContext context;
15560 v8::HandleScope scope(context->GetIsolate());
15561 // Introduce a variable in the prototype chain.
15562 CompileRun("__proto__.x = 42");
15563 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15564 CHECK(!result->IsUndefined());
15565 CHECK_EQ(43, result->Int32Value());
15569 // Regression test for issue 398.
15570 // If a function is added to an object, creating a constant function
15571 // field, and the result is cloned, replacing the constant function on the
15572 // original should not affect the clone.
15573 // See http://code.google.com/p/v8/issues/detail?id=398
15574 THREADED_TEST(ReplaceConstantFunction) {
15575 LocalContext context;
15576 v8::Isolate* isolate = context->GetIsolate();
15577 v8::HandleScope scope(isolate);
15578 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15579 v8::Handle<v8::FunctionTemplate> func_templ =
15580 v8::FunctionTemplate::New(isolate);
15581 v8::Handle<v8::String> foo_string =
15582 v8::String::NewFromUtf8(isolate, "foo");
15583 obj->Set(foo_string, func_templ->GetFunction());
15584 v8::Handle<v8::Object> obj_clone = obj->Clone();
15585 obj_clone->Set(foo_string,
15586 v8::String::NewFromUtf8(isolate, "Hello"));
15587 CHECK(!obj->Get(foo_string)->IsUndefined());
15591 static void CheckElementValue(i::Isolate* isolate,
15593 i::Handle<i::Object> obj,
15595 i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15596 CHECK_EQ(expected, i::Smi::cast(element)->value());
15600 THREADED_TEST(PixelArray) {
15601 LocalContext context;
15602 i::Isolate* isolate = CcTest::i_isolate();
15603 i::Factory* factory = isolate->factory();
15604 v8::HandleScope scope(context->GetIsolate());
15605 const int kElementCount = 260;
15606 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15607 i::Handle<i::ExternalUint8ClampedArray> pixels =
15608 i::Handle<i::ExternalUint8ClampedArray>::cast(
15609 factory->NewExternalArray(kElementCount,
15610 v8::kExternalUint8ClampedArray,
15612 // Force GC to trigger verification.
15613 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15614 for (int i = 0; i < kElementCount; i++) {
15615 pixels->set(i, i % 256);
15617 // Force GC to trigger verification.
15618 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15619 for (int i = 0; i < kElementCount; i++) {
15620 CHECK_EQ(i % 256, pixels->get_scalar(i));
15621 CHECK_EQ(i % 256, pixel_data[i]);
15624 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15625 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15626 // Set the elements to be the pixels.
15627 // jsobj->set_elements(*pixels);
15628 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15629 CheckElementValue(isolate, 1, jsobj, 1);
15630 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15631 context->Global()->Set(v8_str("pixels"), obj);
15632 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15633 CHECK_EQ(1503, result->Int32Value());
15634 result = CompileRun("pixels[1]");
15635 CHECK_EQ(1, result->Int32Value());
15637 result = CompileRun("var sum = 0;"
15638 "for (var i = 0; i < 8; i++) {"
15639 " sum += pixels[i] = pixels[i] = -i;"
15642 CHECK_EQ(-28, result->Int32Value());
15644 result = CompileRun("var sum = 0;"
15645 "for (var i = 0; i < 8; i++) {"
15646 " sum += pixels[i] = pixels[i] = 0;"
15649 CHECK_EQ(0, result->Int32Value());
15651 result = CompileRun("var sum = 0;"
15652 "for (var i = 0; i < 8; i++) {"
15653 " sum += pixels[i] = pixels[i] = 255;"
15656 CHECK_EQ(8 * 255, result->Int32Value());
15658 result = CompileRun("var sum = 0;"
15659 "for (var i = 0; i < 8; i++) {"
15660 " sum += pixels[i] = pixels[i] = 256 + i;"
15663 CHECK_EQ(2076, result->Int32Value());
15665 result = CompileRun("var sum = 0;"
15666 "for (var i = 0; i < 8; i++) {"
15667 " sum += pixels[i] = pixels[i] = i;"
15670 CHECK_EQ(28, result->Int32Value());
15672 result = CompileRun("var sum = 0;"
15673 "for (var i = 0; i < 8; i++) {"
15674 " sum += pixels[i];"
15677 CHECK_EQ(28, result->Int32Value());
15679 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15680 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15681 i::Handle<i::Object> no_failure;
15683 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15684 ASSERT(!no_failure.is_null());
15685 i::USE(no_failure);
15686 CheckElementValue(isolate, 2, jsobj, 1);
15687 *value.location() = i::Smi::FromInt(256);
15689 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15690 ASSERT(!no_failure.is_null());
15691 i::USE(no_failure);
15692 CheckElementValue(isolate, 255, jsobj, 1);
15693 *value.location() = i::Smi::FromInt(-1);
15695 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15696 ASSERT(!no_failure.is_null());
15697 i::USE(no_failure);
15698 CheckElementValue(isolate, 0, jsobj, 1);
15700 result = CompileRun("for (var i = 0; i < 8; i++) {"
15701 " pixels[i] = (i * 65) - 109;"
15703 "pixels[1] + pixels[6];");
15704 CHECK_EQ(255, result->Int32Value());
15705 CheckElementValue(isolate, 0, jsobj, 0);
15706 CheckElementValue(isolate, 0, jsobj, 1);
15707 CheckElementValue(isolate, 21, jsobj, 2);
15708 CheckElementValue(isolate, 86, jsobj, 3);
15709 CheckElementValue(isolate, 151, jsobj, 4);
15710 CheckElementValue(isolate, 216, jsobj, 5);
15711 CheckElementValue(isolate, 255, jsobj, 6);
15712 CheckElementValue(isolate, 255, jsobj, 7);
15713 result = CompileRun("var sum = 0;"
15714 "for (var i = 0; i < 8; i++) {"
15715 " sum += pixels[i];"
15718 CHECK_EQ(984, result->Int32Value());
15720 result = CompileRun("for (var i = 0; i < 8; i++) {"
15721 " pixels[i] = (i * 1.1);"
15723 "pixels[1] + pixels[6];");
15724 CHECK_EQ(8, result->Int32Value());
15725 CheckElementValue(isolate, 0, jsobj, 0);
15726 CheckElementValue(isolate, 1, jsobj, 1);
15727 CheckElementValue(isolate, 2, jsobj, 2);
15728 CheckElementValue(isolate, 3, jsobj, 3);
15729 CheckElementValue(isolate, 4, jsobj, 4);
15730 CheckElementValue(isolate, 6, jsobj, 5);
15731 CheckElementValue(isolate, 7, jsobj, 6);
15732 CheckElementValue(isolate, 8, jsobj, 7);
15734 result = CompileRun("for (var i = 0; i < 8; i++) {"
15735 " pixels[7] = undefined;"
15738 CHECK_EQ(0, result->Int32Value());
15739 CheckElementValue(isolate, 0, jsobj, 7);
15741 result = CompileRun("for (var i = 0; i < 8; i++) {"
15742 " pixels[6] = '2.3';"
15745 CHECK_EQ(2, result->Int32Value());
15746 CheckElementValue(isolate, 2, jsobj, 6);
15748 result = CompileRun("for (var i = 0; i < 8; i++) {"
15749 " pixels[5] = NaN;"
15752 CHECK_EQ(0, result->Int32Value());
15753 CheckElementValue(isolate, 0, jsobj, 5);
15755 result = CompileRun("for (var i = 0; i < 8; i++) {"
15756 " pixels[8] = Infinity;"
15759 CHECK_EQ(255, result->Int32Value());
15760 CheckElementValue(isolate, 255, jsobj, 8);
15762 result = CompileRun("for (var i = 0; i < 8; i++) {"
15763 " pixels[9] = -Infinity;"
15766 CHECK_EQ(0, result->Int32Value());
15767 CheckElementValue(isolate, 0, jsobj, 9);
15769 result = CompileRun("pixels[3] = 33;"
15770 "delete pixels[3];"
15772 CHECK_EQ(33, result->Int32Value());
15774 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15775 "pixels[2] = 12; pixels[3] = 13;"
15776 "pixels.__defineGetter__('2',"
15777 "function() { return 120; });"
15779 CHECK_EQ(12, result->Int32Value());
15781 result = CompileRun("var js_array = new Array(40);"
15782 "js_array[0] = 77;"
15784 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15786 result = CompileRun("pixels[1] = 23;"
15787 "pixels.__proto__ = [];"
15788 "js_array.__proto__ = pixels;"
15789 "js_array.concat(pixels);");
15790 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15791 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15793 result = CompileRun("pixels[1] = 23;");
15794 CHECK_EQ(23, result->Int32Value());
15796 // Test for index greater than 255. Regression test for:
15797 // http://code.google.com/p/chromium/issues/detail?id=26337.
15798 result = CompileRun("pixels[256] = 255;");
15799 CHECK_EQ(255, result->Int32Value());
15800 result = CompileRun("var i = 0;"
15801 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15803 CHECK_EQ(255, result->Int32Value());
15805 // Make sure that pixel array ICs recognize when a non-pixel array
15806 // is passed to it.
15807 result = CompileRun("function pa_load(p) {"
15809 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15812 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15813 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15814 "just_ints = new Object();"
15815 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15816 "for (var i = 0; i < 10; ++i) {"
15817 " result = pa_load(just_ints);"
15820 CHECK_EQ(32640, result->Int32Value());
15822 // Make sure that pixel array ICs recognize out-of-bound accesses.
15823 result = CompileRun("function pa_load(p, start) {"
15825 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15828 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15829 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15830 "for (var i = 0; i < 10; ++i) {"
15831 " result = pa_load(pixels,-10);"
15834 CHECK_EQ(0, result->Int32Value());
15836 // Make sure that generic ICs properly handles a pixel array.
15837 result = CompileRun("function pa_load(p) {"
15839 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15842 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15843 "just_ints = new Object();"
15844 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15845 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15846 "for (var i = 0; i < 10; ++i) {"
15847 " result = pa_load(pixels);"
15850 CHECK_EQ(32640, result->Int32Value());
15852 // Make sure that generic load ICs recognize out-of-bound accesses in
15854 result = CompileRun("function pa_load(p, start) {"
15856 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15859 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15860 "just_ints = new Object();"
15861 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15862 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15863 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15864 "for (var i = 0; i < 10; ++i) {"
15865 " result = pa_load(pixels,-10);"
15868 CHECK_EQ(0, result->Int32Value());
15870 // Make sure that generic ICs properly handles other types than pixel
15871 // arrays (that the inlined fast pixel array test leaves the right information
15872 // in the right registers).
15873 result = CompileRun("function pa_load(p) {"
15875 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15878 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15879 "just_ints = new Object();"
15880 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15881 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15882 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15883 "sparse_array = new Object();"
15884 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15885 "sparse_array[1000000] = 3;"
15886 "for (var i = 0; i < 10; ++i) {"
15887 " result = pa_load(sparse_array);"
15890 CHECK_EQ(32640, result->Int32Value());
15892 // Make sure that pixel array store ICs clamp values correctly.
15893 result = CompileRun("function pa_store(p) {"
15894 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15896 "pa_store(pixels);"
15898 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15900 CHECK_EQ(48896, result->Int32Value());
15902 // Make sure that pixel array stores correctly handle accesses outside
15903 // of the pixel array..
15904 result = CompileRun("function pa_store(p,start) {"
15905 " for (var j = 0; j < 256; j++) {"
15906 " p[j+start] = j * 2;"
15909 "pa_store(pixels,0);"
15910 "pa_store(pixels,-128);"
15912 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15914 CHECK_EQ(65280, result->Int32Value());
15916 // Make sure that the generic store stub 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 "just_ints = new Object();"
15925 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15926 "pa_store(just_ints, 0);"
15927 "pa_store(pixels,-128);"
15929 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15931 CHECK_EQ(65280, result->Int32Value());
15933 // Make sure that the generic keyed store stub clamps pixel array values
15935 result = CompileRun("function pa_store(p) {"
15936 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15938 "pa_store(pixels);"
15939 "just_ints = new Object();"
15940 "pa_store(just_ints);"
15941 "pa_store(pixels);"
15943 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15945 CHECK_EQ(48896, result->Int32Value());
15947 // Make sure that pixel array loads are optimized by crankshaft.
15948 result = CompileRun("function pa_load(p) {"
15950 " for (var i=0; i<256; ++i) {"
15955 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15956 "for (var i = 0; i < 5000; ++i) {"
15957 " result = pa_load(pixels);"
15960 CHECK_EQ(32640, result->Int32Value());
15962 // Make sure that pixel array stores are optimized by crankshaft.
15963 result = CompileRun("function pa_init(p) {"
15964 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15966 "function pa_load(p) {"
15968 " for (var i=0; i<256; ++i) {"
15973 "for (var i = 0; i < 5000; ++i) {"
15974 " pa_init(pixels);"
15976 "result = pa_load(pixels);"
15978 CHECK_EQ(32640, result->Int32Value());
15984 THREADED_TEST(PixelArrayInfo) {
15985 LocalContext context;
15986 v8::HandleScope scope(context->GetIsolate());
15987 for (int size = 0; size < 100; size += 10) {
15988 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15989 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15990 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15991 CHECK(obj->HasIndexedPropertiesInPixelData());
15992 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15993 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15999 static void NotHandledIndexedPropertyGetter(
16001 const v8::PropertyCallbackInfo<v8::Value>& info) {
16002 ApiTestFuzzer::Fuzz();
16006 static void NotHandledIndexedPropertySetter(
16008 Local<Value> value,
16009 const v8::PropertyCallbackInfo<v8::Value>& info) {
16010 ApiTestFuzzer::Fuzz();
16014 THREADED_TEST(PixelArrayWithInterceptor) {
16015 LocalContext context;
16016 i::Factory* factory = CcTest::i_isolate()->factory();
16017 v8::Isolate* isolate = context->GetIsolate();
16018 v8::HandleScope scope(isolate);
16019 const int kElementCount = 260;
16020 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16021 i::Handle<i::ExternalUint8ClampedArray> pixels =
16022 i::Handle<i::ExternalUint8ClampedArray>::cast(
16023 factory->NewExternalArray(kElementCount,
16024 v8::kExternalUint8ClampedArray,
16026 for (int i = 0; i < kElementCount; i++) {
16027 pixels->set(i, i % 256);
16029 v8::Handle<v8::ObjectTemplate> templ =
16030 v8::ObjectTemplate::New(context->GetIsolate());
16031 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16032 NotHandledIndexedPropertySetter);
16033 v8::Handle<v8::Object> obj = templ->NewInstance();
16034 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16035 context->Global()->Set(v8_str("pixels"), obj);
16036 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16037 CHECK_EQ(1, result->Int32Value());
16038 result = CompileRun("var sum = 0;"
16039 "for (var i = 0; i < 8; i++) {"
16040 " sum += pixels[i] = pixels[i] = -i;"
16043 CHECK_EQ(-28, result->Int32Value());
16044 result = CompileRun("pixels.hasOwnProperty('1')");
16045 CHECK(result->BooleanValue());
16050 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16051 switch (array_type) {
16052 case v8::kExternalInt8Array:
16053 case v8::kExternalUint8Array:
16054 case v8::kExternalUint8ClampedArray:
16057 case v8::kExternalInt16Array:
16058 case v8::kExternalUint16Array:
16061 case v8::kExternalInt32Array:
16062 case v8::kExternalUint32Array:
16063 case v8::kExternalFloat32Array:
16066 case v8::kExternalFloat64Array:
16078 template <class ExternalArrayClass, class ElementType>
16079 static void ObjectWithExternalArrayTestHelper(
16080 Handle<Context> context,
16081 v8::Handle<Object> obj,
16083 v8::ExternalArrayType array_type,
16084 int64_t low, int64_t high) {
16085 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16086 i::Isolate* isolate = jsobj->GetIsolate();
16087 obj->Set(v8_str("field"),
16088 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16089 context->Global()->Set(v8_str("ext_array"), obj);
16090 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16091 CHECK_EQ(1503, result->Int32Value());
16092 result = CompileRun("ext_array[1]");
16093 CHECK_EQ(1, result->Int32Value());
16095 // Check assigned smis
16096 result = CompileRun("for (var i = 0; i < 8; i++) {"
16097 " ext_array[i] = i;"
16100 "for (var i = 0; i < 8; i++) {"
16101 " sum += ext_array[i];"
16105 CHECK_EQ(28, result->Int32Value());
16106 // Check pass through of assigned smis
16107 result = CompileRun("var sum = 0;"
16108 "for (var i = 0; i < 8; i++) {"
16109 " sum += ext_array[i] = ext_array[i] = -i;"
16112 CHECK_EQ(-28, result->Int32Value());
16115 // Check assigned smis in reverse order
16116 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16117 " ext_array[i] = i;"
16120 "for (var i = 0; i < 8; i++) {"
16121 " sum += ext_array[i];"
16124 CHECK_EQ(28, result->Int32Value());
16126 // Check pass through of assigned HeapNumbers
16127 result = CompileRun("var sum = 0;"
16128 "for (var i = 0; i < 16; i+=2) {"
16129 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16132 CHECK_EQ(-28, result->Int32Value());
16134 // Check assigned HeapNumbers
16135 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16136 " ext_array[i] = (i * 0.5);"
16139 "for (var i = 0; i < 16; i+=2) {"
16140 " sum += ext_array[i];"
16143 CHECK_EQ(28, result->Int32Value());
16145 // Check assigned HeapNumbers in reverse order
16146 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16147 " ext_array[i] = (i * 0.5);"
16150 "for (var i = 0; i < 16; i+=2) {"
16151 " sum += ext_array[i];"
16154 CHECK_EQ(28, result->Int32Value());
16156 i::ScopedVector<char> test_buf(1024);
16158 // Check legal boundary conditions.
16159 // The repeated loads and stores ensure the ICs are exercised.
16160 const char* boundary_program =
16162 "for (var i = 0; i < 16; i++) {"
16163 " ext_array[i] = %lld;"
16165 " res = ext_array[i];"
16169 i::OS::SNPrintF(test_buf,
16172 result = CompileRun(test_buf.start());
16173 CHECK_EQ(low, result->IntegerValue());
16175 i::OS::SNPrintF(test_buf,
16178 result = CompileRun(test_buf.start());
16179 CHECK_EQ(high, result->IntegerValue());
16181 // Check misprediction of type in IC.
16182 result = CompileRun("var tmp_array = ext_array;"
16184 "for (var i = 0; i < 8; i++) {"
16185 " tmp_array[i] = i;"
16186 " sum += tmp_array[i];"
16192 // Force GC to trigger verification.
16193 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16194 CHECK_EQ(28, result->Int32Value());
16196 // Make sure out-of-range loads do not throw.
16197 i::OS::SNPrintF(test_buf,
16198 "var caught_exception = false;"
16202 " caught_exception = true;"
16204 "caught_exception;",
16206 result = CompileRun(test_buf.start());
16207 CHECK_EQ(false, result->BooleanValue());
16209 // Make sure out-of-range stores do not throw.
16210 i::OS::SNPrintF(test_buf,
16211 "var caught_exception = false;"
16213 " ext_array[%d] = 1;"
16215 " caught_exception = true;"
16217 "caught_exception;",
16219 result = CompileRun(test_buf.start());
16220 CHECK_EQ(false, result->BooleanValue());
16222 // Check other boundary conditions, values and operations.
16223 result = CompileRun("for (var i = 0; i < 8; i++) {"
16224 " ext_array[7] = undefined;"
16227 CHECK_EQ(0, result->Int32Value());
16228 if (array_type == v8::kExternalFloat64Array ||
16229 array_type == v8::kExternalFloat32Array) {
16230 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16232 jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
16234 CheckElementValue(isolate, 0, jsobj, 7);
16237 result = CompileRun("for (var i = 0; i < 8; i++) {"
16238 " ext_array[6] = '2.3';"
16241 CHECK_EQ(2, result->Int32Value());
16244 jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
16246 if (array_type != v8::kExternalFloat32Array &&
16247 array_type != v8::kExternalFloat64Array) {
16248 // Though the specification doesn't state it, be explicit about
16249 // converting NaNs and +/-Infinity to zero.
16250 result = CompileRun("for (var i = 0; i < 8; i++) {"
16251 " ext_array[i] = 5;"
16253 "for (var i = 0; i < 8; i++) {"
16254 " ext_array[i] = NaN;"
16257 CHECK_EQ(0, result->Int32Value());
16258 CheckElementValue(isolate, 0, jsobj, 5);
16260 result = CompileRun("for (var i = 0; i < 8; i++) {"
16261 " ext_array[i] = 5;"
16263 "for (var i = 0; i < 8; i++) {"
16264 " ext_array[i] = Infinity;"
16267 int expected_value =
16268 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16269 CHECK_EQ(expected_value, result->Int32Value());
16270 CheckElementValue(isolate, expected_value, jsobj, 5);
16272 result = CompileRun("for (var i = 0; i < 8; i++) {"
16273 " ext_array[i] = 5;"
16275 "for (var i = 0; i < 8; i++) {"
16276 " ext_array[i] = -Infinity;"
16279 CHECK_EQ(0, result->Int32Value());
16280 CheckElementValue(isolate, 0, jsobj, 5);
16282 // Check truncation behavior of integral arrays.
16283 const char* unsigned_data =
16284 "var source_data = [0.6, 10.6];"
16285 "var expected_results = [0, 10];";
16286 const char* signed_data =
16287 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16288 "var expected_results = [0, 10, 0, -10];";
16289 const char* pixel_data =
16290 "var source_data = [0.6, 10.6];"
16291 "var expected_results = [1, 11];";
16293 (array_type == v8::kExternalUint8Array ||
16294 array_type == v8::kExternalUint16Array ||
16295 array_type == v8::kExternalUint32Array);
16296 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16298 i::OS::SNPrintF(test_buf,
16300 "var all_passed = true;"
16301 "for (var i = 0; i < source_data.length; i++) {"
16302 " for (var j = 0; j < 8; j++) {"
16303 " ext_array[j] = source_data[i];"
16305 " all_passed = all_passed &&"
16306 " (ext_array[5] == expected_results[i]);"
16311 (is_pixel_data ? pixel_data : signed_data)));
16312 result = CompileRun(test_buf.start());
16313 CHECK_EQ(true, result->BooleanValue());
16316 i::Handle<ExternalArrayClass> array(
16317 ExternalArrayClass::cast(jsobj->elements()));
16318 for (int i = 0; i < element_count; i++) {
16319 array->set(i, static_cast<ElementType>(i));
16322 // Test complex assignments
16323 result = CompileRun("function ee_op_test_complex_func(sum) {"
16324 " for (var i = 0; i < 40; ++i) {"
16325 " sum += (ext_array[i] += 1);"
16326 " sum += (ext_array[i] -= 1);"
16331 "for (var i=0;i<10000;++i) {"
16332 " sum=ee_op_test_complex_func(sum);"
16335 CHECK_EQ(16000000, result->Int32Value());
16337 // Test count operations
16338 result = CompileRun("function ee_op_test_count_func(sum) {"
16339 " for (var i = 0; i < 40; ++i) {"
16340 " sum += (++ext_array[i]);"
16341 " sum += (--ext_array[i]);"
16346 "for (var i=0;i<10000;++i) {"
16347 " sum=ee_op_test_count_func(sum);"
16350 CHECK_EQ(16000000, result->Int32Value());
16352 result = CompileRun("ext_array[3] = 33;"
16353 "delete ext_array[3];"
16355 CHECK_EQ(33, result->Int32Value());
16357 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16358 "ext_array[2] = 12; ext_array[3] = 13;"
16359 "ext_array.__defineGetter__('2',"
16360 "function() { return 120; });"
16362 CHECK_EQ(12, result->Int32Value());
16364 result = CompileRun("var js_array = new Array(40);"
16365 "js_array[0] = 77;"
16367 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16369 result = CompileRun("ext_array[1] = 23;"
16370 "ext_array.__proto__ = [];"
16371 "js_array.__proto__ = ext_array;"
16372 "js_array.concat(ext_array);");
16373 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16374 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16376 result = CompileRun("ext_array[1] = 23;");
16377 CHECK_EQ(23, result->Int32Value());
16381 template <class FixedTypedArrayClass,
16382 i::ElementsKind elements_kind,
16384 static void FixedTypedArrayTestHelper(
16385 v8::ExternalArrayType array_type,
16387 ElementType high) {
16388 i::FLAG_allow_natives_syntax = true;
16389 LocalContext context;
16390 i::Isolate* isolate = CcTest::i_isolate();
16391 i::Factory* factory = isolate->factory();
16392 v8::HandleScope scope(context->GetIsolate());
16393 const int kElementCount = 260;
16394 i::Handle<FixedTypedArrayClass> fixed_array =
16395 i::Handle<FixedTypedArrayClass>::cast(
16396 factory->NewFixedTypedArray(kElementCount, array_type));
16397 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16398 fixed_array->map()->instance_type());
16399 CHECK_EQ(kElementCount, fixed_array->length());
16400 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16401 for (int i = 0; i < kElementCount; i++) {
16402 fixed_array->set(i, static_cast<ElementType>(i));
16404 // Force GC to trigger verification.
16405 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16406 for (int i = 0; i < kElementCount; i++) {
16407 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16408 static_cast<int64_t>(fixed_array->get_scalar(i)));
16410 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16411 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16412 i::Handle<i::Map> fixed_array_map =
16413 isolate->factory()->GetElementsTransitionMap(jsobj, elements_kind);
16414 jsobj->set_map(*fixed_array_map);
16415 jsobj->set_elements(*fixed_array);
16417 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16418 context.local(), obj, kElementCount, array_type,
16419 static_cast<int64_t>(low),
16420 static_cast<int64_t>(high));
16424 THREADED_TEST(FixedUint8Array) {
16425 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16426 v8::kExternalUint8Array,
16431 THREADED_TEST(FixedUint8ClampedArray) {
16432 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16433 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16434 v8::kExternalUint8ClampedArray,
16439 THREADED_TEST(FixedInt8Array) {
16440 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16441 v8::kExternalInt8Array,
16446 THREADED_TEST(FixedUint16Array) {
16447 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16448 v8::kExternalUint16Array,
16453 THREADED_TEST(FixedInt16Array) {
16454 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16455 v8::kExternalInt16Array,
16460 THREADED_TEST(FixedUint32Array) {
16461 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16462 v8::kExternalUint32Array,
16467 THREADED_TEST(FixedInt32Array) {
16468 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16469 v8::kExternalInt32Array,
16474 THREADED_TEST(FixedFloat32Array) {
16475 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16476 v8::kExternalFloat32Array,
16481 THREADED_TEST(FixedFloat64Array) {
16482 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16483 v8::kExternalFloat64Array,
16488 template <class ExternalArrayClass, class ElementType>
16489 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16492 LocalContext context;
16493 i::Isolate* isolate = CcTest::i_isolate();
16494 i::Factory* factory = isolate->factory();
16495 v8::HandleScope scope(context->GetIsolate());
16496 const int kElementCount = 40;
16497 int element_size = ExternalArrayElementSize(array_type);
16498 ElementType* array_data =
16499 static_cast<ElementType*>(malloc(kElementCount * element_size));
16500 i::Handle<ExternalArrayClass> array =
16501 i::Handle<ExternalArrayClass>::cast(
16502 factory->NewExternalArray(kElementCount, array_type, array_data));
16503 // Force GC to trigger verification.
16504 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16505 for (int i = 0; i < kElementCount; i++) {
16506 array->set(i, static_cast<ElementType>(i));
16508 // Force GC to trigger verification.
16509 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16510 for (int i = 0; i < kElementCount; i++) {
16511 CHECK_EQ(static_cast<int64_t>(i),
16512 static_cast<int64_t>(array->get_scalar(i)));
16513 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16516 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16517 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16518 // Set the elements to be the external array.
16519 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16524 jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
16526 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16527 context.local(), obj, kElementCount, array_type, low, high);
16529 v8::Handle<v8::Value> result;
16531 // Test more complex manipulations which cause eax to contain values
16532 // that won't be completely overwritten by loads from the arrays.
16533 // This catches bugs in the instructions used for the KeyedLoadIC
16534 // for byte and word types.
16536 const int kXSize = 300;
16537 const int kYSize = 300;
16538 const int kLargeElementCount = kXSize * kYSize * 4;
16539 ElementType* large_array_data =
16540 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16541 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16542 // Set the elements to be the external array.
16543 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16545 kLargeElementCount);
16546 context->Global()->Set(v8_str("large_array"), large_obj);
16547 // Initialize contents of a few rows.
16548 for (int x = 0; x < 300; x++) {
16550 int offset = row * 300 * 4;
16551 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16552 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16553 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16554 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16556 offset = row * 300 * 4;
16557 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16558 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16559 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16560 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16562 offset = row * 300 * 4;
16563 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16564 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16565 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16566 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16568 // The goal of the code below is to make "offset" large enough
16569 // that the computation of the index (which goes into eax) has
16570 // high bits set which will not be overwritten by a byte or short
16572 result = CompileRun("var failed = false;"
16574 "for (var i = 0; i < 300; i++) {"
16575 " if (large_array[4 * i] != 127 ||"
16576 " large_array[4 * i + 1] != 0 ||"
16577 " large_array[4 * i + 2] != 0 ||"
16578 " large_array[4 * i + 3] != 127) {"
16582 "offset = 150 * 300 * 4;"
16583 "for (var i = 0; i < 300; i++) {"
16584 " if (large_array[offset + 4 * i] != 127 ||"
16585 " large_array[offset + 4 * i + 1] != 0 ||"
16586 " large_array[offset + 4 * i + 2] != 0 ||"
16587 " large_array[offset + 4 * i + 3] != 127) {"
16591 "offset = 298 * 300 * 4;"
16592 "for (var i = 0; i < 300; i++) {"
16593 " if (large_array[offset + 4 * i] != 127 ||"
16594 " large_array[offset + 4 * i + 1] != 0 ||"
16595 " large_array[offset + 4 * i + 2] != 0 ||"
16596 " large_array[offset + 4 * i + 3] != 127) {"
16601 CHECK_EQ(true, result->BooleanValue());
16602 free(large_array_data);
16605 // The "" property descriptor is overloaded to store information about
16606 // the external array. Ensure that setting and accessing the "" property
16607 // works (it should overwrite the information cached about the external
16608 // array in the DescriptorArray) in various situations.
16609 result = CompileRun("ext_array[''] = 23; ext_array['']");
16610 CHECK_EQ(23, result->Int32Value());
16612 // Property "" set after the external array is associated with the object.
16614 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16615 obj2->Set(v8_str("ee_test_field"),
16616 v8::Int32::New(context->GetIsolate(), 256));
16617 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16618 // Set the elements to be the external array.
16619 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16622 context->Global()->Set(v8_str("ext_array"), obj2);
16623 result = CompileRun("ext_array['']");
16624 CHECK_EQ(1503, result->Int32Value());
16627 // Property "" set after the external array is associated with the object.
16629 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16630 obj2->Set(v8_str("ee_test_field_2"),
16631 v8::Int32::New(context->GetIsolate(), 256));
16632 // Set the elements to be the external array.
16633 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16636 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16637 context->Global()->Set(v8_str("ext_array"), obj2);
16638 result = CompileRun("ext_array['']");
16639 CHECK_EQ(1503, result->Int32Value());
16642 // Should reuse the map from previous test.
16644 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16645 obj2->Set(v8_str("ee_test_field_2"),
16646 v8::Int32::New(context->GetIsolate(), 256));
16647 // Set the elements to be the external array. Should re-use the map
16648 // from previous test.
16649 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16652 context->Global()->Set(v8_str("ext_array"), obj2);
16653 result = CompileRun("ext_array['']");
16656 // Property "" is a constant function that shouldn't not be interfered with
16657 // when an external array is set.
16659 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16661 obj2->Set(v8_str("ee_test_field3"),
16662 v8::Int32::New(context->GetIsolate(), 256));
16664 // Add a constant function to an object.
16665 context->Global()->Set(v8_str("ext_array"), obj2);
16666 result = CompileRun("ext_array[''] = function() {return 1503;};"
16667 "ext_array['']();");
16669 // Add an external array transition to the same map that
16670 // has the constant transition.
16671 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16672 obj3->Set(v8_str("ee_test_field3"),
16673 v8::Int32::New(context->GetIsolate(), 256));
16674 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16677 context->Global()->Set(v8_str("ext_array"), obj3);
16680 // If a external array transition is in the map, it should get clobbered
16681 // by a constant function.
16683 // Add an external array transition.
16684 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16685 obj3->Set(v8_str("ee_test_field4"),
16686 v8::Int32::New(context->GetIsolate(), 256));
16687 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16691 // Add a constant function to the same map that just got an external array
16693 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16694 obj2->Set(v8_str("ee_test_field4"),
16695 v8::Int32::New(context->GetIsolate(), 256));
16696 context->Global()->Set(v8_str("ext_array"), obj2);
16697 result = CompileRun("ext_array[''] = function() {return 1503;};"
16698 "ext_array['']();");
16705 THREADED_TEST(ExternalInt8Array) {
16706 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16707 v8::kExternalInt8Array,
16713 THREADED_TEST(ExternalUint8Array) {
16714 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16715 v8::kExternalUint8Array,
16721 THREADED_TEST(ExternalUint8ClampedArray) {
16722 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16723 v8::kExternalUint8ClampedArray,
16729 THREADED_TEST(ExternalInt16Array) {
16730 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16731 v8::kExternalInt16Array,
16737 THREADED_TEST(ExternalUint16Array) {
16738 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16739 v8::kExternalUint16Array,
16745 THREADED_TEST(ExternalInt32Array) {
16746 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16747 v8::kExternalInt32Array,
16748 INT_MIN, // -2147483648
16749 INT_MAX); // 2147483647
16753 THREADED_TEST(ExternalUint32Array) {
16754 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16755 v8::kExternalUint32Array,
16757 UINT_MAX); // 4294967295
16761 THREADED_TEST(ExternalFloat32Array) {
16762 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16763 v8::kExternalFloat32Array,
16769 THREADED_TEST(ExternalFloat64Array) {
16770 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16771 v8::kExternalFloat64Array,
16777 THREADED_TEST(ExternalArrays) {
16778 TestExternalInt8Array();
16779 TestExternalUint8Array();
16780 TestExternalInt16Array();
16781 TestExternalUint16Array();
16782 TestExternalInt32Array();
16783 TestExternalUint32Array();
16784 TestExternalFloat32Array();
16788 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16789 LocalContext context;
16790 v8::HandleScope scope(context->GetIsolate());
16791 for (int size = 0; size < 100; size += 10) {
16792 int element_size = ExternalArrayElementSize(array_type);
16793 void* external_data = malloc(size * element_size);
16794 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16795 obj->SetIndexedPropertiesToExternalArrayData(
16796 external_data, array_type, size);
16797 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16798 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16799 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16800 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16801 free(external_data);
16806 THREADED_TEST(ExternalArrayInfo) {
16807 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16808 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16809 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16810 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16811 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16812 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16813 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16814 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16815 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16819 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16820 v8::ExternalArrayType array_type,
16822 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16823 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16824 last_location = last_message = NULL;
16825 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16826 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16827 CHECK_NE(NULL, last_location);
16828 CHECK_NE(NULL, last_message);
16832 TEST(ExternalArrayLimits) {
16833 LocalContext context;
16834 v8::Isolate* isolate = context->GetIsolate();
16835 v8::HandleScope scope(isolate);
16836 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16837 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16838 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16839 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16840 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16841 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16842 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16843 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16844 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16845 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16846 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16847 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16848 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16849 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16850 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16851 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16852 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16853 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16857 template <typename ElementType, typename TypedArray,
16858 class ExternalArrayClass>
16859 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16860 int64_t low, int64_t high) {
16861 const int kElementCount = 50;
16863 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16866 v8::Isolate* isolate = env->GetIsolate();
16867 v8::HandleScope handle_scope(isolate);
16869 Local<v8::ArrayBuffer> ab =
16870 v8::ArrayBuffer::New(isolate, backing_store.start(),
16871 (kElementCount + 2) * sizeof(ElementType));
16872 Local<TypedArray> ta =
16873 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16874 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16875 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16876 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16877 CHECK_EQ(kElementCount*sizeof(ElementType),
16878 static_cast<int>(ta->ByteLength()));
16879 CHECK_EQ(ab, ta->Buffer());
16881 ElementType* data = backing_store.start() + 2;
16882 for (int i = 0; i < kElementCount; i++) {
16883 data[i] = static_cast<ElementType>(i);
16886 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16887 env.local(), ta, kElementCount, array_type, low, high);
16891 THREADED_TEST(Uint8Array) {
16892 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16893 v8::kExternalUint8Array, 0, 0xFF);
16897 THREADED_TEST(Int8Array) {
16898 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16899 v8::kExternalInt8Array, -0x80, 0x7F);
16903 THREADED_TEST(Uint16Array) {
16904 TypedArrayTestHelper<uint16_t,
16906 i::ExternalUint16Array>(
16907 v8::kExternalUint16Array, 0, 0xFFFF);
16911 THREADED_TEST(Int16Array) {
16912 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16913 v8::kExternalInt16Array, -0x8000, 0x7FFF);
16917 THREADED_TEST(Uint32Array) {
16918 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16919 v8::kExternalUint32Array, 0, UINT_MAX);
16923 THREADED_TEST(Int32Array) {
16924 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16925 v8::kExternalInt32Array, INT_MIN, INT_MAX);
16929 THREADED_TEST(Float32Array) {
16930 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16931 v8::kExternalFloat32Array, -500, 500);
16935 THREADED_TEST(Float64Array) {
16936 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16937 v8::kExternalFloat64Array, -500, 500);
16941 THREADED_TEST(Uint8ClampedArray) {
16942 TypedArrayTestHelper<uint8_t,
16943 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16944 v8::kExternalUint8ClampedArray, 0, 0xFF);
16948 THREADED_TEST(DataView) {
16949 const int kSize = 50;
16951 i::ScopedVector<uint8_t> backing_store(kSize+2);
16954 v8::Isolate* isolate = env->GetIsolate();
16955 v8::HandleScope handle_scope(isolate);
16957 Local<v8::ArrayBuffer> ab =
16958 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16959 Local<v8::DataView> dv =
16960 v8::DataView::New(ab, 2, kSize);
16961 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16962 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16963 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16964 CHECK_EQ(ab, dv->Buffer());
16968 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16969 THREADED_TEST(Is##View) { \
16970 LocalContext env; \
16971 v8::Isolate* isolate = env->GetIsolate(); \
16972 v8::HandleScope handle_scope(isolate); \
16974 Handle<Value> result = CompileRun( \
16975 "var ab = new ArrayBuffer(128);" \
16976 "new " #View "(ab)"); \
16977 CHECK(result->IsArrayBufferView()); \
16978 CHECK(result->Is##View()); \
16979 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16982 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16983 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16984 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16985 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16986 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16987 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16988 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16989 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16990 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16991 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16993 #undef IS_ARRAY_BUFFER_VIEW_TEST
16997 THREADED_TEST(ScriptContextDependence) {
16999 v8::HandleScope scope(c1->GetIsolate());
17000 const char *source = "foo";
17001 v8::Handle<v8::Script> dep =
17002 v8::Script::Compile(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17003 v8::Handle<v8::Script> indep =
17004 v8::Script::New(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17005 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17006 v8::Integer::New(c1->GetIsolate(), 100));
17007 CHECK_EQ(dep->Run()->Int32Value(), 100);
17008 CHECK_EQ(indep->Run()->Int32Value(), 100);
17010 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17011 v8::Integer::New(c2->GetIsolate(), 101));
17012 CHECK_EQ(dep->Run()->Int32Value(), 100);
17013 CHECK_EQ(indep->Run()->Int32Value(), 101);
17017 THREADED_TEST(StackTrace) {
17018 LocalContext context;
17019 v8::HandleScope scope(context->GetIsolate());
17020 v8::TryCatch try_catch;
17021 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17022 v8::Handle<v8::String> src =
17023 v8::String::NewFromUtf8(context->GetIsolate(), source);
17024 v8::Handle<v8::String> origin =
17025 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17026 v8::Script::New(src, origin)->Run();
17027 CHECK(try_catch.HasCaught());
17028 v8::String::Utf8Value stack(try_catch.StackTrace());
17029 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17033 // Checks that a StackFrame has certain expected values.
17034 void checkStackFrame(const char* expected_script_name,
17035 const char* expected_func_name, int expected_line_number,
17036 int expected_column, bool is_eval, bool is_constructor,
17037 v8::Handle<v8::StackFrame> frame) {
17038 v8::HandleScope scope(CcTest::isolate());
17039 v8::String::Utf8Value func_name(frame->GetFunctionName());
17040 v8::String::Utf8Value script_name(frame->GetScriptName());
17041 if (*script_name == NULL) {
17042 // The situation where there is no associated script, like for evals.
17043 CHECK(expected_script_name == NULL);
17045 CHECK(strstr(*script_name, expected_script_name) != NULL);
17047 CHECK(strstr(*func_name, expected_func_name) != NULL);
17048 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17049 CHECK_EQ(expected_column, frame->GetColumn());
17050 CHECK_EQ(is_eval, frame->IsEval());
17051 CHECK_EQ(is_constructor, frame->IsConstructor());
17055 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17056 v8::HandleScope scope(args.GetIsolate());
17057 const char* origin = "capture-stack-trace-test";
17058 const int kOverviewTest = 1;
17059 const int kDetailedTest = 2;
17061 ASSERT(args.Length() == 1);
17063 int testGroup = args[0]->Int32Value();
17064 if (testGroup == kOverviewTest) {
17065 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17066 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17067 CHECK_EQ(4, stackTrace->GetFrameCount());
17068 checkStackFrame(origin, "bar", 2, 10, false, false,
17069 stackTrace->GetFrame(0));
17070 checkStackFrame(origin, "foo", 6, 3, false, false,
17071 stackTrace->GetFrame(1));
17072 // This is the source string inside the eval which has the call to foo.
17073 checkStackFrame(NULL, "", 1, 5, false, false,
17074 stackTrace->GetFrame(2));
17075 // The last frame is an anonymous function which has the initial eval call.
17076 checkStackFrame(origin, "", 8, 7, false, false,
17077 stackTrace->GetFrame(3));
17079 CHECK(stackTrace->AsArray()->IsArray());
17080 } else if (testGroup == kDetailedTest) {
17081 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17082 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17083 CHECK_EQ(4, stackTrace->GetFrameCount());
17084 checkStackFrame(origin, "bat", 4, 22, false, false,
17085 stackTrace->GetFrame(0));
17086 checkStackFrame(origin, "baz", 8, 3, false, true,
17087 stackTrace->GetFrame(1));
17088 #ifdef ENABLE_DEBUGGER_SUPPORT
17089 bool is_eval = true;
17090 #else // ENABLE_DEBUGGER_SUPPORT
17091 bool is_eval = false;
17092 #endif // ENABLE_DEBUGGER_SUPPORT
17094 // This is the source string inside the eval which has the call to baz.
17095 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17096 stackTrace->GetFrame(2));
17097 // The last frame is an anonymous function which has the initial eval call.
17098 checkStackFrame(origin, "", 10, 1, false, false,
17099 stackTrace->GetFrame(3));
17101 CHECK(stackTrace->AsArray()->IsArray());
17106 // Tests the C++ StackTrace API.
17107 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17108 // THREADED_TEST(CaptureStackTrace) {
17109 TEST(CaptureStackTrace) {
17110 v8::Isolate* isolate = CcTest::isolate();
17111 v8::HandleScope scope(isolate);
17112 v8::Handle<v8::String> origin =
17113 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17114 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17115 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17116 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17117 LocalContext context(0, templ);
17119 // Test getting OVERVIEW information. Should ignore information that is not
17120 // script name, function name, line number, and column offset.
17121 const char *overview_source =
17122 "function bar() {\n"
17123 " var y; AnalyzeStackInNativeCode(1);\n"
17125 "function foo() {\n"
17129 "var x;eval('new foo();');";
17130 v8::Handle<v8::String> overview_src =
17131 v8::String::NewFromUtf8(isolate, overview_source);
17132 v8::Handle<Value> overview_result(
17133 v8::Script::New(overview_src, origin)->Run());
17134 CHECK(!overview_result.IsEmpty());
17135 CHECK(overview_result->IsObject());
17137 // Test getting DETAILED information.
17138 const char *detailed_source =
17139 "function bat() {AnalyzeStackInNativeCode(2);\n"
17142 "function baz() {\n"
17145 "eval('new baz();');";
17146 v8::Handle<v8::String> detailed_src =
17147 v8::String::NewFromUtf8(isolate, detailed_source);
17148 // Make the script using a non-zero line and column offset.
17149 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17150 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17151 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17152 v8::Handle<v8::Script> detailed_script(
17153 v8::Script::New(detailed_src, &detailed_origin));
17154 v8::Handle<Value> detailed_result(detailed_script->Run());
17155 CHECK(!detailed_result.IsEmpty());
17156 CHECK(detailed_result->IsObject());
17160 static void StackTraceForUncaughtExceptionListener(
17161 v8::Handle<v8::Message> message,
17162 v8::Handle<Value>) {
17163 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17164 CHECK_EQ(2, stack_trace->GetFrameCount());
17165 checkStackFrame("origin", "foo", 2, 3, false, false,
17166 stack_trace->GetFrame(0));
17167 checkStackFrame("origin", "bar", 5, 3, false, false,
17168 stack_trace->GetFrame(1));
17172 TEST(CaptureStackTraceForUncaughtException) {
17175 v8::HandleScope scope(env->GetIsolate());
17176 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17177 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17179 Script::Compile(v8_str("function foo() {\n"
17182 "function bar() {\n"
17185 v8_str("origin"))->Run();
17186 v8::Local<v8::Object> global = env->Global();
17187 Local<Value> trouble = global->Get(v8_str("bar"));
17188 CHECK(trouble->IsFunction());
17189 Function::Cast(*trouble)->Call(global, 0, NULL);
17190 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17191 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17195 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17197 v8::HandleScope scope(env->GetIsolate());
17198 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17200 v8::StackTrace::kDetailed);
17203 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17204 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17205 " 'isConstructor'];\n"
17206 "for (var i = 0; i < setters.length; i++) {\n"
17207 " var prop = setters[i];\n"
17208 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17210 CompileRun("throw 'exception';");
17211 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17215 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17216 v8::Handle<v8::Value> data) {
17217 // Use the frame where JavaScript is called from.
17218 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17219 CHECK(!stack_trace.IsEmpty());
17220 int frame_count = stack_trace->GetFrameCount();
17221 CHECK_EQ(3, frame_count);
17222 int line_number[] = {1, 2, 5};
17223 for (int i = 0; i < frame_count; i++) {
17224 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17229 // Test that we only return the stack trace at the site where the exception
17230 // is first thrown (not where it is rethrown).
17231 TEST(RethrowStackTrace) {
17233 v8::HandleScope scope(env->GetIsolate());
17234 // We make sure that
17235 // - the stack trace of the ReferenceError in g() is reported.
17236 // - the stack trace is not overwritten when e1 is rethrown by t().
17237 // - the stack trace of e2 does not overwrite that of e1.
17238 const char* source =
17239 "function g() { error; } \n"
17240 "function f() { g(); } \n"
17241 "function t(e) { throw e; } \n"
17244 "} catch (e1) { \n"
17247 " } catch (e2) { \n"
17251 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17252 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17253 CompileRun(source);
17254 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17255 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17259 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17260 v8::Handle<v8::Value> data) {
17261 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17262 CHECK(!stack_trace.IsEmpty());
17263 int frame_count = stack_trace->GetFrameCount();
17264 CHECK_EQ(2, frame_count);
17265 int line_number[] = {3, 7};
17266 for (int i = 0; i < frame_count; i++) {
17267 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17272 // Test that we do not recognize identity for primitive exceptions.
17273 TEST(RethrowPrimitiveStackTrace) {
17275 v8::HandleScope scope(env->GetIsolate());
17276 // We do not capture stack trace for non Error objects on creation time.
17277 // Instead, we capture the stack trace on last throw.
17278 const char* source =
17279 "function g() { throw 404; } \n"
17280 "function f() { g(); } \n"
17281 "function t(e) { throw e; } \n"
17284 "} catch (e1) { \n"
17287 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17288 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17289 CompileRun(source);
17290 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17291 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17295 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17296 v8::Handle<v8::Value> data) {
17297 // Use the frame where JavaScript is called from.
17298 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17299 CHECK(!stack_trace.IsEmpty());
17300 CHECK_EQ(1, stack_trace->GetFrameCount());
17301 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17305 // Test that the stack trace is captured when the error object is created and
17306 // not where it is thrown.
17307 TEST(RethrowExistingStackTrace) {
17309 v8::HandleScope scope(env->GetIsolate());
17310 const char* source =
17311 "var e = new Error(); \n"
17313 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17314 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17315 CompileRun(source);
17316 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17317 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17321 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17322 v8::Handle<v8::Value> data) {
17323 // Use the frame where JavaScript is called from.
17324 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17325 CHECK(!stack_trace.IsEmpty());
17326 CHECK_EQ(1, stack_trace->GetFrameCount());
17327 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17331 // Test that the stack trace is captured where the bogus Error object is thrown.
17332 TEST(RethrowBogusErrorStackTrace) {
17334 v8::HandleScope scope(env->GetIsolate());
17335 const char* source =
17336 "var e = {__proto__: new Error()} \n"
17338 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17339 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17340 CompileRun(source);
17341 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17342 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17346 void AnalyzeStackOfEvalWithSourceURL(
17347 const v8::FunctionCallbackInfo<v8::Value>& args) {
17348 v8::HandleScope scope(args.GetIsolate());
17349 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17350 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17351 CHECK_EQ(5, stackTrace->GetFrameCount());
17352 v8::Handle<v8::String> url = v8_str("eval_url");
17353 for (int i = 0; i < 3; i++) {
17354 v8::Handle<v8::String> name =
17355 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17356 CHECK(!name.IsEmpty());
17357 CHECK_EQ(url, name);
17362 TEST(SourceURLInStackTrace) {
17363 v8::Isolate* isolate = CcTest::isolate();
17364 v8::HandleScope scope(isolate);
17365 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17366 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17367 v8::FunctionTemplate::New(isolate,
17368 AnalyzeStackOfEvalWithSourceURL));
17369 LocalContext context(0, templ);
17371 const char *source =
17372 "function outer() {\n"
17373 "function bar() {\n"
17374 " AnalyzeStackOfEvalWithSourceURL();\n"
17376 "function foo() {\n"
17382 "eval('(' + outer +')()%s');";
17384 i::ScopedVector<char> code(1024);
17385 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17386 CHECK(CompileRun(code.start())->IsUndefined());
17387 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17388 CHECK(CompileRun(code.start())->IsUndefined());
17392 static int scriptIdInStack[2];
17394 void AnalyzeScriptIdInStack(
17395 const v8::FunctionCallbackInfo<v8::Value>& args) {
17396 v8::HandleScope scope(args.GetIsolate());
17397 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17398 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17399 CHECK_EQ(2, stackTrace->GetFrameCount());
17400 for (int i = 0; i < 2; i++) {
17401 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17406 TEST(ScriptIdInStackTrace) {
17407 v8::Isolate* isolate = CcTest::isolate();
17408 v8::HandleScope scope(isolate);
17409 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17410 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17411 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17412 LocalContext context(0, templ);
17414 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17416 "function foo() {\n"
17417 " AnalyzeScriptIdInStack();"
17420 v8::ScriptOrigin origin =
17421 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"));
17422 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17424 for (int i = 0; i < 2; i++) {
17425 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17426 CHECK_EQ(scriptIdInStack[i], script->GetId());
17431 void AnalyzeStackOfInlineScriptWithSourceURL(
17432 const v8::FunctionCallbackInfo<v8::Value>& args) {
17433 v8::HandleScope scope(args.GetIsolate());
17434 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17435 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17436 CHECK_EQ(4, stackTrace->GetFrameCount());
17437 v8::Handle<v8::String> url = v8_str("url");
17438 for (int i = 0; i < 3; i++) {
17439 v8::Handle<v8::String> name =
17440 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17441 CHECK(!name.IsEmpty());
17442 CHECK_EQ(url, name);
17447 TEST(InlineScriptWithSourceURLInStackTrace) {
17448 v8::Isolate* isolate = CcTest::isolate();
17449 v8::HandleScope scope(isolate);
17450 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17451 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17452 v8::FunctionTemplate::New(
17453 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17454 LocalContext context(0, templ);
17456 const char *source =
17457 "function outer() {\n"
17458 "function bar() {\n"
17459 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17461 "function foo() {\n"
17469 i::ScopedVector<char> code(1024);
17470 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17471 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17472 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17473 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17477 void AnalyzeStackOfDynamicScriptWithSourceURL(
17478 const v8::FunctionCallbackInfo<v8::Value>& args) {
17479 v8::HandleScope scope(args.GetIsolate());
17480 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17481 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17482 CHECK_EQ(4, stackTrace->GetFrameCount());
17483 v8::Handle<v8::String> url = v8_str("source_url");
17484 for (int i = 0; i < 3; i++) {
17485 v8::Handle<v8::String> name =
17486 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17487 CHECK(!name.IsEmpty());
17488 CHECK_EQ(url, name);
17493 TEST(DynamicWithSourceURLInStackTrace) {
17494 v8::Isolate* isolate = CcTest::isolate();
17495 v8::HandleScope scope(isolate);
17496 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17497 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17498 v8::FunctionTemplate::New(
17499 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17500 LocalContext context(0, templ);
17502 const char *source =
17503 "function outer() {\n"
17504 "function bar() {\n"
17505 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17507 "function foo() {\n"
17515 i::ScopedVector<char> code(1024);
17516 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17517 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17518 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17519 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17523 static void CreateGarbageInOldSpace() {
17524 i::Factory* factory = CcTest::i_isolate()->factory();
17525 v8::HandleScope scope(CcTest::isolate());
17526 i::AlwaysAllocateScope always_allocate;
17527 for (int i = 0; i < 1000; i++) {
17528 factory->NewFixedArray(1000, i::TENURED);
17533 // Test that idle notification can be handled and eventually returns true.
17534 TEST(IdleNotification) {
17535 const intptr_t MB = 1024 * 1024;
17537 v8::HandleScope scope(env->GetIsolate());
17538 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17539 CreateGarbageInOldSpace();
17540 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17541 CHECK_GT(size_with_garbage, initial_size + MB);
17542 bool finished = false;
17543 for (int i = 0; i < 200 && !finished; i++) {
17544 finished = v8::V8::IdleNotification();
17546 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17548 CHECK_LT(final_size, initial_size + 1);
17552 // Test that idle notification can be handled and eventually collects garbage.
17553 TEST(IdleNotificationWithSmallHint) {
17554 const intptr_t MB = 1024 * 1024;
17555 const int IdlePauseInMs = 900;
17557 v8::HandleScope scope(env->GetIsolate());
17558 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17559 CreateGarbageInOldSpace();
17560 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17561 CHECK_GT(size_with_garbage, initial_size + MB);
17562 bool finished = false;
17563 for (int i = 0; i < 200 && !finished; i++) {
17564 finished = v8::V8::IdleNotification(IdlePauseInMs);
17566 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17568 CHECK_LT(final_size, initial_size + 1);
17572 // Test that idle notification can be handled and eventually collects garbage.
17573 TEST(IdleNotificationWithLargeHint) {
17574 const intptr_t MB = 1024 * 1024;
17575 const int IdlePauseInMs = 900;
17577 v8::HandleScope scope(env->GetIsolate());
17578 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17579 CreateGarbageInOldSpace();
17580 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17581 CHECK_GT(size_with_garbage, initial_size + MB);
17582 bool finished = false;
17583 for (int i = 0; i < 200 && !finished; i++) {
17584 finished = v8::V8::IdleNotification(IdlePauseInMs);
17586 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17588 CHECK_LT(final_size, initial_size + 1);
17592 TEST(Regress2107) {
17593 const intptr_t MB = 1024 * 1024;
17594 const int kShortIdlePauseInMs = 100;
17595 const int kLongIdlePauseInMs = 1000;
17597 v8::Isolate* isolate = env->GetIsolate();
17598 v8::HandleScope scope(env->GetIsolate());
17599 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17600 // Send idle notification to start a round of incremental GCs.
17601 v8::V8::IdleNotification(kShortIdlePauseInMs);
17602 // Emulate 7 page reloads.
17603 for (int i = 0; i < 7; i++) {
17605 v8::HandleScope inner_scope(env->GetIsolate());
17606 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17608 CreateGarbageInOldSpace();
17611 v8::V8::ContextDisposedNotification();
17612 v8::V8::IdleNotification(kLongIdlePauseInMs);
17614 // Create garbage and check that idle notification still collects it.
17615 CreateGarbageInOldSpace();
17616 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17617 CHECK_GT(size_with_garbage, initial_size + MB);
17618 bool finished = false;
17619 for (int i = 0; i < 200 && !finished; i++) {
17620 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17622 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17623 CHECK_LT(final_size, initial_size + 1);
17627 TEST(Regress2333) {
17629 for (int i = 0; i < 3; i++) {
17630 CcTest::heap()->PerformScavenge();
17634 static uint32_t* stack_limit;
17636 static void GetStackLimitCallback(
17637 const v8::FunctionCallbackInfo<v8::Value>& args) {
17638 stack_limit = reinterpret_cast<uint32_t*>(
17639 CcTest::i_isolate()->stack_guard()->real_climit());
17643 // Uses the address of a local variable to determine the stack top now.
17644 // Given a size, returns an address that is that far from the current
17646 static uint32_t* ComputeStackLimit(uint32_t size) {
17647 uint32_t* answer = &size - (size / sizeof(size));
17648 // If the size is very large and the stack is very near the bottom of
17649 // memory then the calculation above may wrap around and give an address
17650 // that is above the (downwards-growing) stack. In that case we return
17651 // a very low address.
17652 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17657 // We need at least 165kB for an x64 debug build with clang and ASAN.
17658 static const int stack_breathing_room = 256 * i::KB;
17661 TEST(SetResourceConstraints) {
17662 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17664 // Set stack limit.
17665 v8::ResourceConstraints constraints;
17666 constraints.set_stack_limit(set_limit);
17667 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17669 // Execute a script.
17671 v8::HandleScope scope(env->GetIsolate());
17672 Local<v8::FunctionTemplate> fun_templ =
17673 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17674 Local<Function> fun = fun_templ->GetFunction();
17675 env->Global()->Set(v8_str("get_stack_limit"), fun);
17676 CompileRun("get_stack_limit();");
17678 CHECK(stack_limit == set_limit);
17682 TEST(SetResourceConstraintsInThread) {
17683 uint32_t* set_limit;
17685 v8::Locker locker(CcTest::isolate());
17686 set_limit = ComputeStackLimit(stack_breathing_room);
17688 // Set stack limit.
17689 v8::ResourceConstraints constraints;
17690 constraints.set_stack_limit(set_limit);
17691 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17693 // Execute a script.
17694 v8::HandleScope scope(CcTest::isolate());
17696 Local<v8::FunctionTemplate> fun_templ =
17697 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17698 Local<Function> fun = fun_templ->GetFunction();
17699 env->Global()->Set(v8_str("get_stack_limit"), fun);
17700 CompileRun("get_stack_limit();");
17702 CHECK(stack_limit == set_limit);
17705 v8::Locker locker(CcTest::isolate());
17706 CHECK(stack_limit == set_limit);
17711 THREADED_TEST(GetHeapStatistics) {
17713 v8::HandleScope scope(c1->GetIsolate());
17714 v8::HeapStatistics heap_statistics;
17715 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17716 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17717 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17718 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17719 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17723 class VisitorImpl : public v8::ExternalResourceVisitor {
17725 explicit VisitorImpl(TestResource** resource) {
17726 for (int i = 0; i < 4; i++) {
17727 resource_[i] = resource[i];
17728 found_resource_[i] = false;
17731 virtual ~VisitorImpl() {}
17732 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17733 if (!string->IsExternal()) {
17734 CHECK(string->IsExternalAscii());
17737 v8::String::ExternalStringResource* resource =
17738 string->GetExternalStringResource();
17740 for (int i = 0; i < 4; i++) {
17741 if (resource_[i] == resource) {
17742 CHECK(!found_resource_[i]);
17743 found_resource_[i] = true;
17747 void CheckVisitedResources() {
17748 for (int i = 0; i < 4; i++) {
17749 CHECK(found_resource_[i]);
17754 v8::String::ExternalStringResource* resource_[4];
17755 bool found_resource_[4];
17759 TEST(ExternalizeOldSpaceTwoByteCons) {
17761 v8::HandleScope scope(env->GetIsolate());
17762 v8::Local<v8::String> cons =
17763 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17764 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17765 CcTest::heap()->CollectAllAvailableGarbage();
17766 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17767 *v8::Utils::OpenHandle(*cons)));
17769 TestResource* resource = new TestResource(
17770 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17771 cons->MakeExternal(resource);
17773 CHECK(cons->IsExternal());
17774 CHECK_EQ(resource, cons->GetExternalStringResource());
17775 String::Encoding encoding;
17776 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17777 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17781 TEST(ExternalizeOldSpaceOneByteCons) {
17783 v8::HandleScope scope(env->GetIsolate());
17784 v8::Local<v8::String> cons =
17785 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17786 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17787 CcTest::heap()->CollectAllAvailableGarbage();
17788 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17789 *v8::Utils::OpenHandle(*cons)));
17791 TestAsciiResource* resource =
17792 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17793 cons->MakeExternal(resource);
17795 CHECK(cons->IsExternalAscii());
17796 CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17797 String::Encoding encoding;
17798 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17799 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17803 TEST(VisitExternalStrings) {
17805 v8::HandleScope scope(env->GetIsolate());
17806 const char* string = "Some string";
17807 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17808 TestResource* resource[4];
17809 resource[0] = new TestResource(two_byte_string);
17810 v8::Local<v8::String> string0 =
17811 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17812 resource[1] = new TestResource(two_byte_string, NULL, false);
17813 v8::Local<v8::String> string1 =
17814 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17816 // Externalized symbol.
17817 resource[2] = new TestResource(two_byte_string, NULL, false);
17818 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17819 env->GetIsolate(), string, v8::String::kInternalizedString);
17820 CHECK(string2->MakeExternal(resource[2]));
17822 // Symbolized External.
17823 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17824 v8::Local<v8::String> string3 =
17825 v8::String::NewExternal(env->GetIsolate(), resource[3]);
17826 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17827 // Turn into a symbol.
17828 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17829 CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17830 CHECK(string3_i->IsInternalizedString());
17832 // We need to add usages for string* to avoid warnings in GCC 4.7
17833 CHECK(string0->IsExternal());
17834 CHECK(string1->IsExternal());
17835 CHECK(string2->IsExternal());
17836 CHECK(string3->IsExternal());
17838 VisitorImpl visitor(resource);
17839 v8::V8::VisitExternalResources(&visitor);
17840 visitor.CheckVisitedResources();
17844 TEST(ExternalStringCollectedAtTearDown) {
17846 v8::Isolate* isolate = v8::Isolate::New();
17847 { v8::Isolate::Scope isolate_scope(isolate);
17848 v8::HandleScope handle_scope(isolate);
17849 const char* s = "One string to test them all, one string to find them.";
17850 TestAsciiResource* inscription =
17851 new TestAsciiResource(i::StrDup(s), &destroyed);
17852 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17853 // Ring is still alive. Orcs are roaming freely across our lands.
17854 CHECK_EQ(0, destroyed);
17858 isolate->Dispose();
17859 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17860 CHECK_EQ(1, destroyed);
17864 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17866 v8::Isolate* isolate = v8::Isolate::New();
17867 { v8::Isolate::Scope isolate_scope(isolate);
17868 LocalContext env(isolate);
17869 v8::HandleScope handle_scope(isolate);
17870 CompileRun("var ring = 'One string to test them all';");
17871 const char* s = "One string to test them all";
17872 TestAsciiResource* inscription =
17873 new TestAsciiResource(i::StrDup(s), &destroyed);
17874 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17875 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17876 ring->MakeExternal(inscription);
17877 // Ring is still alive. Orcs are roaming freely across our lands.
17878 CHECK_EQ(0, destroyed);
17882 isolate->Dispose();
17883 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17884 CHECK_EQ(1, destroyed);
17888 TEST(ExternalInternalizedStringCollectedAtGC) {
17890 { LocalContext env;
17891 v8::HandleScope handle_scope(env->GetIsolate());
17892 CompileRun("var ring = 'One string to test them all';");
17893 const char* s = "One string to test them all";
17894 TestAsciiResource* inscription =
17895 new TestAsciiResource(i::StrDup(s), &destroyed);
17896 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17897 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17898 ring->MakeExternal(inscription);
17899 // Ring is still alive. Orcs are roaming freely across our lands.
17900 CHECK_EQ(0, destroyed);
17904 // Garbage collector deals swift blows to evil.
17905 CcTest::i_isolate()->compilation_cache()->Clear();
17906 CcTest::heap()->CollectAllAvailableGarbage();
17908 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17909 CHECK_EQ(1, destroyed);
17913 static double DoubleFromBits(uint64_t value) {
17915 i::OS::MemCopy(&target, &value, sizeof(target));
17920 static uint64_t DoubleToBits(double value) {
17922 i::OS::MemCopy(&target, &value, sizeof(target));
17927 static double DoubleToDateTime(double input) {
17928 double date_limit = 864e13;
17929 if (std::isnan(input) || input < -date_limit || input > date_limit) {
17930 return i::OS::nan_value();
17932 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17936 // We don't have a consistent way to write 64-bit constants syntactically, so we
17937 // split them into two 32-bit constants and combine them programmatically.
17938 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17939 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17943 THREADED_TEST(QuietSignalingNaNs) {
17944 LocalContext context;
17945 v8::Isolate* isolate = context->GetIsolate();
17946 v8::HandleScope scope(isolate);
17947 v8::TryCatch try_catch;
17949 // Special double values.
17950 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17951 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17952 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17953 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
17954 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
17955 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
17956 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
17958 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
17959 // on either side of the epoch.
17960 double date_limit = 864e13;
17962 double test_values[] = {
17984 int num_test_values = 20;
17986 for (int i = 0; i < num_test_values; i++) {
17987 double test_value = test_values[i];
17989 // Check that Number::New preserves non-NaNs and quiets SNaNs.
17990 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
17991 double stored_number = number->NumberValue();
17992 if (!std::isnan(test_value)) {
17993 CHECK_EQ(test_value, stored_number);
17995 uint64_t stored_bits = DoubleToBits(stored_number);
17996 // Check if quiet nan (bits 51..62 all set).
17997 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17998 // Most significant fraction bit for quiet nan is set to 0
17999 // on MIPS architecture. Allowed by IEEE-754.
18000 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18002 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18006 // Check that Date::New preserves non-NaNs in the date range and
18008 v8::Handle<v8::Value> date =
18009 v8::Date::New(isolate, test_value);
18010 double expected_stored_date = DoubleToDateTime(test_value);
18011 double stored_date = date->NumberValue();
18012 if (!std::isnan(expected_stored_date)) {
18013 CHECK_EQ(expected_stored_date, stored_date);
18015 uint64_t stored_bits = DoubleToBits(stored_date);
18016 // Check if quiet nan (bits 51..62 all set).
18017 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18018 // Most significant fraction bit for quiet nan is set to 0
18019 // on MIPS architecture. Allowed by IEEE-754.
18020 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18022 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18029 static void SpaghettiIncident(
18030 const v8::FunctionCallbackInfo<v8::Value>& args) {
18031 v8::HandleScope scope(args.GetIsolate());
18033 v8::Handle<v8::String> str(args[0]->ToString());
18035 if (tc.HasCaught())
18040 // Test that an exception can be propagated down through a spaghetti
18041 // stack using ReThrow.
18042 THREADED_TEST(SpaghettiStackReThrow) {
18043 v8::Isolate* isolate = CcTest::isolate();
18044 v8::HandleScope scope(isolate);
18045 LocalContext context;
18046 context->Global()->Set(
18047 v8::String::NewFromUtf8(isolate, "s"),
18048 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18049 v8::TryCatch try_catch;
18053 " toString: function () {"
18063 CHECK(try_catch.HasCaught());
18064 v8::String::Utf8Value value(try_catch.Exception());
18065 CHECK_EQ(0, strcmp(*value, "Hey!"));
18070 v8::V8::Initialize();
18071 v8::Isolate* isolate = CcTest::isolate();
18072 v8::HandleScope scope(isolate);
18073 v8::Local<Context> other_context;
18076 // Create a context used to keep the code from aging in the compilation
18078 other_context = Context::New(isolate);
18080 // Context-dependent context data creates reference from the compilation
18081 // cache to the global object.
18082 const char* source_simple = "1";
18084 v8::HandleScope scope(isolate);
18085 v8::Local<Context> context = Context::New(isolate);
18088 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18089 context->SetEmbedderData(0, obj);
18090 CompileRun(source_simple);
18093 v8::V8::ContextDisposedNotification();
18094 for (gc_count = 1; gc_count < 10; gc_count++) {
18095 other_context->Enter();
18096 CompileRun(source_simple);
18097 other_context->Exit();
18098 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18099 if (GetGlobalObjectsCount() == 1) break;
18101 CHECK_GE(2, gc_count);
18102 CHECK_EQ(1, GetGlobalObjectsCount());
18104 // Eval in a function creates reference from the compilation cache to the
18106 const char* source_eval = "function f(){eval('1')}; f()";
18108 v8::HandleScope scope(isolate);
18109 v8::Local<Context> context = Context::New(isolate);
18112 CompileRun(source_eval);
18115 v8::V8::ContextDisposedNotification();
18116 for (gc_count = 1; gc_count < 10; gc_count++) {
18117 other_context->Enter();
18118 CompileRun(source_eval);
18119 other_context->Exit();
18120 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18121 if (GetGlobalObjectsCount() == 1) break;
18123 CHECK_GE(2, gc_count);
18124 CHECK_EQ(1, GetGlobalObjectsCount());
18126 // Looking up the line number for an exception creates reference from the
18127 // compilation cache to the global object.
18128 const char* source_exception = "function f(){throw 1;} f()";
18130 v8::HandleScope scope(isolate);
18131 v8::Local<Context> context = Context::New(isolate);
18134 v8::TryCatch try_catch;
18135 CompileRun(source_exception);
18136 CHECK(try_catch.HasCaught());
18137 v8::Handle<v8::Message> message = try_catch.Message();
18138 CHECK(!message.IsEmpty());
18139 CHECK_EQ(1, message->GetLineNumber());
18142 v8::V8::ContextDisposedNotification();
18143 for (gc_count = 1; gc_count < 10; gc_count++) {
18144 other_context->Enter();
18145 CompileRun(source_exception);
18146 other_context->Exit();
18147 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18148 if (GetGlobalObjectsCount() == 1) break;
18150 CHECK_GE(2, gc_count);
18151 CHECK_EQ(1, GetGlobalObjectsCount());
18153 v8::V8::ContextDisposedNotification();
18157 THREADED_TEST(ScriptOrigin) {
18159 v8::HandleScope scope(env->GetIsolate());
18160 v8::ScriptOrigin origin =
18161 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18162 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18163 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18164 v8::Script::Compile(script, &origin)->Run();
18165 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18166 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18167 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18168 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18170 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18171 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18172 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18174 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18175 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18176 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18180 THREADED_TEST(FunctionGetInferredName) {
18182 v8::HandleScope scope(env->GetIsolate());
18183 v8::ScriptOrigin origin =
18184 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18185 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18187 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18188 v8::Script::Compile(script, &origin)->Run();
18189 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18190 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18191 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18195 THREADED_TEST(FunctionGetDisplayName) {
18197 v8::HandleScope scope(env->GetIsolate());
18198 const char* code = "var error = false;"
18199 "function a() { this.x = 1; };"
18200 "a.displayName = 'display_a';"
18201 "var b = (function() {"
18202 " var f = function() { this.x = 2; };"
18203 " f.displayName = 'display_b';"
18206 "var c = function() {};"
18207 "c.__defineGetter__('displayName', function() {"
18209 " throw new Error();"
18212 "d.__defineGetter__('displayName', function() {"
18214 " return 'wrong_display_name';"
18217 "e.displayName = 'wrong_display_name';"
18218 "e.__defineSetter__('displayName', function() {"
18220 " throw new Error();"
18223 "f.displayName = { 'foo': 6, toString: function() {"
18225 " return 'wrong_display_name';"
18227 "var g = function() {"
18228 " arguments.callee.displayName = 'set_in_runtime';"
18231 v8::ScriptOrigin origin =
18232 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18233 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18235 v8::Local<v8::Value> error =
18236 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18237 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18238 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18239 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18240 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18241 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18242 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18243 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18244 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18245 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18246 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18247 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18248 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18249 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18250 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18251 CHECK_EQ(false, error->BooleanValue());
18252 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18253 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18254 CHECK(c->GetDisplayName()->IsUndefined());
18255 CHECK(d->GetDisplayName()->IsUndefined());
18256 CHECK(e->GetDisplayName()->IsUndefined());
18257 CHECK(f->GetDisplayName()->IsUndefined());
18258 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18262 THREADED_TEST(ScriptLineNumber) {
18264 v8::HandleScope scope(env->GetIsolate());
18265 v8::ScriptOrigin origin =
18266 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18267 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18268 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18269 v8::Script::Compile(script, &origin)->Run();
18270 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18271 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18272 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18273 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18274 CHECK_EQ(0, f->GetScriptLineNumber());
18275 CHECK_EQ(2, g->GetScriptLineNumber());
18279 THREADED_TEST(ScriptColumnNumber) {
18281 v8::Isolate* isolate = env->GetIsolate();
18282 v8::HandleScope scope(isolate);
18283 v8::ScriptOrigin origin =
18284 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18285 v8::Integer::New(isolate, 3),
18286 v8::Integer::New(isolate, 2));
18287 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18288 isolate, "function foo() {}\n\n function bar() {}");
18289 v8::Script::Compile(script, &origin)->Run();
18290 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18291 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18292 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18293 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18294 CHECK_EQ(14, foo->GetScriptColumnNumber());
18295 CHECK_EQ(17, bar->GetScriptColumnNumber());
18299 THREADED_TEST(FunctionIsBuiltin) {
18301 v8::Isolate* isolate = env->GetIsolate();
18302 v8::HandleScope scope(isolate);
18303 v8::Local<v8::Function> f;
18304 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18305 CHECK(f->IsBuiltin());
18306 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18307 CHECK(f->IsBuiltin());
18308 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18309 CHECK(f->IsBuiltin());
18310 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18311 CHECK(f->IsBuiltin());
18312 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18313 CHECK(!f->IsBuiltin());
18317 THREADED_TEST(FunctionGetScriptId) {
18319 v8::Isolate* isolate = env->GetIsolate();
18320 v8::HandleScope scope(isolate);
18321 v8::ScriptOrigin origin =
18322 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18323 v8::Integer::New(isolate, 3),
18324 v8::Integer::New(isolate, 2));
18325 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18326 isolate, "function foo() {}\n\n function bar() {}");
18327 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18329 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18330 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18331 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18332 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18333 CHECK_EQ(script->GetId(), foo->ScriptId());
18334 CHECK_EQ(script->GetId(), bar->ScriptId());
18338 THREADED_TEST(FunctionGetBoundFunction) {
18340 v8::HandleScope scope(env->GetIsolate());
18341 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18342 env->GetIsolate(), "test"));
18343 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18345 "var a = new Object();\n"
18347 "function f () { return this.x };\n"
18348 "var g = f.bind(a);\n"
18350 v8::Script::Compile(script, &origin)->Run();
18351 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18352 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18353 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18354 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18355 CHECK(g->GetBoundFunction()->IsFunction());
18356 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18357 g->GetBoundFunction());
18358 CHECK_EQ(f->GetName(), original_function->GetName());
18359 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18360 CHECK_EQ(f->GetScriptColumnNumber(),
18361 original_function->GetScriptColumnNumber());
18365 static void GetterWhichReturns42(
18366 Local<String> name,
18367 const v8::PropertyCallbackInfo<v8::Value>& info) {
18368 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18369 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18370 info.GetReturnValue().Set(v8_num(42));
18374 static void SetterWhichSetsYOnThisTo23(
18375 Local<String> name,
18376 Local<Value> value,
18377 const v8::PropertyCallbackInfo<void>& info) {
18378 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18379 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18380 info.This()->Set(v8_str("y"), v8_num(23));
18384 void FooGetInterceptor(Local<String> name,
18385 const v8::PropertyCallbackInfo<v8::Value>& info) {
18386 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18387 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18388 if (!name->Equals(v8_str("foo"))) return;
18389 info.GetReturnValue().Set(v8_num(42));
18393 void FooSetInterceptor(Local<String> name,
18394 Local<Value> value,
18395 const v8::PropertyCallbackInfo<v8::Value>& info) {
18396 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18397 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18398 if (!name->Equals(v8_str("foo"))) return;
18399 info.This()->Set(v8_str("y"), v8_num(23));
18400 info.GetReturnValue().Set(v8_num(23));
18404 TEST(SetterOnConstructorPrototype) {
18405 v8::Isolate* isolate = CcTest::isolate();
18406 v8::HandleScope scope(isolate);
18407 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18408 templ->SetAccessor(v8_str("x"),
18409 GetterWhichReturns42,
18410 SetterWhichSetsYOnThisTo23);
18411 LocalContext context;
18412 context->Global()->Set(v8_str("P"), templ->NewInstance());
18413 CompileRun("function C1() {"
18416 "C1.prototype = P;"
18420 "C2.prototype = { };"
18421 "C2.prototype.__proto__ = P;");
18423 v8::Local<v8::Script> script;
18424 script = v8::Script::Compile(v8_str("new C1();"));
18425 for (int i = 0; i < 10; i++) {
18426 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18427 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18428 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18431 script = v8::Script::Compile(v8_str("new C2();"));
18432 for (int i = 0; i < 10; i++) {
18433 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18434 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18435 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18440 static void NamedPropertyGetterWhichReturns42(
18441 Local<String> name,
18442 const v8::PropertyCallbackInfo<v8::Value>& info) {
18443 info.GetReturnValue().Set(v8_num(42));
18447 static void NamedPropertySetterWhichSetsYOnThisTo23(
18448 Local<String> name,
18449 Local<Value> value,
18450 const v8::PropertyCallbackInfo<v8::Value>& info) {
18451 if (name->Equals(v8_str("x"))) {
18452 info.This()->Set(v8_str("y"), v8_num(23));
18457 THREADED_TEST(InterceptorOnConstructorPrototype) {
18458 v8::Isolate* isolate = CcTest::isolate();
18459 v8::HandleScope scope(isolate);
18460 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18461 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18462 NamedPropertySetterWhichSetsYOnThisTo23);
18463 LocalContext context;
18464 context->Global()->Set(v8_str("P"), templ->NewInstance());
18465 CompileRun("function C1() {"
18468 "C1.prototype = P;"
18472 "C2.prototype = { };"
18473 "C2.prototype.__proto__ = P;");
18475 v8::Local<v8::Script> script;
18476 script = v8::Script::Compile(v8_str("new C1();"));
18477 for (int i = 0; i < 10; i++) {
18478 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18479 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18480 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18483 script = v8::Script::Compile(v8_str("new C2();"));
18484 for (int i = 0; i < 10; i++) {
18485 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18486 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18487 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18493 const char* source = "function C1() {"
18496 "C1.prototype = P;";
18498 LocalContext context;
18499 v8::Isolate* isolate = context->GetIsolate();
18500 v8::HandleScope scope(isolate);
18501 v8::Local<v8::Script> script;
18503 // Use a simple object as prototype.
18504 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18505 prototype->Set(v8_str("y"), v8_num(42));
18506 context->Global()->Set(v8_str("P"), prototype);
18508 // This compile will add the code to the compilation cache.
18509 CompileRun(source);
18511 script = v8::Script::Compile(v8_str("new C1();"));
18512 // Allow enough iterations for the inobject slack tracking logic
18513 // to finalize instance size and install the fast construct stub.
18514 for (int i = 0; i < 256; i++) {
18515 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18516 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18517 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18520 // Use an API object with accessors as prototype.
18521 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18522 templ->SetAccessor(v8_str("x"),
18523 GetterWhichReturns42,
18524 SetterWhichSetsYOnThisTo23);
18525 context->Global()->Set(v8_str("P"), templ->NewInstance());
18527 // This compile will get the code from the compilation cache.
18528 CompileRun(source);
18530 script = v8::Script::Compile(v8_str("new C1();"));
18531 for (int i = 0; i < 10; i++) {
18532 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18533 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18534 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18538 v8::Isolate* gc_callbacks_isolate = NULL;
18539 int prologue_call_count = 0;
18540 int epilogue_call_count = 0;
18541 int prologue_call_count_second = 0;
18542 int epilogue_call_count_second = 0;
18544 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18545 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18546 ++prologue_call_count;
18550 void PrologueCallback(v8::Isolate* isolate,
18552 v8::GCCallbackFlags flags) {
18553 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18554 CHECK_EQ(gc_callbacks_isolate, isolate);
18555 ++prologue_call_count;
18559 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18560 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18561 ++epilogue_call_count;
18565 void EpilogueCallback(v8::Isolate* isolate,
18567 v8::GCCallbackFlags flags) {
18568 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18569 CHECK_EQ(gc_callbacks_isolate, isolate);
18570 ++epilogue_call_count;
18574 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18575 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18576 ++prologue_call_count_second;
18580 void PrologueCallbackSecond(v8::Isolate* isolate,
18582 v8::GCCallbackFlags flags) {
18583 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18584 CHECK_EQ(gc_callbacks_isolate, isolate);
18585 ++prologue_call_count_second;
18589 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18590 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18591 ++epilogue_call_count_second;
18595 void EpilogueCallbackSecond(v8::Isolate* isolate,
18597 v8::GCCallbackFlags flags) {
18598 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18599 CHECK_EQ(gc_callbacks_isolate, isolate);
18600 ++epilogue_call_count_second;
18604 TEST(GCCallbacksOld) {
18605 LocalContext context;
18607 v8::V8::AddGCPrologueCallback(PrologueCallback);
18608 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18609 CHECK_EQ(0, prologue_call_count);
18610 CHECK_EQ(0, epilogue_call_count);
18611 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18612 CHECK_EQ(1, prologue_call_count);
18613 CHECK_EQ(1, epilogue_call_count);
18614 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18615 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18616 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18617 CHECK_EQ(2, prologue_call_count);
18618 CHECK_EQ(2, epilogue_call_count);
18619 CHECK_EQ(1, prologue_call_count_second);
18620 CHECK_EQ(1, epilogue_call_count_second);
18621 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18622 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18623 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18624 CHECK_EQ(2, prologue_call_count);
18625 CHECK_EQ(2, epilogue_call_count);
18626 CHECK_EQ(2, prologue_call_count_second);
18627 CHECK_EQ(2, epilogue_call_count_second);
18628 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18629 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18630 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18631 CHECK_EQ(2, prologue_call_count);
18632 CHECK_EQ(2, epilogue_call_count);
18633 CHECK_EQ(2, prologue_call_count_second);
18634 CHECK_EQ(2, epilogue_call_count_second);
18638 TEST(GCCallbacks) {
18639 LocalContext context;
18640 v8::Isolate* isolate = context->GetIsolate();
18641 gc_callbacks_isolate = isolate;
18642 isolate->AddGCPrologueCallback(PrologueCallback);
18643 isolate->AddGCEpilogueCallback(EpilogueCallback);
18644 CHECK_EQ(0, prologue_call_count);
18645 CHECK_EQ(0, epilogue_call_count);
18646 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18647 CHECK_EQ(1, prologue_call_count);
18648 CHECK_EQ(1, epilogue_call_count);
18649 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18650 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18651 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18652 CHECK_EQ(2, prologue_call_count);
18653 CHECK_EQ(2, epilogue_call_count);
18654 CHECK_EQ(1, prologue_call_count_second);
18655 CHECK_EQ(1, epilogue_call_count_second);
18656 isolate->RemoveGCPrologueCallback(PrologueCallback);
18657 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18658 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18659 CHECK_EQ(2, prologue_call_count);
18660 CHECK_EQ(2, epilogue_call_count);
18661 CHECK_EQ(2, prologue_call_count_second);
18662 CHECK_EQ(2, epilogue_call_count_second);
18663 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18664 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18665 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18666 CHECK_EQ(2, prologue_call_count);
18667 CHECK_EQ(2, epilogue_call_count);
18668 CHECK_EQ(2, prologue_call_count_second);
18669 CHECK_EQ(2, epilogue_call_count_second);
18673 THREADED_TEST(AddToJSFunctionResultCache) {
18674 i::FLAG_stress_compaction = false;
18675 i::FLAG_allow_natives_syntax = true;
18676 v8::HandleScope scope(CcTest::isolate());
18678 LocalContext context;
18684 " var r0 = %_GetFromCache(0, key0);"
18685 " var r1 = %_GetFromCache(0, key1);"
18686 " var r0_ = %_GetFromCache(0, key0);"
18688 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18689 " var r1_ = %_GetFromCache(0, key1);"
18691 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18692 " return 'PASSED';"
18694 CcTest::heap()->ClearJSFunctionResultCaches();
18695 ExpectString(code, "PASSED");
18699 THREADED_TEST(FillJSFunctionResultCache) {
18700 i::FLAG_allow_natives_syntax = true;
18701 LocalContext context;
18702 v8::HandleScope scope(context->GetIsolate());
18707 " var r = %_GetFromCache(0, k);"
18708 " for (var i = 0; i < 16; i++) {"
18709 " %_GetFromCache(0, 'a' + i);"
18711 " if (r === %_GetFromCache(0, k))"
18712 " return 'FAILED: k0CacheSize is too small';"
18713 " return 'PASSED';"
18715 CcTest::heap()->ClearJSFunctionResultCaches();
18716 ExpectString(code, "PASSED");
18720 THREADED_TEST(RoundRobinGetFromCache) {
18721 i::FLAG_allow_natives_syntax = true;
18722 LocalContext context;
18723 v8::HandleScope scope(context->GetIsolate());
18728 " for (var i = 0; i < 16; i++) keys.push(i);"
18729 " var values = [];"
18730 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18731 " for (var i = 0; i < 16; i++) {"
18732 " var v = %_GetFromCache(0, keys[i]);"
18733 " if (v.toString() !== values[i].toString())"
18734 " return 'Wrong value for ' + "
18735 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18737 " return 'PASSED';"
18739 CcTest::heap()->ClearJSFunctionResultCaches();
18740 ExpectString(code, "PASSED");
18744 THREADED_TEST(ReverseGetFromCache) {
18745 i::FLAG_allow_natives_syntax = true;
18746 LocalContext context;
18747 v8::HandleScope scope(context->GetIsolate());
18752 " for (var i = 0; i < 16; i++) keys.push(i);"
18753 " var values = [];"
18754 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18755 " for (var i = 15; i >= 16; i--) {"
18756 " var v = %_GetFromCache(0, keys[i]);"
18757 " if (v !== values[i])"
18758 " return 'Wrong value for ' + "
18759 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18761 " return 'PASSED';"
18763 CcTest::heap()->ClearJSFunctionResultCaches();
18764 ExpectString(code, "PASSED");
18768 THREADED_TEST(TestEviction) {
18769 i::FLAG_allow_natives_syntax = true;
18770 LocalContext context;
18771 v8::HandleScope scope(context->GetIsolate());
18775 " for (var i = 0; i < 2*16; i++) {"
18776 " %_GetFromCache(0, 'a' + i);"
18778 " return 'PASSED';"
18780 CcTest::heap()->ClearJSFunctionResultCaches();
18781 ExpectString(code, "PASSED");
18785 THREADED_TEST(TwoByteStringInAsciiCons) {
18786 // See Chromium issue 47824.
18787 LocalContext context;
18788 v8::HandleScope scope(context->GetIsolate());
18790 const char* init_code =
18791 "var str1 = 'abelspendabel';"
18792 "var str2 = str1 + str1 + str1;"
18794 Local<Value> result = CompileRun(init_code);
18796 Local<Value> indexof = CompileRun("str2.indexOf('els')");
18797 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18799 CHECK(result->IsString());
18800 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18801 int length = string->length();
18802 CHECK(string->IsOneByteRepresentation());
18804 FlattenString(string);
18805 i::Handle<i::String> flat_string = FlattenGetString(string);
18807 CHECK(string->IsOneByteRepresentation());
18808 CHECK(flat_string->IsOneByteRepresentation());
18810 // Create external resource.
18811 uint16_t* uc16_buffer = new uint16_t[length + 1];
18813 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18814 uc16_buffer[length] = 0;
18816 TestResource resource(uc16_buffer);
18818 flat_string->MakeExternal(&resource);
18820 CHECK(flat_string->IsTwoByteRepresentation());
18822 // If the cons string has been short-circuited, skip the following checks.
18823 if (!string.is_identical_to(flat_string)) {
18824 // At this point, we should have a Cons string which is flat and ASCII,
18825 // with a first half that is a two-byte string (although it only contains
18826 // ASCII characters). This is a valid sequence of steps, and it can happen
18828 CHECK(string->IsOneByteRepresentation());
18829 i::ConsString* cons = i::ConsString::cast(*string);
18830 CHECK_EQ(0, cons->second()->length());
18831 CHECK(cons->first()->IsTwoByteRepresentation());
18834 // Check that some string operations work.
18837 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18838 CHECK_EQ(6, reresult->Int32Value());
18841 reresult = CompileRun("str2.match(/abe./g).length;");
18842 CHECK_EQ(6, reresult->Int32Value());
18844 reresult = CompileRun("str2.search(/bel/g);");
18845 CHECK_EQ(1, reresult->Int32Value());
18847 reresult = CompileRun("str2.search(/be./g);");
18848 CHECK_EQ(1, reresult->Int32Value());
18850 ExpectTrue("/bel/g.test(str2);");
18852 ExpectTrue("/be./g.test(str2);");
18854 reresult = CompileRun("/bel/g.exec(str2);");
18855 CHECK(!reresult->IsNull());
18857 reresult = CompileRun("/be./g.exec(str2);");
18858 CHECK(!reresult->IsNull());
18860 ExpectString("str2.substring(2, 10);", "elspenda");
18862 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18864 ExpectString("str2.charAt(2);", "e");
18866 ExpectObject("str2.indexOf('els');", indexof);
18868 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18870 reresult = CompileRun("str2.charCodeAt(2);");
18871 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18875 TEST(ContainsOnlyOneByte) {
18876 v8::V8::Initialize();
18877 v8::Isolate* isolate = CcTest::isolate();
18878 v8::HandleScope scope(isolate);
18879 // Make a buffer long enough that it won't automatically be converted.
18880 const int length = 512;
18881 // Ensure word aligned assignment.
18882 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18883 i::SmartArrayPointer<uintptr_t>
18884 aligned_contents(new uintptr_t[aligned_length]);
18885 uint16_t* string_contents =
18886 reinterpret_cast<uint16_t*>(aligned_contents.get());
18887 // Set to contain only one byte.
18888 for (int i = 0; i < length-1; i++) {
18889 string_contents[i] = 0x41;
18891 string_contents[length-1] = 0;
18893 Handle<String> string =
18894 String::NewExternal(isolate,
18895 new TestResource(string_contents, NULL, false));
18896 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18897 // Counter example.
18898 string = String::NewFromTwoByte(isolate, string_contents);
18899 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18900 // Test left right and balanced cons strings.
18901 Handle<String> base = String::NewFromUtf8(isolate, "a");
18902 Handle<String> left = base;
18903 Handle<String> right = base;
18904 for (int i = 0; i < 1000; i++) {
18905 left = String::Concat(base, left);
18906 right = String::Concat(right, base);
18908 Handle<String> balanced = String::Concat(left, base);
18909 balanced = String::Concat(balanced, right);
18910 Handle<String> cons_strings[] = {left, balanced, right};
18911 Handle<String> two_byte =
18912 String::NewExternal(isolate,
18913 new TestResource(string_contents, NULL, false));
18914 USE(two_byte); USE(cons_strings);
18915 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18916 // Base assumptions.
18917 string = cons_strings[i];
18918 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18919 // Test left and right concatentation.
18920 string = String::Concat(two_byte, cons_strings[i]);
18921 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18922 string = String::Concat(cons_strings[i], two_byte);
18923 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18925 // Set bits in different positions
18926 // for strings of different lengths and alignments.
18927 for (int alignment = 0; alignment < 7; alignment++) {
18928 for (int size = 2; alignment + size < length; size *= 2) {
18929 int zero_offset = size + alignment;
18930 string_contents[zero_offset] = 0;
18931 for (int i = 0; i < size; i++) {
18932 int shift = 8 + (i % 7);
18933 string_contents[alignment + i] = 1 << shift;
18934 string = String::NewExternal(
18936 new TestResource(string_contents + alignment, NULL, false));
18937 CHECK_EQ(size, string->Length());
18938 CHECK(!string->ContainsOnlyOneByte());
18939 string_contents[alignment + i] = 0x41;
18941 string_contents[zero_offset] = 0x41;
18947 // Failed access check callback that performs a GC on each invocation.
18948 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
18949 v8::AccessType type,
18950 Local<v8::Value> data) {
18951 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18955 TEST(GCInFailedAccessCheckCallback) {
18956 // Install a failed access check callback that performs a GC on each
18957 // invocation. Then force the callback to be called from va
18959 v8::V8::Initialize();
18960 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
18962 v8::Isolate* isolate = CcTest::isolate();
18963 v8::HandleScope scope(isolate);
18965 // Create an ObjectTemplate for global objects and install access
18966 // check callbacks that will block access.
18967 v8::Handle<v8::ObjectTemplate> global_template =
18968 v8::ObjectTemplate::New(isolate);
18969 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
18970 IndexedGetAccessBlocker,
18971 v8::Handle<v8::Value>(),
18974 // Create a context and set an x property on it's global object.
18975 LocalContext context0(NULL, global_template);
18976 context0->Global()->Set(v8_str("x"), v8_num(42));
18977 v8::Handle<v8::Object> global0 = context0->Global();
18979 // Create a context with a different security token so that the
18980 // failed access check callback will be called on each access.
18981 LocalContext context1(NULL, global_template);
18982 context1->Global()->Set(v8_str("other"), global0);
18984 // Get property with failed access check.
18985 ExpectUndefined("other.x");
18987 // Get element with failed access check.
18988 ExpectUndefined("other[0]");
18990 // Set property with failed access check.
18991 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
18992 CHECK(result->IsObject());
18994 // Set element with failed access check.
18995 result = CompileRun("other[0] = new Object()");
18996 CHECK(result->IsObject());
18998 // Get property attribute with failed access check.
18999 ExpectFalse("\'x\' in other");
19001 // Get property attribute for element with failed access check.
19002 ExpectFalse("0 in other");
19004 // Delete property.
19005 ExpectFalse("delete other.x");
19008 CHECK_EQ(false, global0->Delete(0));
19012 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19014 // Define JavaScript accessor.
19015 ExpectUndefined("Object.prototype.__defineGetter__.call("
19016 " other, \'x\', function() { return 42; })");
19019 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19022 // HasLocalElement.
19023 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19025 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19026 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19027 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19029 // Reset the failed access check callback so it does not influence
19030 // the other tests.
19031 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19035 TEST(IsolateNewDispose) {
19036 v8::Isolate* current_isolate = CcTest::isolate();
19037 v8::Isolate* isolate = v8::Isolate::New();
19038 CHECK(isolate != NULL);
19039 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19040 CHECK(current_isolate != isolate);
19041 CHECK(current_isolate == CcTest::isolate());
19043 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19044 last_location = last_message = NULL;
19045 isolate->Dispose();
19046 CHECK_EQ(last_location, NULL);
19047 CHECK_EQ(last_message, NULL);
19051 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19052 v8::Isolate* isolate = v8::Isolate::New();
19054 v8::Isolate::Scope i_scope(isolate);
19055 v8::HandleScope scope(isolate);
19056 LocalContext context(isolate);
19057 // Run something in this isolate.
19058 ExpectTrue("true");
19059 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19060 last_location = last_message = NULL;
19061 // Still entered, should fail.
19062 isolate->Dispose();
19063 CHECK_NE(last_location, NULL);
19064 CHECK_NE(last_message, NULL);
19066 isolate->Dispose();
19070 TEST(RunTwoIsolatesOnSingleThread) {
19072 v8::Isolate* isolate1 = v8::Isolate::New();
19074 v8::Persistent<v8::Context> context1;
19076 v8::HandleScope scope(isolate1);
19077 context1.Reset(isolate1, Context::New(isolate1));
19081 v8::HandleScope scope(isolate1);
19082 v8::Local<v8::Context> context =
19083 v8::Local<v8::Context>::New(isolate1, context1);
19084 v8::Context::Scope context_scope(context);
19085 // Run something in new isolate.
19086 CompileRun("var foo = 'isolate 1';");
19087 ExpectString("function f() { return foo; }; f()", "isolate 1");
19091 v8::Isolate* isolate2 = v8::Isolate::New();
19092 v8::Persistent<v8::Context> context2;
19095 v8::Isolate::Scope iscope(isolate2);
19096 v8::HandleScope scope(isolate2);
19097 context2.Reset(isolate2, Context::New(isolate2));
19098 v8::Local<v8::Context> context =
19099 v8::Local<v8::Context>::New(isolate2, context2);
19100 v8::Context::Scope context_scope(context);
19102 // Run something in new isolate.
19103 CompileRun("var foo = 'isolate 2';");
19104 ExpectString("function f() { return foo; }; f()", "isolate 2");
19108 v8::HandleScope scope(isolate1);
19109 v8::Local<v8::Context> context =
19110 v8::Local<v8::Context>::New(isolate1, context1);
19111 v8::Context::Scope context_scope(context);
19112 // Now again in isolate 1
19113 ExpectString("function f() { return foo; }; f()", "isolate 1");
19118 // Run some stuff in default isolate.
19119 v8::Persistent<v8::Context> context_default;
19121 v8::Isolate* isolate = CcTest::isolate();
19122 v8::Isolate::Scope iscope(isolate);
19123 v8::HandleScope scope(isolate);
19124 context_default.Reset(isolate, Context::New(isolate));
19128 v8::HandleScope scope(CcTest::isolate());
19129 v8::Local<v8::Context> context =
19130 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19131 v8::Context::Scope context_scope(context);
19132 // Variables in other isolates should be not available, verify there
19133 // is an exception.
19134 ExpectTrue("function f() {"
19142 "var isDefaultIsolate = true;"
19149 v8::Isolate::Scope iscope(isolate2);
19150 v8::HandleScope scope(isolate2);
19151 v8::Local<v8::Context> context =
19152 v8::Local<v8::Context>::New(isolate2, context2);
19153 v8::Context::Scope context_scope(context);
19154 ExpectString("function f() { return foo; }; f()", "isolate 2");
19158 v8::HandleScope scope(v8::Isolate::GetCurrent());
19159 v8::Local<v8::Context> context =
19160 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19161 v8::Context::Scope context_scope(context);
19162 ExpectString("function f() { return foo; }; f()", "isolate 1");
19166 v8::Isolate::Scope iscope(isolate2);
19173 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19174 last_location = last_message = NULL;
19176 isolate1->Dispose();
19177 CHECK_EQ(last_location, NULL);
19178 CHECK_EQ(last_message, NULL);
19180 isolate2->Dispose();
19181 CHECK_EQ(last_location, NULL);
19182 CHECK_EQ(last_message, NULL);
19184 // Check that default isolate still runs.
19186 v8::HandleScope scope(CcTest::isolate());
19187 v8::Local<v8::Context> context =
19188 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19189 v8::Context::Scope context_scope(context);
19190 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19195 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19196 v8::Isolate::Scope isolate_scope(isolate);
19197 v8::HandleScope scope(isolate);
19198 LocalContext context(isolate);
19199 i::ScopedVector<char> code(1024);
19200 i::OS::SNPrintF(code, "function fib(n) {"
19201 " if (n <= 2) return 1;"
19202 " return fib(n-1) + fib(n-2);"
19205 Local<Value> value = CompileRun(code.start());
19206 CHECK(value->IsNumber());
19207 return static_cast<int>(value->NumberValue());
19210 class IsolateThread : public v8::internal::Thread {
19212 IsolateThread(v8::Isolate* isolate, int fib_limit)
19213 : Thread("IsolateThread"),
19215 fib_limit_(fib_limit),
19219 result_ = CalcFibonacci(isolate_, fib_limit_);
19222 int result() { return result_; }
19225 v8::Isolate* isolate_;
19231 TEST(MultipleIsolatesOnIndividualThreads) {
19232 v8::Isolate* isolate1 = v8::Isolate::New();
19233 v8::Isolate* isolate2 = v8::Isolate::New();
19235 IsolateThread thread1(isolate1, 21);
19236 IsolateThread thread2(isolate2, 12);
19238 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19242 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19243 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19248 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19249 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19250 CHECK_EQ(result1, 10946);
19251 CHECK_EQ(result2, 144);
19252 CHECK_EQ(result1, thread1.result());
19253 CHECK_EQ(result2, thread2.result());
19255 isolate1->Dispose();
19256 isolate2->Dispose();
19260 TEST(IsolateDifferentContexts) {
19261 v8::Isolate* isolate = v8::Isolate::New();
19262 Local<v8::Context> context;
19264 v8::Isolate::Scope isolate_scope(isolate);
19265 v8::HandleScope handle_scope(isolate);
19266 context = v8::Context::New(isolate);
19267 v8::Context::Scope context_scope(context);
19268 Local<Value> v = CompileRun("2");
19269 CHECK(v->IsNumber());
19270 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19273 v8::Isolate::Scope isolate_scope(isolate);
19274 v8::HandleScope handle_scope(isolate);
19275 context = v8::Context::New(isolate);
19276 v8::Context::Scope context_scope(context);
19277 Local<Value> v = CompileRun("22");
19278 CHECK(v->IsNumber());
19279 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19281 isolate->Dispose();
19284 class InitDefaultIsolateThread : public v8::internal::Thread {
19288 SetResourceConstraints,
19290 SetCounterFunction,
19291 SetCreateHistogramFunction,
19292 SetAddHistogramSampleFunction
19295 explicit InitDefaultIsolateThread(TestCase testCase)
19296 : Thread("InitDefaultIsolateThread"),
19297 testCase_(testCase),
19301 v8::Isolate* isolate = v8::Isolate::New();
19303 switch (testCase_) {
19305 v8::V8::IgnoreOutOfMemoryException();
19308 case SetResourceConstraints: {
19309 static const int K = 1024;
19310 v8::ResourceConstraints constraints;
19311 constraints.set_max_young_space_size(256 * K);
19312 constraints.set_max_old_space_size(4 * K * K);
19313 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19317 case SetFatalHandler:
19318 v8::V8::SetFatalErrorHandler(NULL);
19321 case SetCounterFunction:
19322 v8::V8::SetCounterFunction(NULL);
19325 case SetCreateHistogramFunction:
19326 v8::V8::SetCreateHistogramFunction(NULL);
19329 case SetAddHistogramSampleFunction:
19330 v8::V8::SetAddHistogramSampleFunction(NULL);
19334 isolate->Dispose();
19338 bool result() { return result_; }
19341 TestCase testCase_;
19346 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19347 InitDefaultIsolateThread thread(testCase);
19350 CHECK_EQ(thread.result(), true);
19354 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19355 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
19359 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19360 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19364 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19365 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19369 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19370 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19374 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19375 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19379 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
19380 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19384 TEST(StringCheckMultipleContexts) {
19386 "(function() { return \"a\".charAt(0); })()";
19389 // Run the code twice in the first context to initialize the call IC.
19390 LocalContext context1;
19391 v8::HandleScope scope(context1->GetIsolate());
19392 ExpectString(code, "a");
19393 ExpectString(code, "a");
19397 // Change the String.prototype in the second context and check
19398 // that the right function gets called.
19399 LocalContext context2;
19400 v8::HandleScope scope(context2->GetIsolate());
19401 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19402 ExpectString(code, "not a");
19407 TEST(NumberCheckMultipleContexts) {
19409 "(function() { return (42).toString(); })()";
19412 // Run the code twice in the first context to initialize the call IC.
19413 LocalContext context1;
19414 v8::HandleScope scope(context1->GetIsolate());
19415 ExpectString(code, "42");
19416 ExpectString(code, "42");
19420 // Change the Number.prototype in the second context and check
19421 // that the right function gets called.
19422 LocalContext context2;
19423 v8::HandleScope scope(context2->GetIsolate());
19424 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19425 ExpectString(code, "not 42");
19430 TEST(BooleanCheckMultipleContexts) {
19432 "(function() { return true.toString(); })()";
19435 // Run the code twice in the first context to initialize the call IC.
19436 LocalContext context1;
19437 v8::HandleScope scope(context1->GetIsolate());
19438 ExpectString(code, "true");
19439 ExpectString(code, "true");
19443 // Change the Boolean.prototype in the second context and check
19444 // that the right function gets called.
19445 LocalContext context2;
19446 v8::HandleScope scope(context2->GetIsolate());
19447 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19448 ExpectString(code, "");
19453 TEST(DontDeleteCellLoadIC) {
19454 const char* function_code =
19455 "function readCell() { while (true) { return cell; } }";
19458 // Run the code twice in the first context to initialize the load
19459 // IC for a don't delete cell.
19460 LocalContext context1;
19461 v8::HandleScope scope(context1->GetIsolate());
19462 CompileRun("var cell = \"first\";");
19463 ExpectBoolean("delete cell", false);
19464 CompileRun(function_code);
19465 ExpectString("readCell()", "first");
19466 ExpectString("readCell()", "first");
19470 // Use a deletable cell in the second context.
19471 LocalContext context2;
19472 v8::HandleScope scope(context2->GetIsolate());
19473 CompileRun("cell = \"second\";");
19474 CompileRun(function_code);
19475 ExpectString("readCell()", "second");
19476 ExpectBoolean("delete cell", true);
19477 ExpectString("(function() {"
19479 " return readCell();"
19481 " return e.toString();"
19484 "ReferenceError: cell is not defined");
19485 CompileRun("cell = \"new_second\";");
19486 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19487 ExpectString("readCell()", "new_second");
19488 ExpectString("readCell()", "new_second");
19493 TEST(DontDeleteCellLoadICForceDelete) {
19494 const char* function_code =
19495 "function readCell() { while (true) { return cell; } }";
19497 // Run the code twice to initialize the load IC for a don't delete
19499 LocalContext context;
19500 v8::HandleScope scope(context->GetIsolate());
19501 CompileRun("var cell = \"value\";");
19502 ExpectBoolean("delete cell", false);
19503 CompileRun(function_code);
19504 ExpectString("readCell()", "value");
19505 ExpectString("readCell()", "value");
19507 // Delete the cell using the API and check the inlined code works
19509 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19510 ExpectString("(function() {"
19512 " return readCell();"
19514 " return e.toString();"
19517 "ReferenceError: cell is not defined");
19521 TEST(DontDeleteCellLoadICAPI) {
19522 const char* function_code =
19523 "function readCell() { while (true) { return cell; } }";
19525 // Run the code twice to initialize the load IC for a don't delete
19526 // cell created using the API.
19527 LocalContext context;
19528 v8::HandleScope scope(context->GetIsolate());
19529 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19530 ExpectBoolean("delete cell", false);
19531 CompileRun(function_code);
19532 ExpectString("readCell()", "value");
19533 ExpectString("readCell()", "value");
19535 // Delete the cell using the API and check the inlined code works
19537 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19538 ExpectString("(function() {"
19540 " return readCell();"
19542 " return e.toString();"
19545 "ReferenceError: cell is not defined");
19549 class Visitor42 : public v8::PersistentHandleVisitor {
19551 explicit Visitor42(v8::Persistent<v8::Object>* object)
19552 : counter_(0), object_(object) { }
19554 virtual void VisitPersistentHandle(Persistent<Value>* value,
19555 uint16_t class_id) {
19556 if (class_id != 42) return;
19557 CHECK_EQ(42, value->WrapperClassId());
19558 v8::Isolate* isolate = CcTest::isolate();
19559 v8::HandleScope handle_scope(isolate);
19560 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19561 v8::Handle<v8::Value> object =
19562 v8::Local<v8::Object>::New(isolate, *object_);
19563 CHECK(handle->IsObject());
19564 CHECK_EQ(Handle<Object>::Cast(handle), object);
19569 v8::Persistent<v8::Object>* object_;
19573 TEST(PersistentHandleVisitor) {
19574 LocalContext context;
19575 v8::Isolate* isolate = context->GetIsolate();
19576 v8::HandleScope scope(isolate);
19577 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19578 CHECK_EQ(0, object.WrapperClassId());
19579 object.SetWrapperClassId(42);
19580 CHECK_EQ(42, object.WrapperClassId());
19582 Visitor42 visitor(&object);
19583 v8::V8::VisitHandlesWithClassIds(&visitor);
19584 CHECK_EQ(1, visitor.counter_);
19590 TEST(WrapperClassId) {
19591 LocalContext context;
19592 v8::Isolate* isolate = context->GetIsolate();
19593 v8::HandleScope scope(isolate);
19594 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19595 CHECK_EQ(0, object.WrapperClassId());
19596 object.SetWrapperClassId(65535);
19597 CHECK_EQ(65535, object.WrapperClassId());
19602 TEST(PersistentHandleInNewSpaceVisitor) {
19603 LocalContext context;
19604 v8::Isolate* isolate = context->GetIsolate();
19605 v8::HandleScope scope(isolate);
19606 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19607 CHECK_EQ(0, object1.WrapperClassId());
19608 object1.SetWrapperClassId(42);
19609 CHECK_EQ(42, object1.WrapperClassId());
19611 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19613 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19614 CHECK_EQ(0, object2.WrapperClassId());
19615 object2.SetWrapperClassId(42);
19616 CHECK_EQ(42, object2.WrapperClassId());
19618 Visitor42 visitor(&object2);
19619 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19620 CHECK_EQ(1, visitor.counter_);
19628 LocalContext context;
19629 v8::HandleScope scope(context->GetIsolate());
19631 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19632 CHECK(re->IsRegExp());
19633 CHECK(re->GetSource()->Equals(v8_str("foo")));
19634 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19636 re = v8::RegExp::New(v8_str("bar"),
19637 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19638 v8::RegExp::kGlobal));
19639 CHECK(re->IsRegExp());
19640 CHECK(re->GetSource()->Equals(v8_str("bar")));
19641 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19642 static_cast<int>(re->GetFlags()));
19644 re = v8::RegExp::New(v8_str("baz"),
19645 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19646 v8::RegExp::kMultiline));
19647 CHECK(re->IsRegExp());
19648 CHECK(re->GetSource()->Equals(v8_str("baz")));
19649 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19650 static_cast<int>(re->GetFlags()));
19652 re = CompileRun("/quux/").As<v8::RegExp>();
19653 CHECK(re->IsRegExp());
19654 CHECK(re->GetSource()->Equals(v8_str("quux")));
19655 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19657 re = CompileRun("/quux/gm").As<v8::RegExp>();
19658 CHECK(re->IsRegExp());
19659 CHECK(re->GetSource()->Equals(v8_str("quux")));
19660 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19661 static_cast<int>(re->GetFlags()));
19663 // Override the RegExp constructor and check the API constructor
19665 CompileRun("RegExp = function() {}");
19667 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19668 CHECK(re->IsRegExp());
19669 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19670 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19672 re = v8::RegExp::New(v8_str("foobarbaz"),
19673 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19674 v8::RegExp::kMultiline));
19675 CHECK(re->IsRegExp());
19676 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19677 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19678 static_cast<int>(re->GetFlags()));
19680 context->Global()->Set(v8_str("re"), re);
19681 ExpectTrue("re.test('FoobarbaZ')");
19683 // RegExps are objects on which you can set properties.
19684 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19685 v8::Handle<v8::Value> value(CompileRun("re.property"));
19686 CHECK_EQ(32, value->Int32Value());
19688 v8::TryCatch try_catch;
19689 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19690 CHECK(re.IsEmpty());
19691 CHECK(try_catch.HasCaught());
19692 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19693 ExpectTrue("ex instanceof SyntaxError");
19697 THREADED_TEST(Equals) {
19698 LocalContext localContext;
19699 v8::HandleScope handleScope(localContext->GetIsolate());
19701 v8::Handle<v8::Object> globalProxy = localContext->Global();
19702 v8::Handle<Value> global = globalProxy->GetPrototype();
19704 CHECK(global->StrictEquals(global));
19705 CHECK(!global->StrictEquals(globalProxy));
19706 CHECK(!globalProxy->StrictEquals(global));
19707 CHECK(globalProxy->StrictEquals(globalProxy));
19709 CHECK(global->Equals(global));
19710 CHECK(!global->Equals(globalProxy));
19711 CHECK(!globalProxy->Equals(global));
19712 CHECK(globalProxy->Equals(globalProxy));
19716 static void Getter(v8::Local<v8::String> property,
19717 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19718 info.GetReturnValue().Set(v8_str("42!"));
19722 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19723 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19724 result->Set(0, v8_str("universalAnswer"));
19725 info.GetReturnValue().Set(result);
19729 TEST(NamedEnumeratorAndForIn) {
19730 LocalContext context;
19731 v8::Isolate* isolate = context->GetIsolate();
19732 v8::HandleScope handle_scope(isolate);
19733 v8::Context::Scope context_scope(context.local());
19735 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19736 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19737 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19738 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19739 "var result = []; for (var k in o) result.push(k); result"));
19740 CHECK_EQ(1, result->Length());
19741 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19745 TEST(DefinePropertyPostDetach) {
19746 LocalContext context;
19747 v8::HandleScope scope(context->GetIsolate());
19748 v8::Handle<v8::Object> proxy = context->Global();
19749 v8::Handle<v8::Function> define_property =
19750 CompileRun("(function() {"
19751 " Object.defineProperty("
19754 " { configurable: true, enumerable: true, value: 3 });"
19755 "})").As<Function>();
19756 context->DetachGlobal();
19757 define_property->Call(proxy, 0, NULL);
19761 static void InstallContextId(v8::Handle<Context> context, int id) {
19762 Context::Scope scope(context);
19763 CompileRun("Object.prototype").As<Object>()->
19764 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19768 static void CheckContextId(v8::Handle<Object> object, int expected) {
19769 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19773 THREADED_TEST(CreationContext) {
19774 v8::Isolate* isolate = CcTest::isolate();
19775 HandleScope handle_scope(isolate);
19776 Handle<Context> context1 = Context::New(isolate);
19777 InstallContextId(context1, 1);
19778 Handle<Context> context2 = Context::New(isolate);
19779 InstallContextId(context2, 2);
19780 Handle<Context> context3 = Context::New(isolate);
19781 InstallContextId(context3, 3);
19783 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19785 Local<Object> object1;
19786 Local<Function> func1;
19788 Context::Scope scope(context1);
19789 object1 = Object::New(isolate);
19790 func1 = tmpl->GetFunction();
19793 Local<Object> object2;
19794 Local<Function> func2;
19796 Context::Scope scope(context2);
19797 object2 = Object::New(isolate);
19798 func2 = tmpl->GetFunction();
19801 Local<Object> instance1;
19802 Local<Object> instance2;
19805 Context::Scope scope(context3);
19806 instance1 = func1->NewInstance();
19807 instance2 = func2->NewInstance();
19810 CHECK(object1->CreationContext() == context1);
19811 CheckContextId(object1, 1);
19812 CHECK(func1->CreationContext() == context1);
19813 CheckContextId(func1, 1);
19814 CHECK(instance1->CreationContext() == context1);
19815 CheckContextId(instance1, 1);
19816 CHECK(object2->CreationContext() == context2);
19817 CheckContextId(object2, 2);
19818 CHECK(func2->CreationContext() == context2);
19819 CheckContextId(func2, 2);
19820 CHECK(instance2->CreationContext() == context2);
19821 CheckContextId(instance2, 2);
19824 Context::Scope scope(context1);
19825 CHECK(object1->CreationContext() == context1);
19826 CheckContextId(object1, 1);
19827 CHECK(func1->CreationContext() == context1);
19828 CheckContextId(func1, 1);
19829 CHECK(instance1->CreationContext() == context1);
19830 CheckContextId(instance1, 1);
19831 CHECK(object2->CreationContext() == context2);
19832 CheckContextId(object2, 2);
19833 CHECK(func2->CreationContext() == context2);
19834 CheckContextId(func2, 2);
19835 CHECK(instance2->CreationContext() == context2);
19836 CheckContextId(instance2, 2);
19840 Context::Scope scope(context2);
19841 CHECK(object1->CreationContext() == context1);
19842 CheckContextId(object1, 1);
19843 CHECK(func1->CreationContext() == context1);
19844 CheckContextId(func1, 1);
19845 CHECK(instance1->CreationContext() == context1);
19846 CheckContextId(instance1, 1);
19847 CHECK(object2->CreationContext() == context2);
19848 CheckContextId(object2, 2);
19849 CHECK(func2->CreationContext() == context2);
19850 CheckContextId(func2, 2);
19851 CHECK(instance2->CreationContext() == context2);
19852 CheckContextId(instance2, 2);
19857 THREADED_TEST(CreationContextOfJsFunction) {
19858 HandleScope handle_scope(CcTest::isolate());
19859 Handle<Context> context = Context::New(CcTest::isolate());
19860 InstallContextId(context, 1);
19862 Local<Object> function;
19864 Context::Scope scope(context);
19865 function = CompileRun("function foo() {}; foo").As<Object>();
19868 CHECK(function->CreationContext() == context);
19869 CheckContextId(function, 1);
19873 void HasOwnPropertyIndexedPropertyGetter(
19875 const v8::PropertyCallbackInfo<v8::Value>& info) {
19876 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19880 void HasOwnPropertyNamedPropertyGetter(
19881 Local<String> property,
19882 const v8::PropertyCallbackInfo<v8::Value>& info) {
19883 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19887 void HasOwnPropertyIndexedPropertyQuery(
19888 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19889 if (index == 42) info.GetReturnValue().Set(1);
19893 void HasOwnPropertyNamedPropertyQuery(
19894 Local<String> property,
19895 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19896 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19900 void HasOwnPropertyNamedPropertyQuery2(
19901 Local<String> property,
19902 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19903 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19907 void HasOwnPropertyAccessorGetter(
19908 Local<String> property,
19909 const v8::PropertyCallbackInfo<v8::Value>& info) {
19910 info.GetReturnValue().Set(v8_str("yes"));
19914 TEST(HasOwnProperty) {
19916 v8::Isolate* isolate = env->GetIsolate();
19917 v8::HandleScope scope(isolate);
19918 { // Check normal properties and defined getters.
19919 Handle<Value> value = CompileRun(
19922 " this.__defineGetter__('baz', function() { return 1; });"
19924 "function Bar() { "
19926 " this.__defineGetter__('bla', function() { return 2; });"
19928 "Bar.prototype = new Foo();"
19930 CHECK(value->IsObject());
19931 Handle<Object> object = value->ToObject();
19932 CHECK(object->Has(v8_str("foo")));
19933 CHECK(!object->HasOwnProperty(v8_str("foo")));
19934 CHECK(object->HasOwnProperty(v8_str("bar")));
19935 CHECK(object->Has(v8_str("baz")));
19936 CHECK(!object->HasOwnProperty(v8_str("baz")));
19937 CHECK(object->HasOwnProperty(v8_str("bla")));
19939 { // Check named getter interceptors.
19940 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19941 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19942 Handle<Object> instance = templ->NewInstance();
19943 CHECK(!instance->HasOwnProperty(v8_str("42")));
19944 CHECK(instance->HasOwnProperty(v8_str("foo")));
19945 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19947 { // Check indexed getter interceptors.
19948 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19949 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
19950 Handle<Object> instance = templ->NewInstance();
19951 CHECK(instance->HasOwnProperty(v8_str("42")));
19952 CHECK(!instance->HasOwnProperty(v8_str("43")));
19953 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19955 { // Check named query interceptors.
19956 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19957 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
19958 Handle<Object> instance = templ->NewInstance();
19959 CHECK(instance->HasOwnProperty(v8_str("foo")));
19960 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19962 { // Check indexed query interceptors.
19963 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19964 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
19965 Handle<Object> instance = templ->NewInstance();
19966 CHECK(instance->HasOwnProperty(v8_str("42")));
19967 CHECK(!instance->HasOwnProperty(v8_str("41")));
19969 { // Check callbacks.
19970 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19971 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
19972 Handle<Object> instance = templ->NewInstance();
19973 CHECK(instance->HasOwnProperty(v8_str("foo")));
19974 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19976 { // Check that query wins on disagreement.
19977 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19978 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
19980 HasOwnPropertyNamedPropertyQuery2);
19981 Handle<Object> instance = templ->NewInstance();
19982 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19983 CHECK(instance->HasOwnProperty(v8_str("bar")));
19988 TEST(IndexedInterceptorWithStringProto) {
19989 v8::Isolate* isolate = CcTest::isolate();
19990 v8::HandleScope scope(isolate);
19991 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19992 templ->SetIndexedPropertyHandler(NULL,
19994 HasOwnPropertyIndexedPropertyQuery);
19995 LocalContext context;
19996 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19997 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
19998 // These should be intercepted.
19999 CHECK(CompileRun("42 in obj")->BooleanValue());
20000 CHECK(CompileRun("'42' in obj")->BooleanValue());
20001 // These should fall through to the String prototype.
20002 CHECK(CompileRun("0 in obj")->BooleanValue());
20003 CHECK(CompileRun("'0' in obj")->BooleanValue());
20004 // And these should both fail.
20005 CHECK(!CompileRun("32 in obj")->BooleanValue());
20006 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20010 void CheckCodeGenerationAllowed() {
20011 Handle<Value> result = CompileRun("eval('42')");
20012 CHECK_EQ(42, result->Int32Value());
20013 result = CompileRun("(function(e) { return e('42'); })(eval)");
20014 CHECK_EQ(42, result->Int32Value());
20015 result = CompileRun("var f = new Function('return 42'); f()");
20016 CHECK_EQ(42, result->Int32Value());
20020 void CheckCodeGenerationDisallowed() {
20021 TryCatch try_catch;
20023 Handle<Value> result = CompileRun("eval('42')");
20024 CHECK(result.IsEmpty());
20025 CHECK(try_catch.HasCaught());
20028 result = CompileRun("(function(e) { return e('42'); })(eval)");
20029 CHECK(result.IsEmpty());
20030 CHECK(try_catch.HasCaught());
20033 result = CompileRun("var f = new Function('return 42'); f()");
20034 CHECK(result.IsEmpty());
20035 CHECK(try_catch.HasCaught());
20039 bool CodeGenerationAllowed(Local<Context> context) {
20040 ApiTestFuzzer::Fuzz();
20045 bool CodeGenerationDisallowed(Local<Context> context) {
20046 ApiTestFuzzer::Fuzz();
20051 THREADED_TEST(AllowCodeGenFromStrings) {
20052 LocalContext context;
20053 v8::HandleScope scope(context->GetIsolate());
20055 // eval and the Function constructor allowed by default.
20056 CHECK(context->IsCodeGenerationFromStringsAllowed());
20057 CheckCodeGenerationAllowed();
20059 // Disallow eval and the Function constructor.
20060 context->AllowCodeGenerationFromStrings(false);
20061 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20062 CheckCodeGenerationDisallowed();
20065 context->AllowCodeGenerationFromStrings(true);
20066 CheckCodeGenerationAllowed();
20068 // Disallow but setting a global callback that will allow the calls.
20069 context->AllowCodeGenerationFromStrings(false);
20070 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20071 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20072 CheckCodeGenerationAllowed();
20074 // Set a callback that disallows the code generation.
20075 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20076 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20077 CheckCodeGenerationDisallowed();
20081 TEST(SetErrorMessageForCodeGenFromStrings) {
20082 LocalContext context;
20083 v8::HandleScope scope(context->GetIsolate());
20084 TryCatch try_catch;
20086 Handle<String> message = v8_str("Message") ;
20087 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20088 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20089 context->AllowCodeGenerationFromStrings(false);
20090 context->SetErrorMessageForCodeGenerationFromStrings(message);
20091 Handle<Value> result = CompileRun("eval('42')");
20092 CHECK(result.IsEmpty());
20093 CHECK(try_catch.HasCaught());
20094 Handle<String> actual_message = try_catch.Message()->Get();
20095 CHECK(expected_message->Equals(actual_message));
20099 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20103 THREADED_TEST(CallAPIFunctionOnNonObject) {
20104 LocalContext context;
20105 v8::Isolate* isolate = context->GetIsolate();
20106 v8::HandleScope scope(isolate);
20107 Handle<FunctionTemplate> templ =
20108 v8::FunctionTemplate::New(isolate, NonObjectThis);
20109 Handle<Function> function = templ->GetFunction();
20110 context->Global()->Set(v8_str("f"), function);
20111 TryCatch try_catch;
20112 CompileRun("f.call(2)");
20116 // Regression test for issue 1470.
20117 THREADED_TEST(ReadOnlyIndexedProperties) {
20118 v8::Isolate* isolate = CcTest::isolate();
20119 v8::HandleScope scope(isolate);
20120 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20122 LocalContext context;
20123 Local<v8::Object> obj = templ->NewInstance();
20124 context->Global()->Set(v8_str("obj"), obj);
20125 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20126 obj->Set(v8_str("1"), v8_str("foobar"));
20127 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20128 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20129 obj->Set(v8_num(2), v8_str("foobar"));
20130 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20132 // Test non-smi case.
20133 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20134 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20135 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20139 THREADED_TEST(Regress1516) {
20140 LocalContext context;
20141 v8::HandleScope scope(context->GetIsolate());
20143 { v8::HandleScope temp_scope(context->GetIsolate());
20144 CompileRun("({'a': 0})");
20148 { i::MapCache* map_cache =
20149 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20150 elements = map_cache->NumberOfElements();
20151 CHECK_LE(1, elements);
20154 CcTest::heap()->CollectAllGarbage(
20155 i::Heap::kAbortIncrementalMarkingMask);
20156 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20157 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20158 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20159 CHECK_GT(elements, map_cache->NumberOfElements());
20165 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20167 v8::AccessType type,
20168 Local<Value> data) {
20169 // Only block read access to __proto__.
20170 if (type == v8::ACCESS_GET &&
20171 name->IsString() &&
20172 name->ToString()->Length() == 9 &&
20173 name->ToString()->Utf8Length() == 9) {
20175 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20176 return strncmp(buffer, "__proto__", 9) != 0;
20183 THREADED_TEST(Regress93759) {
20184 v8::Isolate* isolate = CcTest::isolate();
20185 HandleScope scope(isolate);
20187 // Template for object with security check.
20188 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20189 // We don't do indexing, so any callback can be used for that.
20190 no_proto_template->SetAccessCheckCallbacks(
20191 BlockProtoNamedSecurityTestCallback,
20192 IndexedSecurityTestCallback);
20194 // Templates for objects with hidden prototypes and possibly security check.
20195 Local<FunctionTemplate> hidden_proto_template =
20196 v8::FunctionTemplate::New(isolate);
20197 hidden_proto_template->SetHiddenPrototype(true);
20199 Local<FunctionTemplate> protected_hidden_proto_template =
20200 v8::FunctionTemplate::New(isolate);
20201 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20202 BlockProtoNamedSecurityTestCallback,
20203 IndexedSecurityTestCallback);
20204 protected_hidden_proto_template->SetHiddenPrototype(true);
20206 // Context for "foreign" objects used in test.
20207 Local<Context> context = v8::Context::New(isolate);
20210 // Plain object, no security check.
20211 Local<Object> simple_object = Object::New(isolate);
20213 // Object with explicit security check.
20214 Local<Object> protected_object =
20215 no_proto_template->NewInstance();
20217 // JSGlobalProxy object, always have security check.
20218 Local<Object> proxy_object =
20221 // Global object, the prototype of proxy_object. No security checks.
20222 Local<Object> global_object =
20223 proxy_object->GetPrototype()->ToObject();
20225 // Hidden prototype without security check.
20226 Local<Object> hidden_prototype =
20227 hidden_proto_template->GetFunction()->NewInstance();
20228 Local<Object> object_with_hidden =
20229 Object::New(isolate);
20230 object_with_hidden->SetPrototype(hidden_prototype);
20232 // Hidden prototype with security check on the hidden prototype.
20233 Local<Object> protected_hidden_prototype =
20234 protected_hidden_proto_template->GetFunction()->NewInstance();
20235 Local<Object> object_with_protected_hidden =
20236 Object::New(isolate);
20237 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20241 // Template for object for second context. Values to test are put on it as
20243 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20244 global_template->Set(v8_str("simple"), simple_object);
20245 global_template->Set(v8_str("protected"), protected_object);
20246 global_template->Set(v8_str("global"), global_object);
20247 global_template->Set(v8_str("proxy"), proxy_object);
20248 global_template->Set(v8_str("hidden"), object_with_hidden);
20249 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20251 LocalContext context2(NULL, global_template);
20253 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20254 CHECK(result1->Equals(simple_object->GetPrototype()));
20256 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20257 CHECK(result2->Equals(Undefined(isolate)));
20259 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20260 CHECK(result3->Equals(global_object->GetPrototype()));
20262 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20263 CHECK(result4->Equals(Undefined(isolate)));
20265 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20266 CHECK(result5->Equals(
20267 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20269 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20270 CHECK(result6->Equals(Undefined(isolate)));
20274 THREADED_TEST(Regress125988) {
20275 v8::HandleScope scope(CcTest::isolate());
20276 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20277 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20279 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20280 CompileRun("var a = new Object();"
20281 "var b = new Intercept();"
20282 "var c = new Object();"
20286 "for (var i = 0; i < 3; i++) c.x;");
20287 ExpectBoolean("c.hasOwnProperty('x')", false);
20288 ExpectInt32("c.x", 23);
20289 CompileRun("a.y = 42;"
20290 "for (var i = 0; i < 3; i++) c.x;");
20291 ExpectBoolean("c.hasOwnProperty('x')", false);
20292 ExpectInt32("c.x", 23);
20293 ExpectBoolean("c.hasOwnProperty('y')", false);
20294 ExpectInt32("c.y", 42);
20298 static void TestReceiver(Local<Value> expected_result,
20299 Local<Value> expected_receiver,
20300 const char* code) {
20301 Local<Value> result = CompileRun(code);
20302 CHECK(result->IsObject());
20303 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20304 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20308 THREADED_TEST(ForeignFunctionReceiver) {
20309 v8::Isolate* isolate = CcTest::isolate();
20310 HandleScope scope(isolate);
20312 // Create two contexts with different "id" properties ('i' and 'o').
20313 // Call a function both from its own context and from a the foreign
20314 // context, and see what "this" is bound to (returning both "this"
20315 // and "this.id" for comparison).
20317 Local<Context> foreign_context = v8::Context::New(isolate);
20318 foreign_context->Enter();
20319 Local<Value> foreign_function =
20320 CompileRun("function func() { return { 0: this.id, "
20322 " toString: function() { "
20329 CHECK(foreign_function->IsFunction());
20330 foreign_context->Exit();
20332 LocalContext context;
20334 Local<String> password = v8_str("Password");
20335 // Don't get hit by security checks when accessing foreign_context's
20336 // global receiver (aka. global proxy).
20337 context->SetSecurityToken(password);
20338 foreign_context->SetSecurityToken(password);
20340 Local<String> i = v8_str("i");
20341 Local<String> o = v8_str("o");
20342 Local<String> id = v8_str("id");
20344 CompileRun("function ownfunc() { return { 0: this.id, "
20346 " toString: function() { "
20353 context->Global()->Set(v8_str("func"), foreign_function);
20355 // Sanity check the contexts.
20356 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20357 CHECK(o->Equals(context->Global()->Get(id)));
20359 // Checking local function's receiver.
20360 // Calling function using its call/apply methods.
20361 TestReceiver(o, context->Global(), "ownfunc.call()");
20362 TestReceiver(o, context->Global(), "ownfunc.apply()");
20363 // Making calls through built-in functions.
20364 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20365 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20366 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20367 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20368 // Calling with environment record as base.
20369 TestReceiver(o, context->Global(), "ownfunc()");
20370 // Calling with no base.
20371 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20373 // Checking foreign function return value.
20374 // Calling function using its call/apply methods.
20375 TestReceiver(i, foreign_context->Global(), "func.call()");
20376 TestReceiver(i, foreign_context->Global(), "func.apply()");
20377 // Calling function using another context's call/apply methods.
20378 TestReceiver(i, foreign_context->Global(),
20379 "Function.prototype.call.call(func)");
20380 TestReceiver(i, foreign_context->Global(),
20381 "Function.prototype.call.apply(func)");
20382 TestReceiver(i, foreign_context->Global(),
20383 "Function.prototype.apply.call(func)");
20384 TestReceiver(i, foreign_context->Global(),
20385 "Function.prototype.apply.apply(func)");
20386 // Making calls through built-in functions.
20387 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20388 // ToString(func()) is func()[0], i.e., the returned this.id.
20389 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20390 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20391 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20393 // Calling with environment record as base.
20394 TestReceiver(i, foreign_context->Global(), "func()");
20395 // Calling with no base.
20396 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20400 uint8_t callback_fired = 0;
20403 void CallCompletedCallback1() {
20404 i::OS::Print("Firing callback 1.\n");
20405 callback_fired ^= 1; // Toggle first bit.
20409 void CallCompletedCallback2() {
20410 i::OS::Print("Firing callback 2.\n");
20411 callback_fired ^= 2; // Toggle second bit.
20415 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20416 int32_t level = args[0]->Int32Value();
20419 i::OS::Print("Entering recursion level %d.\n", level);
20421 i::Vector<char> script_vector(script, sizeof(script));
20422 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20423 CompileRun(script_vector.start());
20424 i::OS::Print("Leaving recursion level %d.\n", level);
20425 CHECK_EQ(0, callback_fired);
20427 i::OS::Print("Recursion ends.\n");
20428 CHECK_EQ(0, callback_fired);
20433 TEST(CallCompletedCallback) {
20435 v8::HandleScope scope(env->GetIsolate());
20436 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20437 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20438 env->Global()->Set(v8_str("recursion"),
20439 recursive_runtime->GetFunction());
20440 // Adding the same callback a second time has no effect.
20441 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20442 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20443 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20444 i::OS::Print("--- Script (1) ---\n");
20445 Local<Script> script = v8::Script::Compile(
20446 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20448 CHECK_EQ(3, callback_fired);
20450 i::OS::Print("\n--- Script (2) ---\n");
20451 callback_fired = 0;
20452 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20454 CHECK_EQ(2, callback_fired);
20456 i::OS::Print("\n--- Function ---\n");
20457 callback_fired = 0;
20458 Local<Function> recursive_function =
20459 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20460 v8::Handle<Value> args[] = { v8_num(0) };
20461 recursive_function->Call(env->Global(), 1, args);
20462 CHECK_EQ(2, callback_fired);
20466 void CallCompletedCallbackNoException() {
20467 v8::HandleScope scope(CcTest::isolate());
20468 CompileRun("1+1;");
20472 void CallCompletedCallbackException() {
20473 v8::HandleScope scope(CcTest::isolate());
20474 CompileRun("throw 'second exception';");
20478 TEST(CallCompletedCallbackOneException) {
20480 v8::HandleScope scope(env->GetIsolate());
20481 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20482 CompileRun("throw 'exception';");
20486 TEST(CallCompletedCallbackTwoExceptions) {
20488 v8::HandleScope scope(env->GetIsolate());
20489 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20490 CompileRun("throw 'first exception';");
20494 static int probes_counter = 0;
20495 static int misses_counter = 0;
20496 static int updates_counter = 0;
20499 static int* LookupCounter(const char* name) {
20500 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20501 return &probes_counter;
20502 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20503 return &misses_counter;
20504 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20505 return &updates_counter;
20511 static const char* kMegamorphicTestProgram =
20512 "function ClassA() { };"
20513 "function ClassB() { };"
20514 "ClassA.prototype.foo = function() { };"
20515 "ClassB.prototype.foo = function() { };"
20516 "function fooify(obj) { obj.foo(); };"
20517 "var a = new ClassA();"
20518 "var b = new ClassB();"
20519 "for (var i = 0; i < 10000; i++) {"
20525 static void StubCacheHelper(bool primary) {
20526 V8::SetCounterFunction(LookupCounter);
20527 USE(kMegamorphicTestProgram);
20529 i::FLAG_native_code_counters = true;
20531 i::FLAG_test_primary_stub_cache = true;
20533 i::FLAG_test_secondary_stub_cache = true;
20535 i::FLAG_crankshaft = false;
20537 v8::HandleScope scope(env->GetIsolate());
20538 int initial_probes = probes_counter;
20539 int initial_misses = misses_counter;
20540 int initial_updates = updates_counter;
20541 CompileRun(kMegamorphicTestProgram);
20542 int probes = probes_counter - initial_probes;
20543 int misses = misses_counter - initial_misses;
20544 int updates = updates_counter - initial_updates;
20545 CHECK_LT(updates, 10);
20546 CHECK_LT(misses, 10);
20547 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20548 // before megamorphism. The number of probes will only work once we teach the
20549 // serializer to embed references to counters in the stubs, given that the
20550 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20551 CHECK_GE(probes, 0);
20556 TEST(SecondaryStubCache) {
20557 StubCacheHelper(true);
20561 TEST(PrimaryStubCache) {
20562 StubCacheHelper(false);
20566 static int cow_arrays_created_runtime = 0;
20569 static int* LookupCounterCOWArrays(const char* name) {
20570 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20571 return &cow_arrays_created_runtime;
20577 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20578 V8::SetCounterFunction(LookupCounterCOWArrays);
20580 i::FLAG_native_code_counters = true;
20582 v8::HandleScope scope(env->GetIsolate());
20583 int initial_cow_arrays = cow_arrays_created_runtime;
20584 CompileRun("var o = [1, 2, 3];");
20585 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20586 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20587 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20588 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20589 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20594 TEST(StaticGetters) {
20595 LocalContext context;
20596 i::Factory* factory = CcTest::i_isolate()->factory();
20597 v8::Isolate* isolate = CcTest::isolate();
20598 v8::HandleScope scope(isolate);
20599 i::Handle<i::Object> undefined_value = factory->undefined_value();
20600 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20601 i::Handle<i::Object> null_value = factory->null_value();
20602 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20603 i::Handle<i::Object> true_value = factory->true_value();
20604 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20605 i::Handle<i::Object> false_value = factory->false_value();
20606 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20610 UNINITIALIZED_TEST(IsolateEmbedderData) {
20611 CcTest::DisableAutomaticDispose();
20612 v8::Isolate* isolate = v8::Isolate::New();
20614 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20615 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20616 CHECK_EQ(NULL, isolate->GetData(slot));
20617 CHECK_EQ(NULL, i_isolate->GetData(slot));
20619 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20620 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20621 isolate->SetData(slot, data);
20623 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20624 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20625 CHECK_EQ(data, isolate->GetData(slot));
20626 CHECK_EQ(data, i_isolate->GetData(slot));
20628 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20629 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20630 isolate->SetData(slot, data);
20632 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20633 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20634 CHECK_EQ(data, isolate->GetData(slot));
20635 CHECK_EQ(data, i_isolate->GetData(slot));
20638 isolate->Dispose();
20642 TEST(StringEmpty) {
20643 LocalContext context;
20644 i::Factory* factory = CcTest::i_isolate()->factory();
20645 v8::Isolate* isolate = CcTest::isolate();
20646 v8::HandleScope scope(isolate);
20647 i::Handle<i::Object> empty_string = factory->empty_string();
20648 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20652 static int instance_checked_getter_count = 0;
20653 static void InstanceCheckedGetter(
20654 Local<String> name,
20655 const v8::PropertyCallbackInfo<v8::Value>& info) {
20656 CHECK_EQ(name, v8_str("foo"));
20657 instance_checked_getter_count++;
20658 info.GetReturnValue().Set(v8_num(11));
20662 static int instance_checked_setter_count = 0;
20663 static void InstanceCheckedSetter(Local<String> name,
20664 Local<Value> value,
20665 const v8::PropertyCallbackInfo<void>& info) {
20666 CHECK_EQ(name, v8_str("foo"));
20667 CHECK_EQ(value, v8_num(23));
20668 instance_checked_setter_count++;
20672 static void CheckInstanceCheckedResult(int getters,
20674 bool expects_callbacks,
20675 TryCatch* try_catch) {
20676 if (expects_callbacks) {
20677 CHECK(!try_catch->HasCaught());
20678 CHECK_EQ(getters, instance_checked_getter_count);
20679 CHECK_EQ(setters, instance_checked_setter_count);
20681 CHECK(try_catch->HasCaught());
20682 CHECK_EQ(0, instance_checked_getter_count);
20683 CHECK_EQ(0, instance_checked_setter_count);
20685 try_catch->Reset();
20689 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20690 instance_checked_getter_count = 0;
20691 instance_checked_setter_count = 0;
20692 TryCatch try_catch;
20694 // Test path through generic runtime code.
20695 CompileRun("obj.foo");
20696 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20697 CompileRun("obj.foo = 23");
20698 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20700 // Test path through generated LoadIC and StoredIC.
20701 CompileRun("function test_get(o) { o.foo; }"
20703 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20704 CompileRun("test_get(obj);");
20705 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20706 CompileRun("test_get(obj);");
20707 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20708 CompileRun("function test_set(o) { o.foo = 23; }"
20710 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20711 CompileRun("test_set(obj);");
20712 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20713 CompileRun("test_set(obj);");
20714 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20716 // Test path through optimized code.
20717 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20719 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20720 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20722 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20724 // Cleanup so that closures start out fresh in next check.
20725 CompileRun("%DeoptimizeFunction(test_get);"
20726 "%ClearFunctionTypeFeedback(test_get);"
20727 "%DeoptimizeFunction(test_set);"
20728 "%ClearFunctionTypeFeedback(test_set);");
20732 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20733 v8::internal::FLAG_allow_natives_syntax = true;
20734 LocalContext context;
20735 v8::HandleScope scope(context->GetIsolate());
20737 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20738 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20739 inst->SetAccessor(v8_str("foo"),
20740 InstanceCheckedGetter, InstanceCheckedSetter,
20744 v8::AccessorSignature::New(context->GetIsolate(), templ));
20745 context->Global()->Set(v8_str("f"), templ->GetFunction());
20747 printf("Testing positive ...\n");
20748 CompileRun("var obj = new f();");
20749 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20750 CheckInstanceCheckedAccessors(true);
20752 printf("Testing negative ...\n");
20753 CompileRun("var obj = {};"
20754 "obj.__proto__ = new f();");
20755 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20756 CheckInstanceCheckedAccessors(false);
20760 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20761 v8::internal::FLAG_allow_natives_syntax = true;
20762 LocalContext context;
20763 v8::HandleScope scope(context->GetIsolate());
20765 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20766 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20767 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20768 inst->SetAccessor(v8_str("foo"),
20769 InstanceCheckedGetter, InstanceCheckedSetter,
20773 v8::AccessorSignature::New(context->GetIsolate(), templ));
20774 context->Global()->Set(v8_str("f"), templ->GetFunction());
20776 printf("Testing positive ...\n");
20777 CompileRun("var obj = new f();");
20778 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20779 CheckInstanceCheckedAccessors(true);
20781 printf("Testing negative ...\n");
20782 CompileRun("var obj = {};"
20783 "obj.__proto__ = new f();");
20784 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20785 CheckInstanceCheckedAccessors(false);
20789 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20790 v8::internal::FLAG_allow_natives_syntax = true;
20791 LocalContext context;
20792 v8::HandleScope scope(context->GetIsolate());
20794 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20795 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20796 proto->SetAccessor(v8_str("foo"),
20797 InstanceCheckedGetter, InstanceCheckedSetter,
20801 v8::AccessorSignature::New(context->GetIsolate(), templ));
20802 context->Global()->Set(v8_str("f"), templ->GetFunction());
20804 printf("Testing positive ...\n");
20805 CompileRun("var obj = new f();");
20806 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20807 CheckInstanceCheckedAccessors(true);
20809 printf("Testing negative ...\n");
20810 CompileRun("var obj = {};"
20811 "obj.__proto__ = new f();");
20812 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20813 CheckInstanceCheckedAccessors(false);
20815 printf("Testing positive with modified prototype chain ...\n");
20816 CompileRun("var obj = new f();"
20818 "pro.__proto__ = obj.__proto__;"
20819 "obj.__proto__ = pro;");
20820 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20821 CheckInstanceCheckedAccessors(true);
20825 TEST(TryFinallyMessage) {
20826 LocalContext context;
20827 v8::HandleScope scope(context->GetIsolate());
20829 // Test that the original error message is not lost if there is a
20830 // recursive call into Javascript is done in the finally block, e.g. to
20831 // initialize an IC. (crbug.com/129171)
20832 TryCatch try_catch;
20833 const char* trigger_ic =
20835 " throw new Error('test'); \n"
20838 " x++; \n" // Trigger an IC initialization here.
20840 CompileRun(trigger_ic);
20841 CHECK(try_catch.HasCaught());
20842 Local<Message> message = try_catch.Message();
20843 CHECK(!message.IsEmpty());
20844 CHECK_EQ(2, message->GetLineNumber());
20848 // Test that the original exception message is indeed overwritten if
20849 // a new error is thrown in the finally block.
20850 TryCatch try_catch;
20851 const char* throw_again =
20853 " throw new Error('test'); \n"
20857 " throw new Error('again'); \n" // This is the new uncaught error.
20859 CompileRun(throw_again);
20860 CHECK(try_catch.HasCaught());
20861 Local<Message> message = try_catch.Message();
20862 CHECK(!message.IsEmpty());
20863 CHECK_EQ(6, message->GetLineNumber());
20868 static void Helper137002(bool do_store,
20870 bool remove_accessor,
20871 bool interceptor) {
20872 LocalContext context;
20873 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
20875 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20877 templ->SetAccessor(v8_str("foo"),
20878 GetterWhichReturns42,
20879 SetterWhichSetsYOnThisTo23);
20881 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20883 // Turn monomorphic on slow object with native accessor, then turn
20884 // polymorphic, finally optimize to create negative lookup and fail.
20885 CompileRun(do_store ?
20886 "function f(x) { x.foo = void 0; }" :
20887 "function f(x) { return x.foo; }");
20888 CompileRun("obj.y = void 0;");
20889 if (!interceptor) {
20890 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20892 CompileRun("obj.__proto__ = null;"
20893 "f(obj); f(obj); f(obj);");
20895 CompileRun("f({});");
20897 CompileRun("obj.y = void 0;"
20898 "%OptimizeFunctionOnNextCall(f);");
20899 if (remove_accessor) {
20900 CompileRun("delete obj.foo;");
20902 CompileRun("var result = f(obj);");
20904 CompileRun("result = obj.y;");
20906 if (remove_accessor && !interceptor) {
20907 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20909 CHECK_EQ(do_store ? 23 : 42,
20910 context->Global()->Get(v8_str("result"))->Int32Value());
20915 THREADED_TEST(Regress137002a) {
20916 i::FLAG_allow_natives_syntax = true;
20917 i::FLAG_compilation_cache = false;
20918 v8::HandleScope scope(CcTest::isolate());
20919 for (int i = 0; i < 16; i++) {
20920 Helper137002(i & 8, i & 4, i & 2, i & 1);
20925 THREADED_TEST(Regress137002b) {
20926 i::FLAG_allow_natives_syntax = true;
20927 LocalContext context;
20928 v8::Isolate* isolate = context->GetIsolate();
20929 v8::HandleScope scope(isolate);
20930 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20931 templ->SetAccessor(v8_str("foo"),
20932 GetterWhichReturns42,
20933 SetterWhichSetsYOnThisTo23);
20934 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20936 // Turn monomorphic on slow object with native accessor, then just
20937 // delete the property and fail.
20938 CompileRun("function load(x) { return x.foo; }"
20939 "function store(x) { x.foo = void 0; }"
20940 "function keyed_load(x, key) { return x[key]; }"
20941 // Second version of function has a different source (add void 0)
20942 // so that it does not share code with the first version. This
20943 // ensures that the ICs are monomorphic.
20944 "function load2(x) { void 0; return x.foo; }"
20945 "function store2(x) { void 0; x.foo = void 0; }"
20946 "function keyed_load2(x, key) { void 0; return x[key]; }"
20949 "obj.__proto__ = null;"
20951 "subobj.y = void 0;"
20952 "subobj.__proto__ = obj;"
20953 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20955 // Make the ICs monomorphic.
20956 "load(obj); load(obj);"
20957 "load2(subobj); load2(subobj);"
20958 "store(obj); store(obj);"
20959 "store2(subobj); store2(subobj);"
20960 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
20961 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
20963 // Actually test the shiny new ICs and better not crash. This
20964 // serves as a regression test for issue 142088 as well.
20969 "keyed_load(obj, 'foo');"
20970 "keyed_load2(subobj, 'foo');"
20972 // Delete the accessor. It better not be called any more now.
20975 "subobj.y = void 0;"
20977 "var load_result = load(obj);"
20978 "var load_result2 = load2(subobj);"
20979 "var keyed_load_result = keyed_load(obj, 'foo');"
20980 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
20983 "var y_from_obj = obj.y;"
20984 "var y_from_subobj = subobj.y;");
20985 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
20986 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
20987 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
20988 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
20989 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
20990 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
20994 THREADED_TEST(Regress142088) {
20995 i::FLAG_allow_natives_syntax = true;
20996 LocalContext context;
20997 v8::Isolate* isolate = context->GetIsolate();
20998 v8::HandleScope scope(isolate);
20999 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21000 templ->SetAccessor(v8_str("foo"),
21001 GetterWhichReturns42,
21002 SetterWhichSetsYOnThisTo23);
21003 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21005 CompileRun("function load(x) { return x.foo; }"
21006 "var o = Object.create(obj);"
21007 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21008 "load(o); load(o); load(o); load(o);");
21012 THREADED_TEST(Regress137496) {
21013 i::FLAG_expose_gc = true;
21014 LocalContext context;
21015 v8::HandleScope scope(context->GetIsolate());
21017 // Compile a try-finally clause where the finally block causes a GC
21018 // while there still is a message pending for external reporting.
21019 TryCatch try_catch;
21020 try_catch.SetVerbose(true);
21021 CompileRun("try { throw new Error(); } finally { gc(); }");
21022 CHECK(try_catch.HasCaught());
21026 THREADED_TEST(Regress149912) {
21027 LocalContext context;
21028 v8::HandleScope scope(context->GetIsolate());
21029 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21030 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21031 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21032 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21036 THREADED_TEST(Regress157124) {
21037 LocalContext context;
21038 v8::Isolate* isolate = context->GetIsolate();
21039 v8::HandleScope scope(isolate);
21040 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21041 Local<Object> obj = templ->NewInstance();
21042 obj->GetIdentityHash();
21043 obj->DeleteHiddenValue(v8_str("Bug"));
21047 THREADED_TEST(Regress2535) {
21048 i::FLAG_harmony_collections = true;
21049 LocalContext context;
21050 v8::HandleScope scope(context->GetIsolate());
21051 Local<Value> set_value = CompileRun("new Set();");
21052 Local<Object> set_object(Local<Object>::Cast(set_value));
21053 CHECK_EQ(0, set_object->InternalFieldCount());
21054 Local<Value> map_value = CompileRun("new Map();");
21055 Local<Object> map_object(Local<Object>::Cast(map_value));
21056 CHECK_EQ(0, map_object->InternalFieldCount());
21060 THREADED_TEST(Regress2746) {
21061 LocalContext context;
21062 v8::Isolate* isolate = context->GetIsolate();
21063 v8::HandleScope scope(isolate);
21064 Local<Object> obj = Object::New(isolate);
21065 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21066 obj->SetHiddenValue(key, v8::Undefined(isolate));
21067 Local<Value> value = obj->GetHiddenValue(key);
21068 CHECK(!value.IsEmpty());
21069 CHECK(value->IsUndefined());
21073 THREADED_TEST(Regress260106) {
21074 LocalContext context;
21075 v8::Isolate* isolate = context->GetIsolate();
21076 v8::HandleScope scope(isolate);
21077 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21079 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21080 Local<Function> function = templ->GetFunction();
21081 CHECK(!function.IsEmpty());
21082 CHECK(function->IsFunction());
21086 THREADED_TEST(JSONParseObject) {
21087 LocalContext context;
21088 HandleScope scope(context->GetIsolate());
21089 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21090 Handle<Object> global = context->Global();
21091 global->Set(v8_str("obj"), obj);
21092 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21096 THREADED_TEST(JSONParseNumber) {
21097 LocalContext context;
21098 HandleScope scope(context->GetIsolate());
21099 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21100 Handle<Object> global = context->Global();
21101 global->Set(v8_str("obj"), obj);
21102 ExpectString("JSON.stringify(obj)", "42");
21107 class ThreadInterruptTest {
21109 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21110 ~ThreadInterruptTest() {}
21113 InterruptThread i_thread(this);
21117 CHECK_EQ(kExpectedValue, sem_value_);
21121 static const int kExpectedValue = 1;
21123 class InterruptThread : public i::Thread {
21125 explicit InterruptThread(ThreadInterruptTest* test)
21126 : Thread("InterruptThread"), test_(test) {}
21128 virtual void Run() {
21129 struct sigaction action;
21131 // Ensure that we'll enter waiting condition
21134 // Setup signal handler
21135 memset(&action, 0, sizeof(action));
21136 action.sa_handler = SignalHandler;
21137 sigaction(SIGCHLD, &action, NULL);
21140 kill(getpid(), SIGCHLD);
21142 // Ensure that if wait has returned because of error
21145 // Set value and signal semaphore
21146 test_->sem_value_ = 1;
21147 test_->sem_.Signal();
21150 static void SignalHandler(int signal) {
21154 ThreadInterruptTest* test_;
21158 volatile int sem_value_;
21162 THREADED_TEST(SemaphoreInterruption) {
21163 ThreadInterruptTest().RunTest();
21167 #endif // V8_OS_POSIX
21170 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21172 v8::AccessType type,
21173 Local<Value> data) {
21174 i::PrintF("Named access blocked.\n");
21179 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21181 v8::AccessType type,
21182 Local<Value> data) {
21183 i::PrintF("Indexed access blocked.\n");
21188 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21193 TEST(JSONStringifyAccessCheck) {
21194 v8::V8::Initialize();
21195 v8::Isolate* isolate = CcTest::isolate();
21196 v8::HandleScope scope(isolate);
21198 // Create an ObjectTemplate for global objects and install access
21199 // check callbacks that will block access.
21200 v8::Handle<v8::ObjectTemplate> global_template =
21201 v8::ObjectTemplate::New(isolate);
21202 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21203 IndexAccessAlwaysBlocked);
21205 // Create a context and set an x property on it's global object.
21206 LocalContext context0(NULL, global_template);
21207 v8::Handle<v8::Object> global0 = context0->Global();
21208 global0->Set(v8_str("x"), v8_num(42));
21209 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21211 for (int i = 0; i < 2; i++) {
21213 // Install a toJSON function on the second run.
21214 v8::Handle<v8::FunctionTemplate> toJSON =
21215 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21217 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21219 // Create a context with a different security token so that the
21220 // failed access check callback will be called on each access.
21221 LocalContext context1(NULL, global_template);
21222 context1->Global()->Set(v8_str("other"), global0);
21224 ExpectString("JSON.stringify(other)", "{}");
21225 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21226 "{\"a\":{},\"b\":[\"c\"]}");
21227 ExpectString("JSON.stringify([other, 'b', 'c'])",
21228 "[{},\"b\",\"c\"]");
21230 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21231 array->Set(0, v8_str("a"));
21232 array->Set(1, v8_str("b"));
21233 context1->Global()->Set(v8_str("array"), array);
21234 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21235 array->TurnOnAccessCheck();
21236 ExpectString("JSON.stringify(array)", "[]");
21237 ExpectString("JSON.stringify([array])", "[[]]");
21238 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21243 bool access_check_fail_thrown = false;
21244 bool catch_callback_called = false;
21247 // Failed access check callback that performs a GC on each invocation.
21248 void FailedAccessCheckThrows(Local<v8::Object> target,
21249 v8::AccessType type,
21250 Local<v8::Value> data) {
21251 access_check_fail_thrown = true;
21252 i::PrintF("Access check failed. Error thrown.\n");
21253 CcTest::isolate()->ThrowException(
21254 v8::Exception::Error(v8_str("cross context")));
21258 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21259 for (int i = 0; i < args.Length(); i++) {
21260 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21262 catch_callback_called = true;
21266 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21267 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21271 void CheckCorrectThrow(const char* script) {
21272 // Test that the script, when wrapped into a try-catch, triggers the catch
21273 // clause due to failed access check throwing an exception.
21274 // The subsequent try-catch should run without any exception.
21275 access_check_fail_thrown = false;
21276 catch_callback_called = false;
21277 i::ScopedVector<char> source(1024);
21278 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21279 CompileRun(source.start());
21280 CHECK(access_check_fail_thrown);
21281 CHECK(catch_callback_called);
21283 access_check_fail_thrown = false;
21284 catch_callback_called = false;
21285 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21286 CHECK(!access_check_fail_thrown);
21287 CHECK(!catch_callback_called);
21291 TEST(AccessCheckThrows) {
21292 i::FLAG_allow_natives_syntax = true;
21293 v8::V8::Initialize();
21294 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21295 v8::Isolate* isolate = CcTest::isolate();
21296 v8::HandleScope scope(isolate);
21298 // Create an ObjectTemplate for global objects and install access
21299 // check callbacks that will block access.
21300 v8::Handle<v8::ObjectTemplate> global_template =
21301 v8::ObjectTemplate::New(isolate);
21302 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21303 IndexAccessAlwaysBlocked);
21305 // Create a context and set an x property on it's global object.
21306 LocalContext context0(NULL, global_template);
21307 context0->Global()->Set(v8_str("x"), v8_num(42));
21308 v8::Handle<v8::Object> global0 = context0->Global();
21310 // Create a context with a different security token so that the
21311 // failed access check callback will be called on each access.
21312 LocalContext context1(NULL, global_template);
21313 context1->Global()->Set(v8_str("other"), global0);
21315 v8::Handle<v8::FunctionTemplate> catcher_fun =
21316 v8::FunctionTemplate::New(isolate, CatcherCallback);
21317 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21319 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21320 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21321 context1->Global()->Set(v8_str("has_own_property"),
21322 has_own_property_fun->GetFunction());
21324 { v8::TryCatch try_catch;
21325 access_check_fail_thrown = false;
21326 CompileRun("other.x;");
21327 CHECK(access_check_fail_thrown);
21328 CHECK(try_catch.HasCaught());
21331 CheckCorrectThrow("other.x");
21332 CheckCorrectThrow("other[1]");
21333 CheckCorrectThrow("JSON.stringify(other)");
21334 CheckCorrectThrow("has_own_property(other, 'x')");
21335 CheckCorrectThrow("%GetProperty(other, 'x')");
21336 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21337 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21338 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21339 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21340 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21341 CheckCorrectThrow("%HasProperty(other, 'x')");
21342 CheckCorrectThrow("%HasElement(other, 1)");
21343 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21344 CheckCorrectThrow("%GetPropertyNames(other)");
21345 // PROPERTY_ATTRIBUTES_NONE = 0
21346 CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21347 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21348 "other, 'x', null, null, 1)");
21350 // Reset the failed access check callback so it does not influence
21351 // the other tests.
21352 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21356 THREADED_TEST(Regress256330) {
21357 i::FLAG_allow_natives_syntax = true;
21358 LocalContext context;
21359 v8::HandleScope scope(context->GetIsolate());
21360 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21361 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21362 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21363 CompileRun("\"use strict\"; var o = new Bug;"
21364 "function f(o) { o.x = 10; };"
21365 "f(o); f(o); f(o);"
21366 "%OptimizeFunctionOnNextCall(f);"
21368 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21372 THREADED_TEST(CrankshaftInterceptorSetter) {
21373 i::FLAG_allow_natives_syntax = true;
21374 v8::HandleScope scope(CcTest::isolate());
21375 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21376 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21378 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21379 CompileRun("var obj = new Obj;"
21380 // Initialize fields to avoid transitions later.
21382 "obj.accessor_age = 42;"
21383 "function setter(i) { this.accessor_age = i; };"
21384 "function getter() { return this.accessor_age; };"
21385 "function setAge(i) { obj.age = i; };"
21386 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21390 "%OptimizeFunctionOnNextCall(setAge);"
21392 // All stores went through the interceptor.
21393 ExpectInt32("obj.interceptor_age", 4);
21394 ExpectInt32("obj.accessor_age", 42);
21398 THREADED_TEST(CrankshaftInterceptorGetter) {
21399 i::FLAG_allow_natives_syntax = true;
21400 v8::HandleScope scope(CcTest::isolate());
21401 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21402 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21404 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21405 CompileRun("var obj = new Obj;"
21406 // Initialize fields to avoid transitions later.
21408 "obj.accessor_age = 42;"
21409 "function getter() { return this.accessor_age; };"
21410 "function getAge() { return obj.interceptor_age; };"
21411 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21415 "%OptimizeFunctionOnNextCall(getAge);");
21416 // Access through interceptor.
21417 ExpectInt32("getAge()", 1);
21421 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21422 i::FLAG_allow_natives_syntax = true;
21423 v8::HandleScope scope(CcTest::isolate());
21424 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21425 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21427 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21428 CompileRun("var obj = new Obj;"
21429 "obj.__proto__.interceptor_age = 42;"
21431 "function getAge() { return obj.interceptor_age; };");
21432 ExpectInt32("getAge();", 100);
21433 ExpectInt32("getAge();", 100);
21434 ExpectInt32("getAge();", 100);
21435 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21436 // Access through interceptor.
21437 ExpectInt32("getAge();", 100);
21441 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21442 i::FLAG_allow_natives_syntax = true;
21443 v8::HandleScope scope(CcTest::isolate());
21444 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21445 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21447 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21448 CompileRun("var obj = new Obj;"
21449 "obj.age = 100000;"
21450 "function setAge(i) { obj.age = i };"
21454 "%OptimizeFunctionOnNextCall(setAge);"
21456 ExpectInt32("obj.age", 100000);
21457 ExpectInt32("obj.interceptor_age", 103);
21461 class RequestInterruptTestBase {
21463 RequestInterruptTestBase()
21465 isolate_(env_->GetIsolate()),
21468 should_continue_(true) {
21471 virtual ~RequestInterruptTestBase() { }
21473 virtual void TestBody() = 0;
21476 InterruptThread i_thread(this);
21479 v8::HandleScope handle_scope(isolate_);
21483 isolate_->ClearInterrupt();
21485 // Verify we arrived here because interruptor was called
21486 // not due to a bug causing us to exit the loop too early.
21487 CHECK(!should_continue());
21490 void WakeUpInterruptor() {
21494 bool should_continue() const { return should_continue_; }
21496 bool ShouldContinue() {
21498 if (--warmup_ == 0) {
21499 WakeUpInterruptor();
21503 return should_continue_;
21507 static void ShouldContinueCallback(
21508 const v8::FunctionCallbackInfo<Value>& info) {
21509 RequestInterruptTestBase* test =
21510 reinterpret_cast<RequestInterruptTestBase*>(
21511 info.Data().As<v8::External>()->Value());
21512 info.GetReturnValue().Set(test->ShouldContinue());
21515 class InterruptThread : public i::Thread {
21517 explicit InterruptThread(RequestInterruptTestBase* test)
21518 : Thread("RequestInterruptTest"), test_(test) {}
21520 virtual void Run() {
21521 test_->sem_.Wait();
21522 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21525 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21526 reinterpret_cast<RequestInterruptTestBase*>(data)->
21527 should_continue_ = false;
21531 RequestInterruptTestBase* test_;
21535 v8::Isolate* isolate_;
21538 bool should_continue_;
21542 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21544 virtual void TestBody() {
21545 Local<Function> func = Function::New(
21546 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21547 env_->Global()->Set(v8_str("ShouldContinue"), func);
21549 CompileRun("while (ShouldContinue()) { }");
21554 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21556 virtual void TestBody() {
21557 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21558 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21559 proto->Set(v8_str("shouldContinue"), Function::New(
21560 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21561 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21563 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21568 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21570 virtual void TestBody() {
21571 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21572 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21573 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21574 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21575 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21577 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21582 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21584 virtual void TestBody() {
21585 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21586 t->InstanceTemplate()->SetNativeDataProperty(
21587 v8_str("shouldContinue"),
21588 &ShouldContinueNativeGetter,
21590 v8::External::New(isolate_, this));
21591 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21593 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21597 static void ShouldContinueNativeGetter(
21598 Local<String> property,
21599 const v8::PropertyCallbackInfo<v8::Value>& info) {
21600 RequestInterruptTestBase* test =
21601 reinterpret_cast<RequestInterruptTestBase*>(
21602 info.Data().As<v8::External>()->Value());
21603 info.GetReturnValue().Set(test->ShouldContinue());
21608 class RequestInterruptTestWithMethodCallAndInterceptor
21609 : public RequestInterruptTestBase {
21611 virtual void TestBody() {
21612 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21613 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21614 proto->Set(v8_str("shouldContinue"), Function::New(
21615 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21616 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21617 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21619 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21621 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21625 static void EmptyInterceptor(
21626 Local<String> property,
21627 const v8::PropertyCallbackInfo<v8::Value>& info) {
21632 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21634 virtual void TestBody() {
21635 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21637 WakeUpInterruptorCallback,
21638 v8::External::New(isolate_, this)));
21640 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21642 ShouldContinueCallback,
21643 v8::External::New(isolate_, this)));
21645 i::FLAG_allow_natives_syntax = true;
21646 CompileRun("function loopish(o) {"
21648 " while (o.abs(1) > 0) {"
21649 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21651 " if (--pre === 0) WakeUpInterruptor(o === Math);"
21656 "var obj = {abs: function () { return i-- }, x: null};"
21659 "%OptimizeFunctionOnNextCall(loopish);"
21662 i::FLAG_allow_natives_syntax = false;
21666 static void WakeUpInterruptorCallback(
21667 const v8::FunctionCallbackInfo<Value>& info) {
21668 if (!info[0]->BooleanValue()) return;
21670 RequestInterruptTestBase* test =
21671 reinterpret_cast<RequestInterruptTestBase*>(
21672 info.Data().As<v8::External>()->Value());
21673 test->WakeUpInterruptor();
21676 static void ShouldContinueCallback(
21677 const v8::FunctionCallbackInfo<Value>& info) {
21678 RequestInterruptTestBase* test =
21679 reinterpret_cast<RequestInterruptTestBase*>(
21680 info.Data().As<v8::External>()->Value());
21681 info.GetReturnValue().Set(test->should_continue());
21686 TEST(RequestInterruptTestWithFunctionCall) {
21687 RequestInterruptTestWithFunctionCall().RunTest();
21691 TEST(RequestInterruptTestWithMethodCall) {
21692 RequestInterruptTestWithMethodCall().RunTest();
21696 TEST(RequestInterruptTestWithAccessor) {
21697 RequestInterruptTestWithAccessor().RunTest();
21701 TEST(RequestInterruptTestWithNativeAccessor) {
21702 RequestInterruptTestWithNativeAccessor().RunTest();
21706 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21707 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21711 TEST(RequestInterruptTestWithMathAbs) {
21712 RequestInterruptTestWithMathAbs().RunTest();
21716 static Local<Value> function_new_expected_env;
21717 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21718 CHECK_EQ(function_new_expected_env, info.Data());
21719 info.GetReturnValue().Set(17);
21723 THREADED_TEST(FunctionNew) {
21725 v8::Isolate* isolate = env->GetIsolate();
21726 v8::HandleScope scope(isolate);
21727 Local<Object> data = v8::Object::New(isolate);
21728 function_new_expected_env = data;
21729 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21730 env->Global()->Set(v8_str("func"), func);
21731 Local<Value> result = CompileRun("func();");
21732 CHECK_EQ(v8::Integer::New(isolate, 17), result);
21733 // Verify function not cached
21734 int serial_number =
21735 i::Smi::cast(v8::Utils::OpenHandle(*func)
21736 ->shared()->get_api_func_data()->serial_number())->value();
21737 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21738 i::Object* elm = i_isolate->native_context()->function_cache()
21739 ->GetElementNoExceptionThrown(i_isolate, serial_number);
21740 CHECK(elm->IsUndefined());
21741 // Verify that each Function::New creates a new function instance
21742 Local<Object> data2 = v8::Object::New(isolate);
21743 function_new_expected_env = data2;
21744 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21745 CHECK(!func2->IsNull());
21746 CHECK_NE(func, func2);
21747 env->Global()->Set(v8_str("func2"), func2);
21748 Local<Value> result2 = CompileRun("func2();");
21749 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21753 TEST(EscapeableHandleScope) {
21754 HandleScope outer_scope(CcTest::isolate());
21755 LocalContext context;
21756 const int runs = 10;
21757 Local<String> values[runs];
21758 for (int i = 0; i < runs; i++) {
21759 v8::EscapableHandleScope inner_scope(CcTest::isolate());
21760 Local<String> value;
21761 if (i != 0) value = v8_str("escape value");
21762 values[i] = inner_scope.Escape(value);
21764 for (int i = 0; i < runs; i++) {
21765 Local<String> expected;
21767 CHECK_EQ(v8_str("escape value"), values[i]);
21769 CHECK(values[i].IsEmpty());
21775 static void SetterWhichExpectsThisAndHolderToDiffer(
21776 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21777 CHECK(info.Holder() != info.This());
21781 TEST(Regress239669) {
21782 LocalContext context;
21783 v8::Isolate* isolate = context->GetIsolate();
21784 v8::HandleScope scope(isolate);
21785 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21786 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21787 context->Global()->Set(v8_str("P"), templ->NewInstance());
21792 "C1.prototype = P;"
21793 "for (var i = 0; i < 4; i++ ) {"
21799 class ApiCallOptimizationChecker {
21801 static Local<Object> data;
21802 static Local<Object> receiver;
21803 static Local<Object> holder;
21804 static Local<Object> callee;
21807 static void OptimizationCallback(
21808 const v8::FunctionCallbackInfo<v8::Value>& info) {
21809 CHECK(callee == info.Callee());
21810 CHECK(data == info.Data());
21811 CHECK(receiver == info.This());
21812 if (info.Length() == 1) {
21813 CHECK_EQ(v8_num(1), info[0]);
21815 CHECK(holder == info.Holder());
21819 // TODO(dcarney): move this to v8.h
21820 static void SetAccessorProperty(Local<Object> object,
21821 Local<String> name,
21822 Local<Function> getter,
21823 Local<Function> setter = Local<Function>()) {
21824 i::Isolate* isolate = CcTest::i_isolate();
21825 v8::AccessControl settings = v8::DEFAULT;
21826 v8::PropertyAttribute attribute = v8::None;
21827 i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
21828 i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
21829 if (setter_i.is_null()) setter_i = isolate->factory()->null_value();
21830 i::JSObject::DefineAccessor(v8::Utils::OpenHandle(*object),
21831 v8::Utils::OpenHandle(*name),
21834 static_cast<PropertyAttributes>(attribute),
21839 void Run(bool use_signature, bool global) {
21840 v8::Isolate* isolate = CcTest::isolate();
21841 v8::HandleScope scope(isolate);
21842 // Build a template for signature checks.
21843 Local<v8::ObjectTemplate> signature_template;
21844 Local<v8::Signature> signature;
21846 Local<v8::FunctionTemplate> parent_template =
21847 FunctionTemplate::New(isolate);
21848 parent_template->SetHiddenPrototype(true);
21849 Local<v8::FunctionTemplate> function_template
21850 = FunctionTemplate::New(isolate);
21851 function_template->Inherit(parent_template);
21852 if (use_signature) {
21853 signature = v8::Signature::New(isolate, parent_template);
21855 signature_template = function_template->InstanceTemplate();
21857 // Global object must pass checks.
21858 Local<v8::Context> context =
21859 v8::Context::New(isolate, NULL, signature_template);
21860 v8::Context::Scope context_scope(context);
21861 // Install regular object that can pass signature checks.
21862 Local<Object> function_receiver = signature_template->NewInstance();
21863 context->Global()->Set(v8_str("function_receiver"), function_receiver);
21864 // Get the holder objects.
21865 Local<Object> inner_global =
21866 Local<Object>::Cast(context->Global()->GetPrototype());
21867 Local<Object> function_holder =
21868 Local<Object>::Cast(function_receiver->GetPrototype());
21869 // Install function on hidden prototype object.
21870 data = Object::New(isolate);
21871 Local<FunctionTemplate> function_template = FunctionTemplate::New(
21872 isolate, OptimizationCallback, data, signature);
21873 Local<Function> function = function_template->GetFunction();
21874 Local<Object> global_holder = Local<Object>::Cast(
21875 inner_global->GetPrototype());
21876 global_holder->Set(v8_str("g_f"), function);
21877 SetAccessorProperty(global_holder, v8_str("g_acc"), function, function);
21878 function_holder->Set(v8_str("f"), function);
21879 SetAccessorProperty(function_holder, v8_str("acc"), function, function);
21880 // Initialize expected values.
21884 receiver = context->Global();
21885 holder = inner_global;
21887 holder = function_receiver;
21888 // If not using a signature, add something else to the prototype chain
21889 // to test the case that holder != receiver
21890 if (!use_signature) {
21891 receiver = Local<Object>::Cast(CompileRun(
21892 "var receiver_subclass = {};\n"
21893 "receiver_subclass.__proto__ = function_receiver;\n"
21894 "receiver_subclass"));
21896 receiver = Local<Object>::Cast(CompileRun(
21897 "var receiver_subclass = function_receiver;\n"
21898 "receiver_subclass"));
21901 // With no signature, the holder is not set.
21902 if (!use_signature) holder = receiver;
21903 // build wrap_function
21904 int key = (use_signature ? 1 : 0) + 2 * (global ? 1 : 0);
21905 i::ScopedVector<char> wrap_function(200);
21909 "function wrap_f_%d() { var f = g_f; return f(); }\n"
21910 "function wrap_get_%d() { return this.g_acc; }\n"
21911 "function wrap_set_%d() { this.g_acc = 1; }\n",
21916 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
21917 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
21918 "function wrap_set_%d() { receiver_subclass.acc = 1; }\n",
21921 // build source string
21922 i::ScopedVector<char> source(500);
21925 "%s\n" // wrap functions
21926 "function wrap_f() { wrap_f_%d(); }\n"
21927 "function wrap_get() { wrap_get_%d(); }\n"
21928 "function wrap_set() { wrap_set_%d(); }\n"
21932 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
21937 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
21942 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
21944 wrap_function.start(), key, key, key, key, key, key);
21945 v8::TryCatch try_catch;
21946 CompileRun(source.start());
21947 ASSERT(!try_catch.HasCaught());
21948 CHECK_EQ(9, count);
21953 Local<Object> ApiCallOptimizationChecker::data;
21954 Local<Object> ApiCallOptimizationChecker::receiver;
21955 Local<Object> ApiCallOptimizationChecker::holder;
21956 Local<Object> ApiCallOptimizationChecker::callee;
21957 int ApiCallOptimizationChecker::count = 0;
21960 TEST(TestFunctionCallOptimization) {
21961 i::FLAG_allow_natives_syntax = true;
21962 ApiCallOptimizationChecker checker;
21963 checker.Run(true, true);
21964 checker.Run(false, true);
21965 checker.Run(true, false);
21966 checker.Run(false, false);