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 explicit TestResource(uint16_t* data, int* counter = NULL)
466 : data_(data), length_(0), counter_(counter) {
467 while (data[length_]) ++length_;
471 i::DeleteArray(data_);
472 if (counter_ != NULL) ++*counter_;
475 const uint16_t* data() const {
479 size_t length() const {
489 class TestAsciiResource: public String::ExternalAsciiStringResource {
491 explicit TestAsciiResource(const char* data, int* counter = NULL)
492 : data_(data), length_(strlen(data)), counter_(counter) { }
494 ~TestAsciiResource() {
495 i::DeleteArray(data_);
496 if (counter_ != NULL) ++*counter_;
499 const char* data() const {
503 size_t length() const {
513 THREADED_TEST(ScriptUsingStringResource) {
514 int dispose_count = 0;
515 const char* c_source = "1 + 2 * 3";
516 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
519 v8::HandleScope scope(env->GetIsolate());
520 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
521 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
522 Local<Script> script = Script::Compile(source);
523 Local<Value> value = script->Run();
524 CHECK(value->IsNumber());
525 CHECK_EQ(7, value->Int32Value());
526 CHECK(source->IsExternal());
528 static_cast<TestResource*>(source->GetExternalStringResource()));
529 String::Encoding encoding = String::UNKNOWN_ENCODING;
530 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
531 source->GetExternalStringResourceBase(&encoding));
532 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
533 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
534 CHECK_EQ(0, dispose_count);
536 CcTest::i_isolate()->compilation_cache()->Clear();
537 CcTest::heap()->CollectAllAvailableGarbage();
538 CHECK_EQ(1, dispose_count);
542 THREADED_TEST(ScriptUsingAsciiStringResource) {
543 int dispose_count = 0;
544 const char* c_source = "1 + 2 * 3";
547 v8::HandleScope scope(env->GetIsolate());
548 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
550 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
551 CHECK(source->IsExternalAscii());
552 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
553 source->GetExternalAsciiStringResource());
554 String::Encoding encoding = String::UNKNOWN_ENCODING;
555 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
556 source->GetExternalStringResourceBase(&encoding));
557 CHECK_EQ(String::ASCII_ENCODING, encoding);
558 Local<Script> script = Script::Compile(source);
559 Local<Value> value = script->Run();
560 CHECK(value->IsNumber());
561 CHECK_EQ(7, value->Int32Value());
562 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
563 CHECK_EQ(0, dispose_count);
565 CcTest::i_isolate()->compilation_cache()->Clear();
566 CcTest::heap()->CollectAllAvailableGarbage();
567 CHECK_EQ(1, dispose_count);
571 THREADED_TEST(ScriptMakingExternalString) {
572 int dispose_count = 0;
573 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
576 v8::HandleScope scope(env->GetIsolate());
577 Local<String> source =
578 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
579 // Trigger GCs so that the newly allocated string moves to old gen.
580 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
581 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
582 CHECK_EQ(source->IsExternal(), false);
583 CHECK_EQ(source->IsExternalAscii(), false);
584 String::Encoding encoding = String::UNKNOWN_ENCODING;
585 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
586 CHECK_EQ(String::ASCII_ENCODING, encoding);
587 bool success = source->MakeExternal(new TestResource(two_byte_source,
590 Local<Script> script = Script::Compile(source);
591 Local<Value> value = script->Run();
592 CHECK(value->IsNumber());
593 CHECK_EQ(7, value->Int32Value());
594 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
595 CHECK_EQ(0, dispose_count);
597 CcTest::i_isolate()->compilation_cache()->Clear();
598 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
599 CHECK_EQ(1, dispose_count);
603 THREADED_TEST(ScriptMakingExternalAsciiString) {
604 int dispose_count = 0;
605 const char* c_source = "1 + 2 * 3";
608 v8::HandleScope scope(env->GetIsolate());
609 Local<String> source = v8_str(c_source);
610 // Trigger GCs so that the newly allocated string moves to old gen.
611 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
612 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
613 bool success = source->MakeExternal(
614 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
616 Local<Script> script = Script::Compile(source);
617 Local<Value> value = script->Run();
618 CHECK(value->IsNumber());
619 CHECK_EQ(7, value->Int32Value());
620 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
621 CHECK_EQ(0, dispose_count);
623 CcTest::i_isolate()->compilation_cache()->Clear();
624 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
625 CHECK_EQ(1, dispose_count);
629 TEST(MakingExternalStringConditions) {
631 v8::HandleScope scope(env->GetIsolate());
633 // Free some space in the new space so that we can check freshness.
634 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
635 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
637 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
638 Local<String> small_string =
639 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
640 i::DeleteArray(two_byte_string);
642 // We should refuse to externalize newly created small string.
643 CHECK(!small_string->CanMakeExternal());
644 // Trigger GCs so that the newly allocated string moves to old gen.
645 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
647 // Old space strings should be accepted.
648 CHECK(small_string->CanMakeExternal());
650 two_byte_string = AsciiToTwoByteString("small string 2");
651 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
652 i::DeleteArray(two_byte_string);
654 // We should refuse externalizing newly created small string.
655 CHECK(!small_string->CanMakeExternal());
656 for (int i = 0; i < 100; i++) {
657 String::Value value(small_string);
659 // Frequently used strings should be accepted.
660 CHECK(small_string->CanMakeExternal());
662 const int buf_size = 10 * 1024;
663 char* buf = i::NewArray<char>(buf_size);
664 memset(buf, 'a', buf_size);
665 buf[buf_size - 1] = '\0';
667 two_byte_string = AsciiToTwoByteString(buf);
668 Local<String> large_string =
669 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
671 i::DeleteArray(two_byte_string);
672 // Large strings should be immediately accepted.
673 CHECK(large_string->CanMakeExternal());
677 TEST(MakingExternalAsciiStringConditions) {
679 v8::HandleScope scope(env->GetIsolate());
681 // Free some space in the new space so that we can check freshness.
682 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
683 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
685 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
686 // We should refuse to externalize newly created small string.
687 CHECK(!small_string->CanMakeExternal());
688 // Trigger GCs so that the newly allocated string moves to old gen.
689 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
690 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
691 // Old space strings should be accepted.
692 CHECK(small_string->CanMakeExternal());
694 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
695 // We should refuse externalizing newly created small string.
696 CHECK(!small_string->CanMakeExternal());
697 for (int i = 0; i < 100; i++) {
698 String::Value value(small_string);
700 // Frequently used strings should be accepted.
701 CHECK(small_string->CanMakeExternal());
703 const int buf_size = 10 * 1024;
704 char* buf = i::NewArray<char>(buf_size);
705 memset(buf, 'a', buf_size);
706 buf[buf_size - 1] = '\0';
707 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
709 // Large strings should be immediately accepted.
710 CHECK(large_string->CanMakeExternal());
714 TEST(MakingExternalUnalignedAsciiString) {
716 v8::HandleScope scope(env->GetIsolate());
718 CompileRun("function cons(a, b) { return a + b; }"
719 "function slice(a) { return a.substring(1); }");
720 // Create a cons string that will land in old pointer space.
721 Local<String> cons = Local<String>::Cast(CompileRun(
722 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
723 // Create a sliced string that will land in old pointer space.
724 Local<String> slice = Local<String>::Cast(CompileRun(
725 "slice('abcdefghijklmnopqrstuvwxyz');"));
727 // Trigger GCs so that the newly allocated string moves to old gen.
728 SimulateFullSpace(CcTest::heap()->old_pointer_space());
729 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
730 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
732 // Turn into external string with unaligned resource data.
733 int dispose_count = 0;
734 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
735 bool success = cons->MakeExternal(
736 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
738 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
739 success = slice->MakeExternal(
740 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
743 // Trigger GCs and force evacuation.
744 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
745 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
749 THREADED_TEST(UsingExternalString) {
750 i::Factory* factory = CcTest::i_isolate()->factory();
752 v8::HandleScope scope(CcTest::isolate());
753 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
754 Local<String> string = String::NewExternal(
755 CcTest::isolate(), new TestResource(two_byte_string));
756 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
757 // Trigger GCs so that the newly allocated string moves to old gen.
758 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
759 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
760 i::Handle<i::String> isymbol =
761 factory->InternalizedStringFromString(istring);
762 CHECK(isymbol->IsInternalizedString());
764 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
765 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
769 THREADED_TEST(UsingExternalAsciiString) {
770 i::Factory* factory = CcTest::i_isolate()->factory();
772 v8::HandleScope scope(CcTest::isolate());
773 const char* one_byte_string = "test string";
774 Local<String> string = String::NewExternal(
775 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
776 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
777 // Trigger GCs so that the newly allocated string moves to old gen.
778 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
779 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
780 i::Handle<i::String> isymbol =
781 factory->InternalizedStringFromString(istring);
782 CHECK(isymbol->IsInternalizedString());
784 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
785 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
789 THREADED_TEST(ScavengeExternalString) {
790 i::FLAG_stress_compaction = false;
791 i::FLAG_gc_global = false;
792 int dispose_count = 0;
793 bool in_new_space = false;
795 v8::HandleScope scope(CcTest::isolate());
796 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
797 Local<String> string = String::NewExternal(
798 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
799 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
800 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
801 in_new_space = CcTest::heap()->InNewSpace(*istring);
802 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
803 CHECK_EQ(0, dispose_count);
805 CcTest::heap()->CollectGarbage(
806 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
807 CHECK_EQ(1, dispose_count);
811 THREADED_TEST(ScavengeExternalAsciiString) {
812 i::FLAG_stress_compaction = false;
813 i::FLAG_gc_global = false;
814 int dispose_count = 0;
815 bool in_new_space = false;
817 v8::HandleScope scope(CcTest::isolate());
818 const char* one_byte_string = "test string";
819 Local<String> string = String::NewExternal(
821 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
822 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
823 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
824 in_new_space = CcTest::heap()->InNewSpace(*istring);
825 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
826 CHECK_EQ(0, dispose_count);
828 CcTest::heap()->CollectGarbage(
829 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
830 CHECK_EQ(1, dispose_count);
834 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
836 // Only used by non-threaded tests, so it can use static fields.
837 static int dispose_calls;
838 static int dispose_count;
840 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
841 : TestAsciiResource(data, &dispose_count),
842 dispose_(dispose) { }
846 if (dispose_) delete this;
853 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
854 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
857 TEST(ExternalStringWithDisposeHandling) {
858 const char* c_source = "1 + 2 * 3";
860 // Use a stack allocated external string resource allocated object.
861 TestAsciiResourceWithDisposeControl::dispose_count = 0;
862 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
863 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
866 v8::HandleScope scope(env->GetIsolate());
867 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
868 Local<Script> script = Script::Compile(source);
869 Local<Value> value = script->Run();
870 CHECK(value->IsNumber());
871 CHECK_EQ(7, value->Int32Value());
872 CcTest::heap()->CollectAllAvailableGarbage();
873 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
875 CcTest::i_isolate()->compilation_cache()->Clear();
876 CcTest::heap()->CollectAllAvailableGarbage();
877 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
878 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
880 // Use a heap allocated external string resource allocated object.
881 TestAsciiResourceWithDisposeControl::dispose_count = 0;
882 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
883 TestAsciiResource* res_heap =
884 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
887 v8::HandleScope scope(env->GetIsolate());
888 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
889 Local<Script> script = Script::Compile(source);
890 Local<Value> value = script->Run();
891 CHECK(value->IsNumber());
892 CHECK_EQ(7, value->Int32Value());
893 CcTest::heap()->CollectAllAvailableGarbage();
894 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
896 CcTest::i_isolate()->compilation_cache()->Clear();
897 CcTest::heap()->CollectAllAvailableGarbage();
898 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
899 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
903 THREADED_TEST(StringConcat) {
906 v8::HandleScope scope(env->GetIsolate());
907 const char* one_byte_string_1 = "function a_times_t";
908 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
909 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
910 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
911 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
912 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
913 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
914 Local<String> left = v8_str(one_byte_string_1);
916 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
917 Local<String> right =
918 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
919 i::DeleteArray(two_byte_source);
921 Local<String> source = String::Concat(left, right);
922 right = String::NewExternal(
923 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
924 source = String::Concat(source, right);
925 right = String::NewExternal(
927 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
928 source = String::Concat(source, right);
929 right = v8_str(one_byte_string_2);
930 source = String::Concat(source, right);
932 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
933 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
934 i::DeleteArray(two_byte_source);
936 source = String::Concat(source, right);
937 right = String::NewExternal(
939 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
940 source = String::Concat(source, right);
941 Local<Script> script = Script::Compile(source);
942 Local<Value> value = script->Run();
943 CHECK(value->IsNumber());
944 CHECK_EQ(68, value->Int32Value());
946 CcTest::i_isolate()->compilation_cache()->Clear();
947 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
948 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
952 THREADED_TEST(GlobalProperties) {
954 v8::HandleScope scope(env->GetIsolate());
955 v8::Handle<v8::Object> global = env->Global();
956 global->Set(v8_str("pi"), v8_num(3.1415926));
957 Local<Value> pi = global->Get(v8_str("pi"));
958 CHECK_EQ(3.1415926, pi->NumberValue());
963 static void CheckReturnValue(const T& t, i::Address callback) {
964 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
965 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
966 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
967 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
968 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
970 bool is_runtime = (*o)->IsTheHole();
972 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
973 rv.Set(v8::Handle<v8::Object>());
974 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
975 CHECK_EQ(is_runtime, (*o)->IsTheHole());
977 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
978 // If CPU profiler is active check that when API callback is invoked
979 // VMState is set to EXTERNAL.
980 if (isolate->cpu_profiler()->is_profiling()) {
981 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
982 CHECK(isolate->external_callback_scope());
983 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
988 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
989 i::Address callback) {
990 ApiTestFuzzer::Fuzz();
991 CheckReturnValue(info, callback);
992 info.GetReturnValue().Set(v8_str("bad value"));
993 info.GetReturnValue().Set(v8_num(102));
997 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
998 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1002 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1003 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1006 static void construct_callback(
1007 const v8::FunctionCallbackInfo<Value>& info) {
1008 ApiTestFuzzer::Fuzz();
1009 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1010 info.This()->Set(v8_str("x"), v8_num(1));
1011 info.This()->Set(v8_str("y"), v8_num(2));
1012 info.GetReturnValue().Set(v8_str("bad value"));
1013 info.GetReturnValue().Set(info.This());
1017 static void Return239Callback(
1018 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1019 ApiTestFuzzer::Fuzz();
1020 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1021 info.GetReturnValue().Set(v8_str("bad value"));
1022 info.GetReturnValue().Set(v8_num(239));
1026 template<typename Handler>
1027 static void TestFunctionTemplateInitializer(Handler handler,
1028 Handler handler_2) {
1029 // Test constructor calls.
1032 v8::Isolate* isolate = env->GetIsolate();
1033 v8::HandleScope scope(isolate);
1035 Local<v8::FunctionTemplate> fun_templ =
1036 v8::FunctionTemplate::New(isolate, handler);
1037 Local<Function> fun = fun_templ->GetFunction();
1038 env->Global()->Set(v8_str("obj"), fun);
1039 Local<Script> script = v8_compile("obj()");
1040 for (int i = 0; i < 30; i++) {
1041 CHECK_EQ(102, script->Run()->Int32Value());
1044 // Use SetCallHandler to initialize a function template, should work like
1045 // the previous one.
1048 v8::Isolate* isolate = env->GetIsolate();
1049 v8::HandleScope scope(isolate);
1051 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1052 fun_templ->SetCallHandler(handler_2);
1053 Local<Function> fun = fun_templ->GetFunction();
1054 env->Global()->Set(v8_str("obj"), fun);
1055 Local<Script> script = v8_compile("obj()");
1056 for (int i = 0; i < 30; i++) {
1057 CHECK_EQ(102, script->Run()->Int32Value());
1063 template<typename Constructor, typename Accessor>
1064 static void TestFunctionTemplateAccessor(Constructor constructor,
1065 Accessor accessor) {
1067 v8::HandleScope scope(env->GetIsolate());
1069 Local<v8::FunctionTemplate> fun_templ =
1070 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1071 fun_templ->SetClassName(v8_str("funky"));
1072 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1073 Local<Function> fun = fun_templ->GetFunction();
1074 env->Global()->Set(v8_str("obj"), fun);
1075 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1076 CHECK_EQ(v8_str("[object funky]"), result);
1077 CompileRun("var obj_instance = new obj();");
1078 Local<Script> script;
1079 script = v8_compile("obj_instance.x");
1080 for (int i = 0; i < 30; i++) {
1081 CHECK_EQ(1, script->Run()->Int32Value());
1083 script = v8_compile("obj_instance.m");
1084 for (int i = 0; i < 30; i++) {
1085 CHECK_EQ(239, script->Run()->Int32Value());
1090 THREADED_PROFILED_TEST(FunctionTemplate) {
1091 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1092 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1096 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1097 ApiTestFuzzer::Fuzz();
1098 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1099 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1103 template<typename Callback>
1104 static void TestSimpleCallback(Callback callback) {
1106 v8::Isolate* isolate = env->GetIsolate();
1107 v8::HandleScope scope(isolate);
1109 v8::Handle<v8::ObjectTemplate> object_template =
1110 v8::ObjectTemplate::New(isolate);
1111 object_template->Set(isolate, "callback",
1112 v8::FunctionTemplate::New(isolate, callback));
1113 v8::Local<v8::Object> object = object_template->NewInstance();
1114 (*env)->Global()->Set(v8_str("callback_object"), object);
1115 v8::Handle<v8::Script> script;
1116 script = v8_compile("callback_object.callback(17)");
1117 for (int i = 0; i < 30; i++) {
1118 CHECK_EQ(51424, script->Run()->Int32Value());
1120 script = v8_compile("callback_object.callback(17, 24)");
1121 for (int i = 0; i < 30; i++) {
1122 CHECK_EQ(51425, script->Run()->Int32Value());
1127 THREADED_PROFILED_TEST(SimpleCallback) {
1128 TestSimpleCallback(SimpleCallback);
1132 template<typename T>
1133 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1135 // constant return values
1136 static int32_t fast_return_value_int32 = 471;
1137 static uint32_t fast_return_value_uint32 = 571;
1138 static const double kFastReturnValueDouble = 2.7;
1139 // variable return values
1140 static bool fast_return_value_bool = false;
1141 enum ReturnValueOddball {
1143 kUndefinedReturnValue,
1144 kEmptyStringReturnValue
1146 static ReturnValueOddball fast_return_value_void;
1147 static bool fast_return_value_object_is_empty = false;
1149 // Helper function to avoid compiler error: insufficient contextual information
1150 // to determine type when applying FUNCTION_ADDR to a template function.
1151 static i::Address address_of(v8::FunctionCallback callback) {
1152 return FUNCTION_ADDR(callback);
1156 void FastReturnValueCallback<int32_t>(
1157 const v8::FunctionCallbackInfo<v8::Value>& info) {
1158 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1159 info.GetReturnValue().Set(fast_return_value_int32);
1163 void FastReturnValueCallback<uint32_t>(
1164 const v8::FunctionCallbackInfo<v8::Value>& info) {
1165 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1166 info.GetReturnValue().Set(fast_return_value_uint32);
1170 void FastReturnValueCallback<double>(
1171 const v8::FunctionCallbackInfo<v8::Value>& info) {
1172 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1173 info.GetReturnValue().Set(kFastReturnValueDouble);
1177 void FastReturnValueCallback<bool>(
1178 const v8::FunctionCallbackInfo<v8::Value>& info) {
1179 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1180 info.GetReturnValue().Set(fast_return_value_bool);
1184 void FastReturnValueCallback<void>(
1185 const v8::FunctionCallbackInfo<v8::Value>& info) {
1186 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1187 switch (fast_return_value_void) {
1188 case kNullReturnValue:
1189 info.GetReturnValue().SetNull();
1191 case kUndefinedReturnValue:
1192 info.GetReturnValue().SetUndefined();
1194 case kEmptyStringReturnValue:
1195 info.GetReturnValue().SetEmptyString();
1201 void FastReturnValueCallback<Object>(
1202 const v8::FunctionCallbackInfo<v8::Value>& info) {
1203 v8::Handle<v8::Object> object;
1204 if (!fast_return_value_object_is_empty) {
1205 object = Object::New(info.GetIsolate());
1207 info.GetReturnValue().Set(object);
1210 template<typename T>
1211 Handle<Value> TestFastReturnValues() {
1213 v8::Isolate* isolate = env->GetIsolate();
1214 v8::EscapableHandleScope scope(isolate);
1215 v8::Handle<v8::ObjectTemplate> object_template =
1216 v8::ObjectTemplate::New(isolate);
1217 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1218 object_template->Set(isolate, "callback",
1219 v8::FunctionTemplate::New(isolate, callback));
1220 v8::Local<v8::Object> object = object_template->NewInstance();
1221 (*env)->Global()->Set(v8_str("callback_object"), object);
1222 return scope.Escape(CompileRun("callback_object.callback()"));
1226 THREADED_PROFILED_TEST(FastReturnValues) {
1228 v8::HandleScope scope(CcTest::isolate());
1229 v8::Handle<v8::Value> value;
1230 // check int32_t and uint32_t
1231 int32_t int_values[] = {
1233 i::Smi::kMinValue, i::Smi::kMaxValue
1235 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1236 for (int modifier = -1; modifier <= 1; modifier++) {
1237 int int_value = int_values[i] + modifier;
1239 fast_return_value_int32 = int_value;
1240 value = TestFastReturnValues<int32_t>();
1241 CHECK(value->IsInt32());
1242 CHECK(fast_return_value_int32 == value->Int32Value());
1244 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1245 value = TestFastReturnValues<uint32_t>();
1246 CHECK(value->IsUint32());
1247 CHECK(fast_return_value_uint32 == value->Uint32Value());
1251 value = TestFastReturnValues<double>();
1252 CHECK(value->IsNumber());
1253 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1254 // check bool values
1255 for (int i = 0; i < 2; i++) {
1256 fast_return_value_bool = i == 0;
1257 value = TestFastReturnValues<bool>();
1258 CHECK(value->IsBoolean());
1259 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1262 ReturnValueOddball oddballs[] = {
1264 kUndefinedReturnValue,
1265 kEmptyStringReturnValue
1267 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1268 fast_return_value_void = oddballs[i];
1269 value = TestFastReturnValues<void>();
1270 switch (fast_return_value_void) {
1271 case kNullReturnValue:
1272 CHECK(value->IsNull());
1274 case kUndefinedReturnValue:
1275 CHECK(value->IsUndefined());
1277 case kEmptyStringReturnValue:
1278 CHECK(value->IsString());
1279 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1284 fast_return_value_object_is_empty = false;
1285 value = TestFastReturnValues<Object>();
1286 CHECK(value->IsObject());
1287 fast_return_value_object_is_empty = true;
1288 value = TestFastReturnValues<Object>();
1289 CHECK(value->IsUndefined());
1293 THREADED_TEST(FunctionTemplateSetLength) {
1295 v8::Isolate* isolate = env->GetIsolate();
1296 v8::HandleScope scope(isolate);
1298 Local<v8::FunctionTemplate> fun_templ =
1299 v8::FunctionTemplate::New(isolate,
1301 Handle<v8::Value>(),
1302 Handle<v8::Signature>(),
1304 Local<Function> fun = fun_templ->GetFunction();
1305 env->Global()->Set(v8_str("obj"), fun);
1306 Local<Script> script = v8_compile("obj.length");
1307 CHECK_EQ(23, script->Run()->Int32Value());
1310 Local<v8::FunctionTemplate> fun_templ =
1311 v8::FunctionTemplate::New(isolate, handle_callback);
1312 fun_templ->SetLength(22);
1313 Local<Function> fun = fun_templ->GetFunction();
1314 env->Global()->Set(v8_str("obj"), fun);
1315 Local<Script> script = v8_compile("obj.length");
1316 CHECK_EQ(22, script->Run()->Int32Value());
1319 // Without setting length it defaults to 0.
1320 Local<v8::FunctionTemplate> fun_templ =
1321 v8::FunctionTemplate::New(isolate, handle_callback);
1322 Local<Function> fun = fun_templ->GetFunction();
1323 env->Global()->Set(v8_str("obj"), fun);
1324 Local<Script> script = v8_compile("obj.length");
1325 CHECK_EQ(0, script->Run()->Int32Value());
1330 static void* expected_ptr;
1331 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1332 void* ptr = v8::External::Cast(*args.Data())->Value();
1333 CHECK_EQ(expected_ptr, ptr);
1334 args.GetReturnValue().Set(true);
1338 static void TestExternalPointerWrapping() {
1340 v8::Isolate* isolate = env->GetIsolate();
1341 v8::HandleScope scope(isolate);
1343 v8::Handle<v8::Value> data =
1344 v8::External::New(isolate, expected_ptr);
1346 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1347 obj->Set(v8_str("func"),
1348 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1349 env->Global()->Set(v8_str("obj"), obj);
1352 "function foo() {\n"
1353 " for (var i = 0; i < 13; i++) obj.func();\n"
1355 "foo(), true")->BooleanValue());
1359 THREADED_TEST(ExternalWrap) {
1360 // Check heap allocated object.
1363 TestExternalPointerWrapping();
1366 // Check stack allocated object.
1368 expected_ptr = &foo;
1369 TestExternalPointerWrapping();
1371 // Check not aligned addresses.
1373 char* s = new char[n];
1374 for (int i = 0; i < n; i++) {
1375 expected_ptr = s + i;
1376 TestExternalPointerWrapping();
1381 // Check several invalid addresses.
1382 expected_ptr = reinterpret_cast<void*>(1);
1383 TestExternalPointerWrapping();
1385 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1386 TestExternalPointerWrapping();
1388 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1389 TestExternalPointerWrapping();
1391 #if defined(V8_HOST_ARCH_X64)
1392 // Check a value with a leading 1 bit in x64 Smi encoding.
1393 expected_ptr = reinterpret_cast<void*>(0x400000000);
1394 TestExternalPointerWrapping();
1396 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1397 TestExternalPointerWrapping();
1399 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1400 TestExternalPointerWrapping();
1405 THREADED_TEST(FindInstanceInPrototypeChain) {
1407 v8::Isolate* isolate = env->GetIsolate();
1408 v8::HandleScope scope(isolate);
1410 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1411 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1412 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1413 derived->Inherit(base);
1415 Local<v8::Function> base_function = base->GetFunction();
1416 Local<v8::Function> derived_function = derived->GetFunction();
1417 Local<v8::Function> other_function = other->GetFunction();
1419 Local<v8::Object> base_instance = base_function->NewInstance();
1420 Local<v8::Object> derived_instance = derived_function->NewInstance();
1421 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1422 Local<v8::Object> other_instance = other_function->NewInstance();
1423 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1424 other_instance->Set(v8_str("__proto__"), derived_instance2);
1426 // base_instance is only an instance of base.
1427 CHECK_EQ(base_instance,
1428 base_instance->FindInstanceInPrototypeChain(base));
1429 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1430 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1432 // derived_instance is an instance of base and derived.
1433 CHECK_EQ(derived_instance,
1434 derived_instance->FindInstanceInPrototypeChain(base));
1435 CHECK_EQ(derived_instance,
1436 derived_instance->FindInstanceInPrototypeChain(derived));
1437 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1439 // other_instance is an instance of other and its immediate
1440 // prototype derived_instance2 is an instance of base and derived.
1441 // Note, derived_instance is an instance of base and derived too,
1442 // but it comes after derived_instance2 in the prototype chain of
1444 CHECK_EQ(derived_instance2,
1445 other_instance->FindInstanceInPrototypeChain(base));
1446 CHECK_EQ(derived_instance2,
1447 other_instance->FindInstanceInPrototypeChain(derived));
1448 CHECK_EQ(other_instance,
1449 other_instance->FindInstanceInPrototypeChain(other));
1453 THREADED_TEST(TinyInteger) {
1455 v8::Isolate* isolate = env->GetIsolate();
1456 v8::HandleScope scope(isolate);
1458 int32_t value = 239;
1459 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1460 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462 value_obj = v8::Integer::New(isolate, value);
1463 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467 THREADED_TEST(BigSmiInteger) {
1469 v8::HandleScope scope(env->GetIsolate());
1470 v8::Isolate* isolate = CcTest::isolate();
1472 int32_t value = i::Smi::kMaxValue;
1473 // We cannot add one to a Smi::kMaxValue without wrapping.
1474 if (i::SmiValuesAre31Bits()) {
1475 CHECK(i::Smi::IsValid(value));
1476 CHECK(!i::Smi::IsValid(value + 1));
1478 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1479 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1481 value_obj = v8::Integer::New(isolate, value);
1482 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1487 THREADED_TEST(BigInteger) {
1489 v8::HandleScope scope(env->GetIsolate());
1490 v8::Isolate* isolate = CcTest::isolate();
1492 // We cannot add one to a Smi::kMaxValue without wrapping.
1493 if (i::SmiValuesAre31Bits()) {
1494 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1495 // The code will not be run in that case, due to the "if" guard.
1497 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1498 CHECK(value > i::Smi::kMaxValue);
1499 CHECK(!i::Smi::IsValid(value));
1501 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1502 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1504 value_obj = v8::Integer::New(isolate, value);
1505 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1510 THREADED_TEST(TinyUnsignedInteger) {
1512 v8::HandleScope scope(env->GetIsolate());
1513 v8::Isolate* isolate = CcTest::isolate();
1515 uint32_t value = 239;
1517 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1518 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1520 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1521 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525 THREADED_TEST(BigUnsignedSmiInteger) {
1527 v8::HandleScope scope(env->GetIsolate());
1528 v8::Isolate* isolate = CcTest::isolate();
1530 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1531 CHECK(i::Smi::IsValid(value));
1532 CHECK(!i::Smi::IsValid(value + 1));
1534 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1535 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1537 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1538 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1542 THREADED_TEST(BigUnsignedInteger) {
1544 v8::HandleScope scope(env->GetIsolate());
1545 v8::Isolate* isolate = CcTest::isolate();
1547 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1548 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1549 CHECK(!i::Smi::IsValid(value));
1551 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1552 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1554 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1555 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1559 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1561 v8::HandleScope scope(env->GetIsolate());
1562 v8::Isolate* isolate = CcTest::isolate();
1564 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1565 uint32_t value = INT32_MAX_AS_UINT + 1;
1566 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1568 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1569 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1571 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1572 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576 THREADED_TEST(IsNativeError) {
1578 v8::HandleScope scope(env->GetIsolate());
1579 v8::Handle<Value> syntax_error = CompileRun(
1580 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1581 CHECK(syntax_error->IsNativeError());
1582 v8::Handle<Value> not_error = CompileRun("{a:42}");
1583 CHECK(!not_error->IsNativeError());
1584 v8::Handle<Value> not_object = CompileRun("42");
1585 CHECK(!not_object->IsNativeError());
1589 THREADED_TEST(StringObject) {
1591 v8::HandleScope scope(env->GetIsolate());
1592 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1593 CHECK(boxed_string->IsStringObject());
1594 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1595 CHECK(!unboxed_string->IsStringObject());
1596 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1597 CHECK(!boxed_not_string->IsStringObject());
1598 v8::Handle<Value> not_object = CompileRun("0");
1599 CHECK(!not_object->IsStringObject());
1600 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1601 CHECK(!as_boxed.IsEmpty());
1602 Local<v8::String> the_string = as_boxed->ValueOf();
1603 CHECK(!the_string.IsEmpty());
1604 ExpectObject("\"test\"", the_string);
1605 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1606 CHECK(new_boxed_string->IsStringObject());
1607 as_boxed = new_boxed_string.As<v8::StringObject>();
1608 the_string = as_boxed->ValueOf();
1609 CHECK(!the_string.IsEmpty());
1610 ExpectObject("\"test\"", the_string);
1614 THREADED_TEST(NumberObject) {
1616 v8::HandleScope scope(env->GetIsolate());
1617 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1618 CHECK(boxed_number->IsNumberObject());
1619 v8::Handle<Value> unboxed_number = CompileRun("42");
1620 CHECK(!unboxed_number->IsNumberObject());
1621 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1622 CHECK(!boxed_not_number->IsNumberObject());
1623 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1624 CHECK(!as_boxed.IsEmpty());
1625 double the_number = as_boxed->ValueOf();
1626 CHECK_EQ(42.0, the_number);
1627 v8::Handle<v8::Value> new_boxed_number =
1628 v8::NumberObject::New(env->GetIsolate(), 43);
1629 CHECK(new_boxed_number->IsNumberObject());
1630 as_boxed = new_boxed_number.As<v8::NumberObject>();
1631 the_number = as_boxed->ValueOf();
1632 CHECK_EQ(43.0, the_number);
1636 THREADED_TEST(BooleanObject) {
1638 v8::HandleScope scope(env->GetIsolate());
1639 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1640 CHECK(boxed_boolean->IsBooleanObject());
1641 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1642 CHECK(!unboxed_boolean->IsBooleanObject());
1643 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1644 CHECK(!boxed_not_boolean->IsBooleanObject());
1645 v8::Handle<v8::BooleanObject> as_boxed =
1646 boxed_boolean.As<v8::BooleanObject>();
1647 CHECK(!as_boxed.IsEmpty());
1648 bool the_boolean = as_boxed->ValueOf();
1649 CHECK_EQ(true, the_boolean);
1650 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1651 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1652 CHECK(boxed_true->IsBooleanObject());
1653 CHECK(boxed_false->IsBooleanObject());
1654 as_boxed = boxed_true.As<v8::BooleanObject>();
1655 CHECK_EQ(true, as_boxed->ValueOf());
1656 as_boxed = boxed_false.As<v8::BooleanObject>();
1657 CHECK_EQ(false, as_boxed->ValueOf());
1661 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1663 v8::HandleScope scope(env->GetIsolate());
1665 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1666 CHECK(primitive_false->IsBoolean());
1667 CHECK(!primitive_false->IsBooleanObject());
1668 CHECK(!primitive_false->BooleanValue());
1669 CHECK(!primitive_false->IsTrue());
1670 CHECK(primitive_false->IsFalse());
1672 Local<Value> false_value = BooleanObject::New(false);
1673 CHECK(!false_value->IsBoolean());
1674 CHECK(false_value->IsBooleanObject());
1675 CHECK(false_value->BooleanValue());
1676 CHECK(!false_value->IsTrue());
1677 CHECK(!false_value->IsFalse());
1679 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1680 CHECK(!false_boolean_object->IsBoolean());
1681 CHECK(false_boolean_object->IsBooleanObject());
1682 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1683 // CHECK(false_boolean_object->BooleanValue());
1684 CHECK(!false_boolean_object->ValueOf());
1685 CHECK(!false_boolean_object->IsTrue());
1686 CHECK(!false_boolean_object->IsFalse());
1688 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1689 CHECK(primitive_true->IsBoolean());
1690 CHECK(!primitive_true->IsBooleanObject());
1691 CHECK(primitive_true->BooleanValue());
1692 CHECK(primitive_true->IsTrue());
1693 CHECK(!primitive_true->IsFalse());
1695 Local<Value> true_value = BooleanObject::New(true);
1696 CHECK(!true_value->IsBoolean());
1697 CHECK(true_value->IsBooleanObject());
1698 CHECK(true_value->BooleanValue());
1699 CHECK(!true_value->IsTrue());
1700 CHECK(!true_value->IsFalse());
1702 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1703 CHECK(!true_boolean_object->IsBoolean());
1704 CHECK(true_boolean_object->IsBooleanObject());
1705 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1706 // CHECK(true_boolean_object->BooleanValue());
1707 CHECK(true_boolean_object->ValueOf());
1708 CHECK(!true_boolean_object->IsTrue());
1709 CHECK(!true_boolean_object->IsFalse());
1713 THREADED_TEST(Number) {
1715 v8::HandleScope scope(env->GetIsolate());
1716 double PI = 3.1415926;
1717 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1718 CHECK_EQ(PI, pi_obj->NumberValue());
1722 THREADED_TEST(ToNumber) {
1724 v8::Isolate* isolate = CcTest::isolate();
1725 v8::HandleScope scope(isolate);
1726 Local<String> str = v8_str("3.1415926");
1727 CHECK_EQ(3.1415926, str->NumberValue());
1728 v8::Handle<v8::Boolean> t = v8::True(isolate);
1729 CHECK_EQ(1.0, t->NumberValue());
1730 v8::Handle<v8::Boolean> f = v8::False(isolate);
1731 CHECK_EQ(0.0, f->NumberValue());
1735 THREADED_TEST(Date) {
1737 v8::HandleScope scope(env->GetIsolate());
1738 double PI = 3.1415926;
1739 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1740 CHECK_EQ(3.0, date->NumberValue());
1741 date.As<v8::Date>()->Set(v8_str("property"),
1742 v8::Integer::New(env->GetIsolate(), 42));
1743 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1747 THREADED_TEST(Boolean) {
1749 v8::Isolate* isolate = env->GetIsolate();
1750 v8::HandleScope scope(isolate);
1751 v8::Handle<v8::Boolean> t = v8::True(isolate);
1753 v8::Handle<v8::Boolean> f = v8::False(isolate);
1755 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1756 CHECK(!u->BooleanValue());
1757 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1758 CHECK(!n->BooleanValue());
1759 v8::Handle<String> str1 = v8_str("");
1760 CHECK(!str1->BooleanValue());
1761 v8::Handle<String> str2 = v8_str("x");
1762 CHECK(str2->BooleanValue());
1763 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1764 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1765 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1766 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1767 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1771 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1772 ApiTestFuzzer::Fuzz();
1773 args.GetReturnValue().Set(v8_num(13.4));
1777 static void GetM(Local<String> name,
1778 const v8::PropertyCallbackInfo<v8::Value>& info) {
1779 ApiTestFuzzer::Fuzz();
1780 info.GetReturnValue().Set(v8_num(876));
1784 THREADED_TEST(GlobalPrototype) {
1785 v8::Isolate* isolate = CcTest::isolate();
1786 v8::HandleScope scope(isolate);
1787 v8::Handle<v8::FunctionTemplate> func_templ =
1788 v8::FunctionTemplate::New(isolate);
1789 func_templ->PrototypeTemplate()->Set(
1790 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1791 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1792 templ->Set(isolate, "x", v8_num(200));
1793 templ->SetAccessor(v8_str("m"), GetM);
1794 LocalContext env(0, templ);
1795 v8::Handle<Script> script(v8_compile("dummy()"));
1796 v8::Handle<Value> result(script->Run());
1797 CHECK_EQ(13.4, result->NumberValue());
1798 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1799 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1803 THREADED_TEST(ObjectTemplate) {
1804 v8::Isolate* isolate = CcTest::isolate();
1805 v8::HandleScope scope(isolate);
1806 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1807 templ1->Set(isolate, "x", v8_num(10));
1808 templ1->Set(isolate, "y", v8_num(13));
1810 Local<v8::Object> instance1 = templ1->NewInstance();
1811 env->Global()->Set(v8_str("p"), instance1);
1812 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1813 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1814 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1815 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1816 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1817 templ2->Set(isolate, "a", v8_num(12));
1818 templ2->Set(isolate, "b", templ1);
1819 Local<v8::Object> instance2 = templ2->NewInstance();
1820 env->Global()->Set(v8_str("q"), instance2);
1821 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1822 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1823 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1824 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1828 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1829 ApiTestFuzzer::Fuzz();
1830 args.GetReturnValue().Set(v8_num(17.2));
1834 static void GetKnurd(Local<String> property,
1835 const v8::PropertyCallbackInfo<v8::Value>& info) {
1836 ApiTestFuzzer::Fuzz();
1837 info.GetReturnValue().Set(v8_num(15.2));
1841 THREADED_TEST(DescriptorInheritance) {
1842 v8::Isolate* isolate = CcTest::isolate();
1843 v8::HandleScope scope(isolate);
1844 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1845 super->PrototypeTemplate()->Set(isolate, "flabby",
1846 v8::FunctionTemplate::New(isolate,
1848 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1850 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1852 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1853 base1->Inherit(super);
1854 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1856 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1857 base2->Inherit(super);
1858 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1862 env->Global()->Set(v8_str("s"), super->GetFunction());
1863 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1864 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1866 // Checks right __proto__ chain.
1867 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1868 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1870 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1872 // Instance accessor should not be visible on function object or its prototype
1873 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1874 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1875 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1877 env->Global()->Set(v8_str("obj"),
1878 base1->GetFunction()->NewInstance());
1879 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1880 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1881 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1882 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1883 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1885 env->Global()->Set(v8_str("obj2"),
1886 base2->GetFunction()->NewInstance());
1887 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1888 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1889 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1890 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1891 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1893 // base1 and base2 cannot cross reference to each's prototype
1894 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1895 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1899 int echo_named_call_count;
1902 static void EchoNamedProperty(Local<String> name,
1903 const v8::PropertyCallbackInfo<v8::Value>& info) {
1904 ApiTestFuzzer::Fuzz();
1905 CHECK_EQ(v8_str("data"), info.Data());
1906 echo_named_call_count++;
1907 info.GetReturnValue().Set(name);
1911 // Helper functions for Interceptor/Accessor interaction tests
1913 void SimpleAccessorGetter(Local<String> name,
1914 const v8::PropertyCallbackInfo<v8::Value>& info) {
1915 Handle<Object> self = info.This();
1916 info.GetReturnValue().Set(
1917 self->Get(String::Concat(v8_str("accessor_"), name)));
1920 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1921 const v8::PropertyCallbackInfo<void>& info) {
1922 Handle<Object> self = info.This();
1923 self->Set(String::Concat(v8_str("accessor_"), name), value);
1926 void EmptyInterceptorGetter(Local<String> name,
1927 const v8::PropertyCallbackInfo<v8::Value>& info) {
1930 void EmptyInterceptorSetter(Local<String> name,
1932 const v8::PropertyCallbackInfo<v8::Value>& info) {
1935 void InterceptorGetter(Local<String> name,
1936 const v8::PropertyCallbackInfo<v8::Value>& info) {
1937 // Intercept names that start with 'interceptor_'.
1938 String::Utf8Value utf8(name);
1939 char* name_str = *utf8;
1940 char prefix[] = "interceptor_";
1942 for (i = 0; name_str[i] && prefix[i]; ++i) {
1943 if (name_str[i] != prefix[i]) return;
1945 Handle<Object> self = info.This();
1946 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1949 void InterceptorSetter(Local<String> name,
1951 const v8::PropertyCallbackInfo<v8::Value>& info) {
1952 // Intercept accesses that set certain integer values, for which the name does
1953 // not start with 'accessor_'.
1954 String::Utf8Value utf8(name);
1955 char* name_str = *utf8;
1956 char prefix[] = "accessor_";
1958 for (i = 0; name_str[i] && prefix[i]; ++i) {
1959 if (name_str[i] != prefix[i]) break;
1961 if (!prefix[i]) return;
1963 if (value->IsInt32() && value->Int32Value() < 10000) {
1964 Handle<Object> self = info.This();
1965 self->SetHiddenValue(name, value);
1966 info.GetReturnValue().Set(value);
1970 void AddAccessor(Handle<FunctionTemplate> templ,
1971 Handle<String> name,
1972 v8::AccessorGetterCallback getter,
1973 v8::AccessorSetterCallback setter) {
1974 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1977 void AddInterceptor(Handle<FunctionTemplate> templ,
1978 v8::NamedPropertyGetterCallback getter,
1979 v8::NamedPropertySetterCallback setter) {
1980 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1984 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1985 v8::HandleScope scope(CcTest::isolate());
1986 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1987 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1988 child->Inherit(parent);
1989 AddAccessor(parent, v8_str("age"),
1990 SimpleAccessorGetter, SimpleAccessorSetter);
1991 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1993 env->Global()->Set(v8_str("Child"), child->GetFunction());
1994 CompileRun("var child = new Child;"
1996 ExpectBoolean("child.hasOwnProperty('age')", false);
1997 ExpectInt32("child.age", 10);
1998 ExpectInt32("child.accessor_age", 10);
2002 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2003 v8::HandleScope scope(CcTest::isolate());
2004 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2005 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2007 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2008 CompileRun("var o1 = new Constructor;"
2009 "o1.a = 1;" // Ensure a and x share the descriptor array.
2010 "Object.defineProperty(o1, 'x', {value: 10});");
2011 CompileRun("var o2 = new Constructor;"
2013 "Object.defineProperty(o2, 'x', {value: 10});");
2017 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2018 v8::Isolate* isolate = CcTest::isolate();
2019 v8::HandleScope scope(isolate);
2020 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2021 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2022 child->Inherit(parent);
2023 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2025 env->Global()->Set(v8_str("Child"), child->GetFunction());
2026 CompileRun("var child = new Child;"
2027 "var parent = child.__proto__;"
2028 "Object.defineProperty(parent, 'age', "
2029 " {get: function(){ return this.accessor_age; }, "
2030 " set: function(v){ this.accessor_age = v; }, "
2031 " enumerable: true, configurable: true});"
2033 ExpectBoolean("child.hasOwnProperty('age')", false);
2034 ExpectInt32("child.age", 10);
2035 ExpectInt32("child.accessor_age", 10);
2039 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2040 v8::Isolate* isolate = CcTest::isolate();
2041 v8::HandleScope scope(isolate);
2042 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2043 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2044 child->Inherit(parent);
2045 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2047 env->Global()->Set(v8_str("Child"), child->GetFunction());
2048 CompileRun("var child = new Child;"
2049 "var parent = child.__proto__;"
2050 "parent.name = 'Alice';");
2051 ExpectBoolean("child.hasOwnProperty('name')", false);
2052 ExpectString("child.name", "Alice");
2053 CompileRun("child.name = 'Bob';");
2054 ExpectString("child.name", "Bob");
2055 ExpectBoolean("child.hasOwnProperty('name')", true);
2056 ExpectString("parent.name", "Alice");
2060 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2061 v8::HandleScope scope(CcTest::isolate());
2062 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2063 AddAccessor(templ, v8_str("age"),
2064 SimpleAccessorGetter, SimpleAccessorSetter);
2065 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2067 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2068 CompileRun("var obj = new Obj;"
2069 "function setAge(i){ obj.age = i; };"
2070 "for(var i = 0; i <= 10000; i++) setAge(i);");
2071 // All i < 10000 go to the interceptor.
2072 ExpectInt32("obj.interceptor_age", 9999);
2073 // The last i goes to the accessor.
2074 ExpectInt32("obj.accessor_age", 10000);
2078 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2079 v8::HandleScope scope(CcTest::isolate());
2080 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2081 AddAccessor(templ, v8_str("age"),
2082 SimpleAccessorGetter, SimpleAccessorSetter);
2083 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2085 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2086 CompileRun("var obj = new Obj;"
2087 "function setAge(i){ obj.age = i; };"
2088 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2089 // All i >= 10000 go to the accessor.
2090 ExpectInt32("obj.accessor_age", 10000);
2091 // The last i goes to the interceptor.
2092 ExpectInt32("obj.interceptor_age", 9999);
2096 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2097 v8::HandleScope scope(CcTest::isolate());
2098 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2099 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2100 child->Inherit(parent);
2101 AddAccessor(parent, v8_str("age"),
2102 SimpleAccessorGetter, SimpleAccessorSetter);
2103 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2105 env->Global()->Set(v8_str("Child"), child->GetFunction());
2106 CompileRun("var child = new Child;"
2107 "function setAge(i){ child.age = i; };"
2108 "for(var i = 0; i <= 10000; i++) setAge(i);");
2109 // All i < 10000 go to the interceptor.
2110 ExpectInt32("child.interceptor_age", 9999);
2111 // The last i goes to the accessor.
2112 ExpectInt32("child.accessor_age", 10000);
2116 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2117 v8::HandleScope scope(CcTest::isolate());
2118 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2119 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2120 child->Inherit(parent);
2121 AddAccessor(parent, v8_str("age"),
2122 SimpleAccessorGetter, SimpleAccessorSetter);
2123 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2125 env->Global()->Set(v8_str("Child"), child->GetFunction());
2126 CompileRun("var child = new Child;"
2127 "function setAge(i){ child.age = i; };"
2128 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2129 // All i >= 10000 go to the accessor.
2130 ExpectInt32("child.accessor_age", 10000);
2131 // The last i goes to the interceptor.
2132 ExpectInt32("child.interceptor_age", 9999);
2136 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2137 v8::HandleScope scope(CcTest::isolate());
2138 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2139 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2141 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2142 CompileRun("var obj = new Obj;"
2143 "function setter(i) { this.accessor_age = i; };"
2144 "function getter() { return this.accessor_age; };"
2145 "function setAge(i) { obj.age = i; };"
2146 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2147 "for(var i = 0; i <= 10000; i++) setAge(i);");
2148 // All i < 10000 go to the interceptor.
2149 ExpectInt32("obj.interceptor_age", 9999);
2150 // The last i goes to the JavaScript accessor.
2151 ExpectInt32("obj.accessor_age", 10000);
2152 // The installed JavaScript getter is still intact.
2153 // This last part is a regression test for issue 1651 and relies on the fact
2154 // that both interceptor and accessor are being installed on the same object.
2155 ExpectInt32("obj.age", 10000);
2156 ExpectBoolean("obj.hasOwnProperty('age')", true);
2157 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2161 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2162 v8::HandleScope scope(CcTest::isolate());
2163 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2164 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2166 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2167 CompileRun("var obj = new Obj;"
2168 "function setter(i) { this.accessor_age = i; };"
2169 "function getter() { return this.accessor_age; };"
2170 "function setAge(i) { obj.age = i; };"
2171 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2172 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2173 // All i >= 10000 go to the accessor.
2174 ExpectInt32("obj.accessor_age", 10000);
2175 // The last i goes to the interceptor.
2176 ExpectInt32("obj.interceptor_age", 9999);
2177 // The installed JavaScript getter is still intact.
2178 // This last part is a regression test for issue 1651 and relies on the fact
2179 // that both interceptor and accessor are being installed on the same object.
2180 ExpectInt32("obj.age", 10000);
2181 ExpectBoolean("obj.hasOwnProperty('age')", true);
2182 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2186 THREADED_TEST(SwitchFromInterceptorToProperty) {
2187 v8::HandleScope scope(CcTest::isolate());
2188 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2189 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2190 child->Inherit(parent);
2191 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2193 env->Global()->Set(v8_str("Child"), child->GetFunction());
2194 CompileRun("var child = new Child;"
2195 "function setAge(i){ child.age = i; };"
2196 "for(var i = 0; i <= 10000; i++) setAge(i);");
2197 // All i < 10000 go to the interceptor.
2198 ExpectInt32("child.interceptor_age", 9999);
2199 // The last i goes to child's own property.
2200 ExpectInt32("child.age", 10000);
2204 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2205 v8::HandleScope scope(CcTest::isolate());
2206 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2207 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2208 child->Inherit(parent);
2209 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2211 env->Global()->Set(v8_str("Child"), child->GetFunction());
2212 CompileRun("var child = new Child;"
2213 "function setAge(i){ child.age = i; };"
2214 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2215 // All i >= 10000 go to child's own property.
2216 ExpectInt32("child.age", 10000);
2217 // The last i goes to the interceptor.
2218 ExpectInt32("child.interceptor_age", 9999);
2222 THREADED_TEST(NamedPropertyHandlerGetter) {
2223 echo_named_call_count = 0;
2224 v8::HandleScope scope(CcTest::isolate());
2225 v8::Handle<v8::FunctionTemplate> templ =
2226 v8::FunctionTemplate::New(CcTest::isolate());
2227 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2231 env->Global()->Set(v8_str("obj"),
2232 templ->GetFunction()->NewInstance());
2233 CHECK_EQ(echo_named_call_count, 0);
2234 v8_compile("obj.x")->Run();
2235 CHECK_EQ(echo_named_call_count, 1);
2236 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2237 v8::Handle<Value> str = CompileRun(code);
2238 String::Utf8Value value(str);
2239 CHECK_EQ(*value, "oddlepoddle");
2240 // Check default behavior
2241 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2242 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2243 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2247 int echo_indexed_call_count = 0;
2250 static void EchoIndexedProperty(
2252 const v8::PropertyCallbackInfo<v8::Value>& info) {
2253 ApiTestFuzzer::Fuzz();
2254 CHECK_EQ(v8_num(637), info.Data());
2255 echo_indexed_call_count++;
2256 info.GetReturnValue().Set(v8_num(index));
2260 THREADED_TEST(IndexedPropertyHandlerGetter) {
2261 v8::Isolate* isolate = CcTest::isolate();
2262 v8::HandleScope scope(isolate);
2263 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2264 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2268 env->Global()->Set(v8_str("obj"),
2269 templ->GetFunction()->NewInstance());
2270 Local<Script> script = v8_compile("obj[900]");
2271 CHECK_EQ(script->Run()->Int32Value(), 900);
2275 v8::Handle<v8::Object> bottom;
2277 static void CheckThisIndexedPropertyHandler(
2279 const v8::PropertyCallbackInfo<v8::Value>& info) {
2280 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2281 ApiTestFuzzer::Fuzz();
2282 CHECK(info.This()->Equals(bottom));
2285 static void CheckThisNamedPropertyHandler(
2287 const v8::PropertyCallbackInfo<v8::Value>& info) {
2288 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2289 ApiTestFuzzer::Fuzz();
2290 CHECK(info.This()->Equals(bottom));
2293 void CheckThisIndexedPropertySetter(
2296 const v8::PropertyCallbackInfo<v8::Value>& info) {
2297 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2298 ApiTestFuzzer::Fuzz();
2299 CHECK(info.This()->Equals(bottom));
2303 void CheckThisNamedPropertySetter(
2304 Local<String> property,
2306 const v8::PropertyCallbackInfo<v8::Value>& info) {
2307 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2308 ApiTestFuzzer::Fuzz();
2309 CHECK(info.This()->Equals(bottom));
2312 void CheckThisIndexedPropertyQuery(
2314 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2315 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2316 ApiTestFuzzer::Fuzz();
2317 CHECK(info.This()->Equals(bottom));
2321 void CheckThisNamedPropertyQuery(
2322 Local<String> property,
2323 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2324 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2325 ApiTestFuzzer::Fuzz();
2326 CHECK(info.This()->Equals(bottom));
2330 void CheckThisIndexedPropertyDeleter(
2332 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2333 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2334 ApiTestFuzzer::Fuzz();
2335 CHECK(info.This()->Equals(bottom));
2339 void CheckThisNamedPropertyDeleter(
2340 Local<String> property,
2341 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2342 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2343 ApiTestFuzzer::Fuzz();
2344 CHECK(info.This()->Equals(bottom));
2348 void CheckThisIndexedPropertyEnumerator(
2349 const v8::PropertyCallbackInfo<v8::Array>& info) {
2350 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2351 ApiTestFuzzer::Fuzz();
2352 CHECK(info.This()->Equals(bottom));
2356 void CheckThisNamedPropertyEnumerator(
2357 const v8::PropertyCallbackInfo<v8::Array>& info) {
2358 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2359 ApiTestFuzzer::Fuzz();
2360 CHECK(info.This()->Equals(bottom));
2364 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2366 v8::Isolate* isolate = env->GetIsolate();
2367 v8::HandleScope scope(isolate);
2369 // Set up a prototype chain with three interceptors.
2370 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2371 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2372 CheckThisIndexedPropertyHandler,
2373 CheckThisIndexedPropertySetter,
2374 CheckThisIndexedPropertyQuery,
2375 CheckThisIndexedPropertyDeleter,
2376 CheckThisIndexedPropertyEnumerator);
2378 templ->InstanceTemplate()->SetNamedPropertyHandler(
2379 CheckThisNamedPropertyHandler,
2380 CheckThisNamedPropertySetter,
2381 CheckThisNamedPropertyQuery,
2382 CheckThisNamedPropertyDeleter,
2383 CheckThisNamedPropertyEnumerator);
2385 bottom = templ->GetFunction()->NewInstance();
2386 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2387 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2389 bottom->SetPrototype(middle);
2390 middle->SetPrototype(top);
2391 env->Global()->Set(v8_str("obj"), bottom);
2393 // Indexed and named get.
2394 Script::Compile(v8_str("obj[0]"))->Run();
2395 Script::Compile(v8_str("obj.x"))->Run();
2397 // Indexed and named set.
2398 Script::Compile(v8_str("obj[1] = 42"))->Run();
2399 Script::Compile(v8_str("obj.y = 42"))->Run();
2401 // Indexed and named query.
2402 Script::Compile(v8_str("0 in obj"))->Run();
2403 Script::Compile(v8_str("'x' in obj"))->Run();
2405 // Indexed and named deleter.
2406 Script::Compile(v8_str("delete obj[0]"))->Run();
2407 Script::Compile(v8_str("delete obj.x"))->Run();
2410 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2414 static void PrePropertyHandlerGet(
2416 const v8::PropertyCallbackInfo<v8::Value>& info) {
2417 ApiTestFuzzer::Fuzz();
2418 if (v8_str("pre")->Equals(key)) {
2419 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2424 static void PrePropertyHandlerQuery(
2426 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2427 if (v8_str("pre")->Equals(key)) {
2428 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2433 THREADED_TEST(PrePropertyHandler) {
2434 v8::Isolate* isolate = CcTest::isolate();
2435 v8::HandleScope scope(isolate);
2436 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2437 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2439 PrePropertyHandlerQuery);
2440 LocalContext env(NULL, desc->InstanceTemplate());
2441 Script::Compile(v8_str(
2442 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2443 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2444 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2445 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2446 CHECK_EQ(v8_str("Object: on"), result_on);
2447 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2448 CHECK(result_post.IsEmpty());
2452 THREADED_TEST(UndefinedIsNotEnumerable) {
2454 v8::HandleScope scope(env->GetIsolate());
2455 v8::Handle<Value> result = Script::Compile(v8_str(
2456 "this.propertyIsEnumerable(undefined)"))->Run();
2457 CHECK(result->IsFalse());
2461 v8::Handle<Script> call_recursively_script;
2462 static const int kTargetRecursionDepth = 200; // near maximum
2465 static void CallScriptRecursivelyCall(
2466 const v8::FunctionCallbackInfo<v8::Value>& args) {
2467 ApiTestFuzzer::Fuzz();
2468 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2469 if (depth == kTargetRecursionDepth) return;
2470 args.This()->Set(v8_str("depth"),
2471 v8::Integer::New(args.GetIsolate(), depth + 1));
2472 args.GetReturnValue().Set(call_recursively_script->Run());
2476 static void CallFunctionRecursivelyCall(
2477 const v8::FunctionCallbackInfo<v8::Value>& args) {
2478 ApiTestFuzzer::Fuzz();
2479 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2480 if (depth == kTargetRecursionDepth) {
2481 printf("[depth = %d]\n", depth);
2484 args.This()->Set(v8_str("depth"),
2485 v8::Integer::New(args.GetIsolate(), depth + 1));
2486 v8::Handle<Value> function =
2487 args.This()->Get(v8_str("callFunctionRecursively"));
2488 args.GetReturnValue().Set(
2489 function.As<Function>()->Call(args.This(), 0, NULL));
2493 THREADED_TEST(DeepCrossLanguageRecursion) {
2494 v8::Isolate* isolate = CcTest::isolate();
2495 v8::HandleScope scope(isolate);
2496 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2497 global->Set(v8_str("callScriptRecursively"),
2498 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2499 global->Set(v8_str("callFunctionRecursively"),
2500 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2501 LocalContext env(NULL, global);
2503 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2504 call_recursively_script = v8_compile("callScriptRecursively()");
2505 call_recursively_script->Run();
2506 call_recursively_script = v8::Handle<Script>();
2508 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2509 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2513 static void ThrowingPropertyHandlerGet(
2515 const v8::PropertyCallbackInfo<v8::Value>& info) {
2516 ApiTestFuzzer::Fuzz();
2517 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2521 static void ThrowingPropertyHandlerSet(
2524 const v8::PropertyCallbackInfo<v8::Value>& info) {
2525 info.GetIsolate()->ThrowException(key);
2526 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2530 THREADED_TEST(CallbackExceptionRegression) {
2531 v8::Isolate* isolate = CcTest::isolate();
2532 v8::HandleScope scope(isolate);
2533 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2534 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2535 ThrowingPropertyHandlerSet);
2537 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2538 v8::Handle<Value> otto = Script::Compile(v8_str(
2539 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2540 CHECK_EQ(v8_str("otto"), otto);
2541 v8::Handle<Value> netto = Script::Compile(v8_str(
2542 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2543 CHECK_EQ(v8_str("netto"), netto);
2547 THREADED_TEST(FunctionPrototype) {
2548 v8::Isolate* isolate = CcTest::isolate();
2549 v8::HandleScope scope(isolate);
2550 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2551 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2553 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2554 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2555 CHECK_EQ(script->Run()->Int32Value(), 321);
2559 THREADED_TEST(InternalFields) {
2561 v8::Isolate* isolate = env->GetIsolate();
2562 v8::HandleScope scope(isolate);
2564 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2565 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2566 instance_templ->SetInternalFieldCount(1);
2567 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2568 CHECK_EQ(1, obj->InternalFieldCount());
2569 CHECK(obj->GetInternalField(0)->IsUndefined());
2570 obj->SetInternalField(0, v8_num(17));
2571 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2575 THREADED_TEST(GlobalObjectInternalFields) {
2576 v8::Isolate* isolate = CcTest::isolate();
2577 v8::HandleScope scope(isolate);
2578 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2579 global_template->SetInternalFieldCount(1);
2580 LocalContext env(NULL, global_template);
2581 v8::Handle<v8::Object> global_proxy = env->Global();
2582 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2583 CHECK_EQ(1, global->InternalFieldCount());
2584 CHECK(global->GetInternalField(0)->IsUndefined());
2585 global->SetInternalField(0, v8_num(17));
2586 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2590 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2592 v8::HandleScope scope(CcTest::isolate());
2594 v8::Local<v8::Object> global = env->Global();
2595 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2596 CHECK(global->HasRealIndexedProperty(0));
2600 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2602 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2603 obj->SetAlignedPointerInInternalField(0, value);
2604 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2605 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2609 THREADED_TEST(InternalFieldsAlignedPointers) {
2611 v8::Isolate* isolate = env->GetIsolate();
2612 v8::HandleScope scope(isolate);
2614 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2615 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2616 instance_templ->SetInternalFieldCount(1);
2617 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2618 CHECK_EQ(1, obj->InternalFieldCount());
2620 CheckAlignedPointerInInternalField(obj, NULL);
2622 int* heap_allocated = new int[100];
2623 CheckAlignedPointerInInternalField(obj, heap_allocated);
2624 delete[] heap_allocated;
2626 int stack_allocated[100];
2627 CheckAlignedPointerInInternalField(obj, stack_allocated);
2629 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2630 CheckAlignedPointerInInternalField(obj, huge);
2634 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2637 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2638 (*env)->SetAlignedPointerInEmbedderData(index, value);
2639 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2640 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2644 static void* AlignedTestPointer(int i) {
2645 return reinterpret_cast<void*>(i * 1234);
2649 THREADED_TEST(EmbedderDataAlignedPointers) {
2651 v8::HandleScope scope(env->GetIsolate());
2653 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2655 int* heap_allocated = new int[100];
2656 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2657 delete[] heap_allocated;
2659 int stack_allocated[100];
2660 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2662 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2663 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2665 // Test growing of the embedder data's backing store.
2666 for (int i = 0; i < 100; i++) {
2667 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2669 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2670 for (int i = 0; i < 100; i++) {
2671 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2676 static void CheckEmbedderData(LocalContext* env,
2678 v8::Handle<Value> data) {
2679 (*env)->SetEmbedderData(index, data);
2680 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2684 THREADED_TEST(EmbedderData) {
2686 v8::Isolate* isolate = env->GetIsolate();
2687 v8::HandleScope scope(isolate);
2691 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2692 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2693 "over the lazy dog."));
2694 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2695 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2699 THREADED_TEST(IdentityHash) {
2701 v8::Isolate* isolate = env->GetIsolate();
2702 v8::HandleScope scope(isolate);
2704 // Ensure that the test starts with an fresh heap to test whether the hash
2705 // code is based on the address.
2706 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2707 Local<v8::Object> obj = v8::Object::New(isolate);
2708 int hash = obj->GetIdentityHash();
2709 int hash1 = obj->GetIdentityHash();
2710 CHECK_EQ(hash, hash1);
2711 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2712 // Since the identity hash is essentially a random number two consecutive
2713 // objects should not be assigned the same hash code. If the test below fails
2714 // the random number generator should be evaluated.
2715 CHECK_NE(hash, hash2);
2716 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2717 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2718 // Make sure that the identity hash is not based on the initial address of
2719 // the object alone. If the test below fails the random number generator
2720 // should be evaluated.
2721 CHECK_NE(hash, hash3);
2722 int hash4 = obj->GetIdentityHash();
2723 CHECK_EQ(hash, hash4);
2725 // Check identity hashes behaviour in the presence of JS accessors.
2726 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2728 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2729 Local<v8::Object> o1 = v8::Object::New(isolate);
2730 Local<v8::Object> o2 = v8::Object::New(isolate);
2731 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2735 "function cnst() { return 42; };\n"
2736 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2737 Local<v8::Object> o1 = v8::Object::New(isolate);
2738 Local<v8::Object> o2 = v8::Object::New(isolate);
2739 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2744 THREADED_TEST(SymbolProperties) {
2745 i::FLAG_harmony_symbols = true;
2748 v8::Isolate* isolate = env->GetIsolate();
2749 v8::HandleScope scope(isolate);
2751 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2752 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2753 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2755 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2757 // Check basic symbol functionality.
2758 CHECK(sym1->IsSymbol());
2759 CHECK(sym2->IsSymbol());
2760 CHECK(!obj->IsSymbol());
2762 CHECK(sym1->Equals(sym1));
2763 CHECK(sym2->Equals(sym2));
2764 CHECK(!sym1->Equals(sym2));
2765 CHECK(!sym2->Equals(sym1));
2766 CHECK(sym1->StrictEquals(sym1));
2767 CHECK(sym2->StrictEquals(sym2));
2768 CHECK(!sym1->StrictEquals(sym2));
2769 CHECK(!sym2->StrictEquals(sym1));
2771 CHECK(sym2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-symbol")));
2773 v8::Local<v8::Value> sym_val = sym2;
2774 CHECK(sym_val->IsSymbol());
2775 CHECK(sym_val->Equals(sym2));
2776 CHECK(sym_val->StrictEquals(sym2));
2777 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2779 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2780 CHECK(sym_obj->IsSymbolObject());
2781 CHECK(!sym2->IsSymbolObject());
2782 CHECK(!obj->IsSymbolObject());
2783 CHECK(sym_obj->Equals(sym2));
2784 CHECK(!sym_obj->StrictEquals(sym2));
2785 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2786 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2788 // Make sure delete of a non-existent symbol property works.
2789 CHECK(obj->Delete(sym1));
2790 CHECK(!obj->Has(sym1));
2792 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2793 CHECK(obj->Has(sym1));
2794 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2795 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2796 CHECK(obj->Has(sym1));
2797 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2798 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2800 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2801 int num_props = obj->GetPropertyNames()->Length();
2802 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2803 v8::Integer::New(isolate, 20)));
2804 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2805 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2807 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2809 // Add another property and delete it afterwards to force the object in
2811 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2812 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2813 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2814 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2815 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2817 CHECK(obj->Has(sym1));
2818 CHECK(obj->Has(sym2));
2819 CHECK(obj->Delete(sym2));
2820 CHECK(obj->Has(sym1));
2821 CHECK(!obj->Has(sym2));
2822 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2823 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2825 // Symbol properties are inherited.
2826 v8::Local<v8::Object> child = v8::Object::New(isolate);
2827 child->SetPrototype(obj);
2828 CHECK(child->Has(sym1));
2829 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2830 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2834 THREADED_TEST(PrivateProperties) {
2836 v8::Isolate* isolate = env->GetIsolate();
2837 v8::HandleScope scope(isolate);
2839 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2840 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2841 v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private");
2843 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2845 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2847 // Make sure delete of a non-existent private symbol property works.
2848 CHECK(obj->DeletePrivate(priv1));
2849 CHECK(!obj->HasPrivate(priv1));
2851 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2852 CHECK(obj->HasPrivate(priv1));
2853 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2854 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2855 CHECK(obj->HasPrivate(priv1));
2856 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2858 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2859 int num_props = obj->GetPropertyNames()->Length();
2860 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2861 v8::Integer::New(isolate, 20)));
2862 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2863 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2865 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2867 // Add another property and delete it afterwards to force the object in
2869 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2870 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2871 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2872 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2873 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2875 CHECK(obj->HasPrivate(priv1));
2876 CHECK(obj->HasPrivate(priv2));
2877 CHECK(obj->DeletePrivate(priv2));
2878 CHECK(obj->HasPrivate(priv1));
2879 CHECK(!obj->HasPrivate(priv2));
2880 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2881 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2883 // Private properties are inherited (for the time being).
2884 v8::Local<v8::Object> child = v8::Object::New(isolate);
2885 child->SetPrototype(obj);
2886 CHECK(child->HasPrivate(priv1));
2887 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2888 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2892 class ScopedArrayBufferContents {
2894 explicit ScopedArrayBufferContents(
2895 const v8::ArrayBuffer::Contents& contents)
2896 : contents_(contents) {}
2897 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2898 void* Data() const { return contents_.Data(); }
2899 size_t ByteLength() const { return contents_.ByteLength(); }
2901 const v8::ArrayBuffer::Contents contents_;
2904 template <typename T>
2905 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2906 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2907 for (int i = 0; i < value->InternalFieldCount(); i++) {
2908 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2913 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2915 v8::Isolate* isolate = env->GetIsolate();
2916 v8::HandleScope handle_scope(isolate);
2918 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2919 CheckInternalFieldsAreZero(ab);
2920 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2921 CHECK(!ab->IsExternal());
2922 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2924 ScopedArrayBufferContents ab_contents(ab->Externalize());
2925 CHECK(ab->IsExternal());
2927 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2928 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2929 ASSERT(data != NULL);
2930 env->Global()->Set(v8_str("ab"), ab);
2932 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2933 CHECK_EQ(1024, result->Int32Value());
2935 result = CompileRun("var u8 = new Uint8Array(ab);"
2939 CHECK_EQ(1024, result->Int32Value());
2940 CHECK_EQ(0xFF, data[0]);
2941 CHECK_EQ(0xAA, data[1]);
2944 result = CompileRun("u8[0] + u8[1]");
2945 CHECK_EQ(0xDD, result->Int32Value());
2949 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2951 v8::Isolate* isolate = env->GetIsolate();
2952 v8::HandleScope handle_scope(isolate);
2955 v8::Local<v8::Value> result =
2956 CompileRun("var ab1 = new ArrayBuffer(2);"
2957 "var u8_a = new Uint8Array(ab1);"
2959 "u8_a[1] = 0xFF; u8_a.buffer");
2960 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2961 CheckInternalFieldsAreZero(ab1);
2962 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2963 CHECK(!ab1->IsExternal());
2964 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2965 CHECK(ab1->IsExternal());
2967 result = CompileRun("ab1.byteLength");
2968 CHECK_EQ(2, result->Int32Value());
2969 result = CompileRun("u8_a[0]");
2970 CHECK_EQ(0xAA, result->Int32Value());
2971 result = CompileRun("u8_a[1]");
2972 CHECK_EQ(0xFF, result->Int32Value());
2973 result = CompileRun("var u8_b = new Uint8Array(ab1);"
2976 CHECK_EQ(0xBB, result->Int32Value());
2977 result = CompileRun("u8_b[1]");
2978 CHECK_EQ(0xFF, result->Int32Value());
2980 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2981 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2982 CHECK_EQ(0xBB, ab1_data[0]);
2983 CHECK_EQ(0xFF, ab1_data[1]);
2986 result = CompileRun("u8_a[0] + u8_a[1]");
2987 CHECK_EQ(0xDD, result->Int32Value());
2991 THREADED_TEST(ArrayBuffer_External) {
2993 v8::Isolate* isolate = env->GetIsolate();
2994 v8::HandleScope handle_scope(isolate);
2996 i::ScopedVector<uint8_t> my_data(100);
2997 memset(my_data.start(), 0, 100);
2998 Local<v8::ArrayBuffer> ab3 =
2999 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3000 CheckInternalFieldsAreZero(ab3);
3001 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3002 CHECK(ab3->IsExternal());
3004 env->Global()->Set(v8_str("ab3"), ab3);
3006 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3007 CHECK_EQ(100, result->Int32Value());
3009 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3013 CHECK_EQ(100, result->Int32Value());
3014 CHECK_EQ(0xBB, my_data[0]);
3015 CHECK_EQ(0xCC, my_data[1]);
3018 result = CompileRun("u8_b[0] + u8_b[1]");
3019 CHECK_EQ(0xDD, result->Int32Value());
3023 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3024 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3025 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3029 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3030 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3031 CHECK_EQ(0, static_cast<int>(ta->Length()));
3032 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3036 static void CheckIsTypedArrayVarNeutered(const char* name) {
3037 i::ScopedVector<char> source(1024);
3038 i::OS::SNPrintF(source,
3039 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3041 CHECK(CompileRun(source.start())->IsTrue());
3042 v8::Handle<v8::TypedArray> ta =
3043 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3044 CheckIsNeutered(ta);
3048 template <typename TypedArray, int kElementSize>
3049 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3052 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3053 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3054 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3055 CHECK_EQ(length, static_cast<int>(ta->Length()));
3056 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3061 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3063 v8::Isolate* isolate = env->GetIsolate();
3064 v8::HandleScope handle_scope(isolate);
3066 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3068 v8::Handle<v8::Uint8Array> u8a =
3069 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3070 v8::Handle<v8::Uint8ClampedArray> u8c =
3071 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3072 v8::Handle<v8::Int8Array> i8a =
3073 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3075 v8::Handle<v8::Uint16Array> u16a =
3076 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3077 v8::Handle<v8::Int16Array> i16a =
3078 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3080 v8::Handle<v8::Uint32Array> u32a =
3081 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3082 v8::Handle<v8::Int32Array> i32a =
3083 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3085 v8::Handle<v8::Float32Array> f32a =
3086 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3087 v8::Handle<v8::Float64Array> f64a =
3088 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3090 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3091 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3092 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3093 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3095 ScopedArrayBufferContents contents(buffer->Externalize());
3097 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3098 CheckIsNeutered(u8a);
3099 CheckIsNeutered(u8c);
3100 CheckIsNeutered(i8a);
3101 CheckIsNeutered(u16a);
3102 CheckIsNeutered(i16a);
3103 CheckIsNeutered(u32a);
3104 CheckIsNeutered(i32a);
3105 CheckIsNeutered(f32a);
3106 CheckIsNeutered(f64a);
3107 CheckDataViewIsNeutered(dv);
3111 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3113 v8::Isolate* isolate = env->GetIsolate();
3114 v8::HandleScope handle_scope(isolate);
3117 "var ab = new ArrayBuffer(1024);"
3118 "var u8a = new Uint8Array(ab, 1, 1023);"
3119 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3120 "var i8a = new Int8Array(ab, 1, 1023);"
3121 "var u16a = new Uint16Array(ab, 2, 511);"
3122 "var i16a = new Int16Array(ab, 2, 511);"
3123 "var u32a = new Uint32Array(ab, 4, 255);"
3124 "var i32a = new Int32Array(ab, 4, 255);"
3125 "var f32a = new Float32Array(ab, 4, 255);"
3126 "var f64a = new Float64Array(ab, 8, 127);"
3127 "var dv = new DataView(ab, 1, 1023);");
3129 v8::Handle<v8::ArrayBuffer> ab =
3130 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3132 v8::Handle<v8::DataView> dv =
3133 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3135 ScopedArrayBufferContents contents(ab->Externalize());
3137 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3138 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3140 CheckIsTypedArrayVarNeutered("u8a");
3141 CheckIsTypedArrayVarNeutered("u8c");
3142 CheckIsTypedArrayVarNeutered("i8a");
3143 CheckIsTypedArrayVarNeutered("u16a");
3144 CheckIsTypedArrayVarNeutered("i16a");
3145 CheckIsTypedArrayVarNeutered("u32a");
3146 CheckIsTypedArrayVarNeutered("i32a");
3147 CheckIsTypedArrayVarNeutered("f32a");
3148 CheckIsTypedArrayVarNeutered("f64a");
3150 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3151 CheckDataViewIsNeutered(dv);
3156 THREADED_TEST(HiddenProperties) {
3158 v8::Isolate* isolate = env->GetIsolate();
3159 v8::HandleScope scope(isolate);
3161 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3162 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3163 v8::Local<v8::String> empty = v8_str("");
3164 v8::Local<v8::String> prop_name = v8_str("prop_name");
3166 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3168 // Make sure delete of a non-existent hidden value works
3169 CHECK(obj->DeleteHiddenValue(key));
3171 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3172 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3173 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3174 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3176 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3178 // Make sure we do not find the hidden property.
3179 CHECK(!obj->Has(empty));
3180 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3181 CHECK(obj->Get(empty)->IsUndefined());
3182 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3183 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3184 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3185 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3187 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3189 // Add another property and delete it afterwards to force the object in
3191 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3192 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3193 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3194 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3195 CHECK(obj->Delete(prop_name));
3196 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3198 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3200 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3201 CHECK(obj->GetHiddenValue(key).IsEmpty());
3203 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3204 CHECK(obj->DeleteHiddenValue(key));
3205 CHECK(obj->GetHiddenValue(key).IsEmpty());
3209 THREADED_TEST(Regress97784) {
3210 // Regression test for crbug.com/97784
3211 // Messing with the Object.prototype should not have effect on
3212 // hidden properties.
3214 v8::HandleScope scope(env->GetIsolate());
3216 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3217 v8::Local<v8::String> key = v8_str("hidden");
3220 "set_called = false;"
3221 "Object.defineProperty("
3222 " Object.prototype,"
3224 " {get: function() { return 45; },"
3225 " set: function() { set_called = true; }})");
3227 CHECK(obj->GetHiddenValue(key).IsEmpty());
3228 // Make sure that the getter and setter from Object.prototype is not invoked.
3229 // If it did we would have full access to the hidden properties in
3231 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3232 ExpectFalse("set_called");
3233 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3237 static bool interceptor_for_hidden_properties_called;
3238 static void InterceptorForHiddenProperties(
3239 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3240 interceptor_for_hidden_properties_called = true;
3244 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3245 LocalContext context;
3246 v8::Isolate* isolate = context->GetIsolate();
3247 v8::HandleScope scope(isolate);
3249 interceptor_for_hidden_properties_called = false;
3251 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3253 // Associate an interceptor with an object and start setting hidden values.
3254 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3255 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3256 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3257 Local<v8::Function> function = fun_templ->GetFunction();
3258 Local<v8::Object> obj = function->NewInstance();
3259 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3260 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3261 CHECK(!interceptor_for_hidden_properties_called);
3265 THREADED_TEST(External) {
3266 v8::HandleScope scope(CcTest::isolate());
3268 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3270 env->Global()->Set(v8_str("ext"), ext);
3271 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3272 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3273 int* ptr = static_cast<int*>(reext->Value());
3278 // Make sure unaligned pointers are wrapped properly.
3279 char* data = i::StrDup("0123456789");
3280 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3281 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3282 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3283 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3285 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3286 CHECK_EQ('0', *char_ptr);
3287 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3288 CHECK_EQ('1', *char_ptr);
3289 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3290 CHECK_EQ('2', *char_ptr);
3291 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3292 CHECK_EQ('3', *char_ptr);
3293 i::DeleteArray(data);
3297 THREADED_TEST(GlobalHandle) {
3298 v8::Isolate* isolate = CcTest::isolate();
3299 v8::Persistent<String> global;
3301 v8::HandleScope scope(isolate);
3302 global.Reset(isolate, v8_str("str"));
3305 v8::HandleScope scope(isolate);
3306 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3310 v8::HandleScope scope(isolate);
3311 global.Reset(isolate, v8_str("str"));
3314 v8::HandleScope scope(isolate);
3315 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3321 THREADED_TEST(ResettingGlobalHandle) {
3322 v8::Isolate* isolate = CcTest::isolate();
3323 v8::Persistent<String> global;
3325 v8::HandleScope scope(isolate);
3326 global.Reset(isolate, v8_str("str"));
3328 v8::internal::GlobalHandles* global_handles =
3329 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3330 int initial_handle_count = global_handles->global_handles_count();
3332 v8::HandleScope scope(isolate);
3333 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3336 v8::HandleScope scope(isolate);
3337 global.Reset(isolate, v8_str("longer"));
3339 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3341 v8::HandleScope scope(isolate);
3342 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3345 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3349 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3350 v8::Isolate* isolate = CcTest::isolate();
3351 v8::Persistent<String> global;
3353 v8::HandleScope scope(isolate);
3354 global.Reset(isolate, v8_str("str"));
3356 v8::internal::GlobalHandles* global_handles =
3357 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3358 int initial_handle_count = global_handles->global_handles_count();
3360 v8::HandleScope scope(isolate);
3361 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3364 v8::HandleScope scope(isolate);
3365 Local<String> empty;
3366 global.Reset(isolate, empty);
3368 CHECK(global.IsEmpty());
3369 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3374 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3375 return unique.Pass();
3380 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3381 const v8::Persistent<T> & global) {
3382 v8::UniquePersistent<String> unique(isolate, global);
3383 return unique.Pass();
3387 THREADED_TEST(UniquePersistent) {
3388 v8::Isolate* isolate = CcTest::isolate();
3389 v8::Persistent<String> global;
3391 v8::HandleScope scope(isolate);
3392 global.Reset(isolate, v8_str("str"));
3394 v8::internal::GlobalHandles* global_handles =
3395 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3396 int initial_handle_count = global_handles->global_handles_count();
3398 v8::UniquePersistent<String> unique(isolate, global);
3399 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3400 // Test assignment via Pass
3402 v8::UniquePersistent<String> copy = unique.Pass();
3403 CHECK(unique.IsEmpty());
3404 CHECK(copy == global);
3405 CHECK_EQ(initial_handle_count + 1,
3406 global_handles->global_handles_count());
3407 unique = copy.Pass();
3409 // Test ctor via Pass
3411 v8::UniquePersistent<String> copy(unique.Pass());
3412 CHECK(unique.IsEmpty());
3413 CHECK(copy == global);
3414 CHECK_EQ(initial_handle_count + 1,
3415 global_handles->global_handles_count());
3416 unique = copy.Pass();
3418 // Test pass through function call
3420 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3421 CHECK(unique.IsEmpty());
3422 CHECK(copy == global);
3423 CHECK_EQ(initial_handle_count + 1,
3424 global_handles->global_handles_count());
3425 unique = copy.Pass();
3427 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3429 // Test pass from function call
3431 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3432 CHECK(unique == global);
3433 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3435 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3440 THREADED_TEST(GlobalHandleUpcast) {
3441 v8::Isolate* isolate = CcTest::isolate();
3442 v8::HandleScope scope(isolate);
3443 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3444 v8::Persistent<String> global_string(isolate, local);
3445 v8::Persistent<Value>& global_value =
3446 v8::Persistent<Value>::Cast(global_string);
3447 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3448 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3449 global_string.Reset();
3453 THREADED_TEST(HandleEquality) {
3454 v8::Isolate* isolate = CcTest::isolate();
3455 v8::Persistent<String> global1;
3456 v8::Persistent<String> global2;
3458 v8::HandleScope scope(isolate);
3459 global1.Reset(isolate, v8_str("str"));
3460 global2.Reset(isolate, v8_str("str2"));
3462 CHECK_EQ(global1 == global1, true);
3463 CHECK_EQ(global1 != global1, false);
3465 v8::HandleScope scope(isolate);
3466 Local<String> local1 = Local<String>::New(isolate, global1);
3467 Local<String> local2 = Local<String>::New(isolate, global2);
3469 CHECK_EQ(global1 == local1, true);
3470 CHECK_EQ(global1 != local1, false);
3471 CHECK_EQ(local1 == global1, true);
3472 CHECK_EQ(local1 != global1, false);
3474 CHECK_EQ(global1 == local2, false);
3475 CHECK_EQ(global1 != local2, true);
3476 CHECK_EQ(local2 == global1, false);
3477 CHECK_EQ(local2 != global1, true);
3479 CHECK_EQ(local1 == local2, false);
3480 CHECK_EQ(local1 != local2, true);
3482 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3483 CHECK_EQ(local1 == anotherLocal1, true);
3484 CHECK_EQ(local1 != anotherLocal1, false);
3491 THREADED_TEST(LocalHandle) {
3492 v8::HandleScope scope(CcTest::isolate());
3493 v8::Local<String> local =
3494 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3495 CHECK_EQ(local->Length(), 3);
3499 class WeakCallCounter {
3501 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3502 int id() { return id_; }
3503 void increment() { number_of_weak_calls_++; }
3504 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3507 int number_of_weak_calls_;
3511 template<typename T>
3512 struct WeakCallCounterAndPersistent {
3513 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3514 : counter(counter) {}
3515 WeakCallCounter* counter;
3516 v8::Persistent<T> handle;
3520 template <typename T>
3521 static void WeakPointerCallback(
3522 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3523 CHECK_EQ(1234, data.GetParameter()->counter->id());
3524 data.GetParameter()->counter->increment();
3525 data.GetParameter()->handle.Reset();
3529 template<typename T>
3530 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3531 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3535 THREADED_TEST(ApiObjectGroups) {
3537 v8::Isolate* iso = env->GetIsolate();
3538 HandleScope scope(iso);
3540 WeakCallCounter counter(1234);
3542 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3543 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3544 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3545 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3546 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3547 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3550 HandleScope scope(iso);
3551 g1s1.handle.Reset(iso, Object::New(iso));
3552 g1s2.handle.Reset(iso, Object::New(iso));
3553 g1c1.handle.Reset(iso, Object::New(iso));
3554 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3555 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3556 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3558 g2s1.handle.Reset(iso, Object::New(iso));
3559 g2s2.handle.Reset(iso, Object::New(iso));
3560 g2c1.handle.Reset(iso, Object::New(iso));
3561 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3562 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3563 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3566 WeakCallCounterAndPersistent<Value> root(&counter);
3567 root.handle.Reset(iso, g1s1.handle); // make a root.
3569 // Connect group 1 and 2, make a cycle.
3571 HandleScope scope(iso);
3572 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3573 Set(0, Local<Value>::New(iso, g2s2.handle)));
3574 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3575 Set(0, Local<Value>::New(iso, g1s1.handle)));
3579 UniqueId id1 = MakeUniqueId(g1s1.handle);
3580 UniqueId id2 = MakeUniqueId(g2s2.handle);
3581 iso->SetObjectGroupId(g1s1.handle, id1);
3582 iso->SetObjectGroupId(g1s2.handle, id1);
3583 iso->SetReferenceFromGroup(id1, g1c1.handle);
3584 iso->SetObjectGroupId(g2s1.handle, id2);
3585 iso->SetObjectGroupId(g2s2.handle, id2);
3586 iso->SetReferenceFromGroup(id2, g2c1.handle);
3588 // Do a single full GC, ensure incremental marking is stopped.
3589 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3591 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3593 // All object should be alive.
3594 CHECK_EQ(0, counter.NumberOfWeakCalls());
3597 root.handle.SetWeak(&root, &WeakPointerCallback);
3598 // But make children strong roots---all the objects (except for children)
3599 // should be collectable now.
3600 g1c1.handle.ClearWeak();
3601 g2c1.handle.ClearWeak();
3603 // Groups are deleted, rebuild groups.
3605 UniqueId id1 = MakeUniqueId(g1s1.handle);
3606 UniqueId id2 = MakeUniqueId(g2s2.handle);
3607 iso->SetObjectGroupId(g1s1.handle, id1);
3608 iso->SetObjectGroupId(g1s2.handle, id1);
3609 iso->SetReferenceFromGroup(id1, g1c1.handle);
3610 iso->SetObjectGroupId(g2s1.handle, id2);
3611 iso->SetObjectGroupId(g2s2.handle, id2);
3612 iso->SetReferenceFromGroup(id2, g2c1.handle);
3615 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3617 // All objects should be gone. 5 global handles in total.
3618 CHECK_EQ(5, counter.NumberOfWeakCalls());
3620 // And now make children weak again and collect them.
3621 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3622 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3624 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3625 CHECK_EQ(7, counter.NumberOfWeakCalls());
3629 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3631 v8::Isolate* iso = env->GetIsolate();
3632 HandleScope scope(iso);
3634 WeakCallCounter counter(1234);
3636 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3637 WeakCallCounterAndPersistent<String> g1s2(&counter);
3638 WeakCallCounterAndPersistent<String> g1c1(&counter);
3639 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3640 WeakCallCounterAndPersistent<String> g2s2(&counter);
3641 WeakCallCounterAndPersistent<String> g2c1(&counter);
3644 HandleScope scope(iso);
3645 g1s1.handle.Reset(iso, Object::New(iso));
3646 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3647 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3648 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3649 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3650 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3652 g2s1.handle.Reset(iso, Object::New(iso));
3653 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3654 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3655 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3656 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3657 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3660 WeakCallCounterAndPersistent<Value> root(&counter);
3661 root.handle.Reset(iso, g1s1.handle); // make a root.
3663 // Connect group 1 and 2, make a cycle.
3665 HandleScope scope(iso);
3666 CHECK(Local<Object>::New(iso, g1s1.handle)
3667 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3668 CHECK(Local<Object>::New(iso, g2s1.handle)
3669 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3673 UniqueId id1 = MakeUniqueId(g1s1.handle);
3674 UniqueId id2 = MakeUniqueId(g2s2.handle);
3675 iso->SetObjectGroupId(g1s1.handle, id1);
3676 iso->SetObjectGroupId(g1s2.handle, id1);
3677 iso->SetReference(g1s1.handle, g1c1.handle);
3678 iso->SetObjectGroupId(g2s1.handle, id2);
3679 iso->SetObjectGroupId(g2s2.handle, id2);
3680 iso->SetReferenceFromGroup(id2, g2c1.handle);
3682 // Do a single full GC, ensure incremental marking is stopped.
3683 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3685 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3687 // All object should be alive.
3688 CHECK_EQ(0, counter.NumberOfWeakCalls());
3691 root.handle.SetWeak(&root, &WeakPointerCallback);
3692 // But make children strong roots---all the objects (except for children)
3693 // should be collectable now.
3694 g1c1.handle.ClearWeak();
3695 g2c1.handle.ClearWeak();
3697 // Groups are deleted, rebuild groups.
3699 UniqueId id1 = MakeUniqueId(g1s1.handle);
3700 UniqueId id2 = MakeUniqueId(g2s2.handle);
3701 iso->SetObjectGroupId(g1s1.handle, id1);
3702 iso->SetObjectGroupId(g1s2.handle, id1);
3703 iso->SetReference(g1s1.handle, g1c1.handle);
3704 iso->SetObjectGroupId(g2s1.handle, id2);
3705 iso->SetObjectGroupId(g2s2.handle, id2);
3706 iso->SetReferenceFromGroup(id2, g2c1.handle);
3709 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3711 // All objects should be gone. 5 global handles in total.
3712 CHECK_EQ(5, counter.NumberOfWeakCalls());
3714 // And now make children weak again and collect them.
3715 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3716 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3718 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3719 CHECK_EQ(7, counter.NumberOfWeakCalls());
3723 THREADED_TEST(ApiObjectGroupsCycle) {
3725 v8::Isolate* iso = env->GetIsolate();
3726 HandleScope scope(iso);
3728 WeakCallCounter counter(1234);
3730 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3731 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3732 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3733 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3734 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3735 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3736 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3737 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3740 HandleScope scope(iso);
3741 g1s1.handle.Reset(iso, Object::New(iso));
3742 g1s2.handle.Reset(iso, Object::New(iso));
3743 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3744 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3745 CHECK(g1s1.handle.IsWeak());
3746 CHECK(g1s2.handle.IsWeak());
3748 g2s1.handle.Reset(iso, Object::New(iso));
3749 g2s2.handle.Reset(iso, Object::New(iso));
3750 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3751 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3752 CHECK(g2s1.handle.IsWeak());
3753 CHECK(g2s2.handle.IsWeak());
3755 g3s1.handle.Reset(iso, Object::New(iso));
3756 g3s2.handle.Reset(iso, Object::New(iso));
3757 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3758 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3759 CHECK(g3s1.handle.IsWeak());
3760 CHECK(g3s2.handle.IsWeak());
3762 g4s1.handle.Reset(iso, Object::New(iso));
3763 g4s2.handle.Reset(iso, Object::New(iso));
3764 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3765 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3766 CHECK(g4s1.handle.IsWeak());
3767 CHECK(g4s2.handle.IsWeak());
3770 WeakCallCounterAndPersistent<Value> root(&counter);
3771 root.handle.Reset(iso, g1s1.handle); // make a root.
3773 // Connect groups. We're building the following cycle:
3774 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3777 UniqueId id1 = MakeUniqueId(g1s1.handle);
3778 UniqueId id2 = MakeUniqueId(g2s1.handle);
3779 UniqueId id3 = MakeUniqueId(g3s1.handle);
3780 UniqueId id4 = MakeUniqueId(g4s1.handle);
3781 iso->SetObjectGroupId(g1s1.handle, id1);
3782 iso->SetObjectGroupId(g1s2.handle, id1);
3783 iso->SetReferenceFromGroup(id1, g2s1.handle);
3784 iso->SetObjectGroupId(g2s1.handle, id2);
3785 iso->SetObjectGroupId(g2s2.handle, id2);
3786 iso->SetReferenceFromGroup(id2, g3s1.handle);
3787 iso->SetObjectGroupId(g3s1.handle, id3);
3788 iso->SetObjectGroupId(g3s2.handle, id3);
3789 iso->SetReferenceFromGroup(id3, g4s1.handle);
3790 iso->SetObjectGroupId(g4s1.handle, id4);
3791 iso->SetObjectGroupId(g4s2.handle, id4);
3792 iso->SetReferenceFromGroup(id4, g1s1.handle);
3794 // Do a single full GC
3795 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3797 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3799 // All object should be alive.
3800 CHECK_EQ(0, counter.NumberOfWeakCalls());
3803 root.handle.SetWeak(&root, &WeakPointerCallback);
3805 // Groups are deleted, rebuild groups.
3807 UniqueId id1 = MakeUniqueId(g1s1.handle);
3808 UniqueId id2 = MakeUniqueId(g2s1.handle);
3809 UniqueId id3 = MakeUniqueId(g3s1.handle);
3810 UniqueId id4 = MakeUniqueId(g4s1.handle);
3811 iso->SetObjectGroupId(g1s1.handle, id1);
3812 iso->SetObjectGroupId(g1s2.handle, id1);
3813 iso->SetReferenceFromGroup(id1, g2s1.handle);
3814 iso->SetObjectGroupId(g2s1.handle, id2);
3815 iso->SetObjectGroupId(g2s2.handle, id2);
3816 iso->SetReferenceFromGroup(id2, g3s1.handle);
3817 iso->SetObjectGroupId(g3s1.handle, id3);
3818 iso->SetObjectGroupId(g3s2.handle, id3);
3819 iso->SetReferenceFromGroup(id3, g4s1.handle);
3820 iso->SetObjectGroupId(g4s1.handle, id4);
3821 iso->SetObjectGroupId(g4s2.handle, id4);
3822 iso->SetReferenceFromGroup(id4, g1s1.handle);
3825 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3827 // All objects should be gone. 9 global handles in total.
3828 CHECK_EQ(9, counter.NumberOfWeakCalls());
3832 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3833 // on the buildbots, so was made non-threaded for the time being.
3834 TEST(ApiObjectGroupsCycleForScavenger) {
3835 i::FLAG_stress_compaction = false;
3836 i::FLAG_gc_global = false;
3838 v8::Isolate* iso = env->GetIsolate();
3839 HandleScope scope(iso);
3841 WeakCallCounter counter(1234);
3843 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3844 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3845 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3846 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3847 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3848 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3851 HandleScope scope(iso);
3852 g1s1.handle.Reset(iso, Object::New(iso));
3853 g1s2.handle.Reset(iso, Object::New(iso));
3854 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3855 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3857 g2s1.handle.Reset(iso, Object::New(iso));
3858 g2s2.handle.Reset(iso, Object::New(iso));
3859 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3860 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3862 g3s1.handle.Reset(iso, Object::New(iso));
3863 g3s2.handle.Reset(iso, Object::New(iso));
3864 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3865 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3869 WeakCallCounterAndPersistent<Value> root(&counter);
3870 root.handle.Reset(iso, g1s1.handle);
3871 root.handle.MarkPartiallyDependent();
3873 // Connect groups. We're building the following cycle:
3874 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3877 HandleScope handle_scope(iso);
3878 g1s1.handle.MarkPartiallyDependent();
3879 g1s2.handle.MarkPartiallyDependent();
3880 g2s1.handle.MarkPartiallyDependent();
3881 g2s2.handle.MarkPartiallyDependent();
3882 g3s1.handle.MarkPartiallyDependent();
3883 g3s2.handle.MarkPartiallyDependent();
3884 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3885 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3886 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3887 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3888 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3889 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3890 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3891 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3892 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3893 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3894 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3895 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3898 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3900 heap->CollectGarbage(i::NEW_SPACE);
3902 // All objects should be alive.
3903 CHECK_EQ(0, counter.NumberOfWeakCalls());
3906 root.handle.SetWeak(&root, &WeakPointerCallback);
3907 root.handle.MarkPartiallyDependent();
3909 // Groups are deleted, rebuild groups.
3911 HandleScope handle_scope(iso);
3912 g1s1.handle.MarkPartiallyDependent();
3913 g1s2.handle.MarkPartiallyDependent();
3914 g2s1.handle.MarkPartiallyDependent();
3915 g2s2.handle.MarkPartiallyDependent();
3916 g3s1.handle.MarkPartiallyDependent();
3917 g3s2.handle.MarkPartiallyDependent();
3918 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3919 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3920 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3921 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3922 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3923 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3924 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3925 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3926 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3927 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3928 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3929 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3932 heap->CollectGarbage(i::NEW_SPACE);
3934 // All objects should be gone. 7 global handles in total.
3935 CHECK_EQ(7, counter.NumberOfWeakCalls());
3939 THREADED_TEST(ScriptException) {
3941 v8::HandleScope scope(env->GetIsolate());
3942 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3943 v8::TryCatch try_catch;
3944 Local<Value> result = script->Run();
3945 CHECK(result.IsEmpty());
3946 CHECK(try_catch.HasCaught());
3947 String::Utf8Value exception_value(try_catch.Exception());
3948 CHECK_EQ(*exception_value, "panama!");
3952 TEST(TryCatchCustomException) {
3954 v8::HandleScope scope(env->GetIsolate());
3955 v8::TryCatch try_catch;
3956 CompileRun("function CustomError() { this.a = 'b'; }"
3957 "(function f() { throw new CustomError(); })();");
3958 CHECK(try_catch.HasCaught());
3959 CHECK(try_catch.Exception()->ToObject()->
3960 Get(v8_str("a"))->Equals(v8_str("b")));
3964 bool message_received;
3967 static void check_message_0(v8::Handle<v8::Message> message,
3968 v8::Handle<Value> data) {
3969 CHECK_EQ(5.76, data->NumberValue());
3970 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3971 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3972 CHECK(!message->IsSharedCrossOrigin());
3973 message_received = true;
3977 THREADED_TEST(MessageHandler0) {
3978 message_received = false;
3979 v8::HandleScope scope(CcTest::isolate());
3980 CHECK(!message_received);
3981 LocalContext context;
3982 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3983 v8::ScriptOrigin origin =
3984 v8::ScriptOrigin(v8_str("6.75"));
3985 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3987 script->SetData(v8_str("7.56"));
3989 CHECK(message_received);
3990 // clear out the message listener
3991 v8::V8::RemoveMessageListeners(check_message_0);
3995 static void check_message_1(v8::Handle<v8::Message> message,
3996 v8::Handle<Value> data) {
3997 CHECK(data->IsNumber());
3998 CHECK_EQ(1337, data->Int32Value());
3999 CHECK(!message->IsSharedCrossOrigin());
4000 message_received = true;
4004 TEST(MessageHandler1) {
4005 message_received = false;
4006 v8::HandleScope scope(CcTest::isolate());
4007 CHECK(!message_received);
4008 v8::V8::AddMessageListener(check_message_1);
4009 LocalContext context;
4010 CompileRun("throw 1337;");
4011 CHECK(message_received);
4012 // clear out the message listener
4013 v8::V8::RemoveMessageListeners(check_message_1);
4017 static void check_message_2(v8::Handle<v8::Message> message,
4018 v8::Handle<Value> data) {
4019 LocalContext context;
4020 CHECK(data->IsObject());
4021 v8::Local<v8::Value> hidden_property =
4022 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4023 CHECK(v8_str("hidden value")->Equals(hidden_property));
4024 CHECK(!message->IsSharedCrossOrigin());
4025 message_received = true;
4029 TEST(MessageHandler2) {
4030 message_received = false;
4031 v8::HandleScope scope(CcTest::isolate());
4032 CHECK(!message_received);
4033 v8::V8::AddMessageListener(check_message_2);
4034 LocalContext context;
4035 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4036 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4037 v8_str("hidden value"));
4038 context->Global()->Set(v8_str("error"), error);
4039 CompileRun("throw error;");
4040 CHECK(message_received);
4041 // clear out the message listener
4042 v8::V8::RemoveMessageListeners(check_message_2);
4046 static void check_message_3(v8::Handle<v8::Message> message,
4047 v8::Handle<Value> data) {
4048 CHECK(message->IsSharedCrossOrigin());
4049 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4050 message_received = true;
4054 TEST(MessageHandler3) {
4055 message_received = false;
4056 v8::Isolate* isolate = CcTest::isolate();
4057 v8::HandleScope scope(isolate);
4058 CHECK(!message_received);
4059 v8::V8::AddMessageListener(check_message_3);
4060 LocalContext context;
4061 v8::ScriptOrigin origin =
4062 v8::ScriptOrigin(v8_str("6.75"),
4063 v8::Integer::New(isolate, 1),
4064 v8::Integer::New(isolate, 2),
4066 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4069 CHECK(message_received);
4070 // clear out the message listener
4071 v8::V8::RemoveMessageListeners(check_message_3);
4075 static void check_message_4(v8::Handle<v8::Message> message,
4076 v8::Handle<Value> data) {
4077 CHECK(!message->IsSharedCrossOrigin());
4078 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4079 message_received = true;
4083 TEST(MessageHandler4) {
4084 message_received = false;
4085 v8::Isolate* isolate = CcTest::isolate();
4086 v8::HandleScope scope(isolate);
4087 CHECK(!message_received);
4088 v8::V8::AddMessageListener(check_message_4);
4089 LocalContext context;
4090 v8::ScriptOrigin origin =
4091 v8::ScriptOrigin(v8_str("6.75"),
4092 v8::Integer::New(isolate, 1),
4093 v8::Integer::New(isolate, 2),
4094 v8::False(isolate));
4095 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4098 CHECK(message_received);
4099 // clear out the message listener
4100 v8::V8::RemoveMessageListeners(check_message_4);
4104 static void check_message_5a(v8::Handle<v8::Message> message,
4105 v8::Handle<Value> data) {
4106 CHECK(message->IsSharedCrossOrigin());
4107 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4108 message_received = true;
4112 static void check_message_5b(v8::Handle<v8::Message> message,
4113 v8::Handle<Value> data) {
4114 CHECK(!message->IsSharedCrossOrigin());
4115 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4116 message_received = true;
4120 TEST(MessageHandler5) {
4121 message_received = false;
4122 v8::Isolate* isolate = CcTest::isolate();
4123 v8::HandleScope scope(isolate);
4124 CHECK(!message_received);
4125 v8::V8::AddMessageListener(check_message_5a);
4126 LocalContext context;
4127 v8::ScriptOrigin origin =
4128 v8::ScriptOrigin(v8_str("6.75"),
4129 v8::Integer::New(isolate, 1),
4130 v8::Integer::New(isolate, 2),
4132 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4135 CHECK(message_received);
4136 // clear out the message listener
4137 v8::V8::RemoveMessageListeners(check_message_5a);
4139 message_received = false;
4140 v8::V8::AddMessageListener(check_message_5b);
4142 v8::ScriptOrigin(v8_str("6.75"),
4143 v8::Integer::New(isolate, 1),
4144 v8::Integer::New(isolate, 2),
4145 v8::False(isolate));
4146 script = Script::Compile(v8_str("throw 'error'"),
4149 CHECK(message_received);
4150 // clear out the message listener
4151 v8::V8::RemoveMessageListeners(check_message_5b);
4155 THREADED_TEST(GetSetProperty) {
4156 LocalContext context;
4157 v8::Isolate* isolate = context->GetIsolate();
4158 v8::HandleScope scope(isolate);
4159 context->Global()->Set(v8_str("foo"), v8_num(14));
4160 context->Global()->Set(v8_str("12"), v8_num(92));
4161 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4162 context->Global()->Set(v8_num(13), v8_num(56));
4163 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
4164 CHECK_EQ(14, foo->Int32Value());
4165 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
4166 CHECK_EQ(92, twelve->Int32Value());
4167 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
4168 CHECK_EQ(32, sixteen->Int32Value());
4169 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
4170 CHECK_EQ(56, thirteen->Int32Value());
4172 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4173 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4174 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4176 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4177 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4178 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4180 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4181 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4182 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4186 THREADED_TEST(PropertyAttributes) {
4187 LocalContext context;
4188 v8::HandleScope scope(context->GetIsolate());
4190 Local<String> prop = v8_str("none");
4191 context->Global()->Set(prop, v8_num(7));
4192 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4194 prop = v8_str("read_only");
4195 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4196 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4197 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4198 Script::Compile(v8_str("read_only = 9"))->Run();
4199 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4200 context->Global()->Set(prop, v8_num(10));
4201 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4203 prop = v8_str("dont_delete");
4204 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4205 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4206 Script::Compile(v8_str("delete dont_delete"))->Run();
4207 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4208 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4210 prop = v8_str("dont_enum");
4211 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4212 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4214 prop = v8_str("absent");
4215 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4216 Local<Value> fake_prop = v8_num(1);
4217 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4220 Local<Value> exception =
4221 CompileRun("({ toString: function() { throw 'exception';} })");
4222 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4223 CHECK(try_catch.HasCaught());
4224 String::Utf8Value exception_value(try_catch.Exception());
4225 CHECK_EQ("exception", *exception_value);
4230 THREADED_TEST(Array) {
4231 LocalContext context;
4232 v8::HandleScope scope(context->GetIsolate());
4233 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4234 CHECK_EQ(0, array->Length());
4235 CHECK(array->Get(0)->IsUndefined());
4236 CHECK(!array->Has(0));
4237 CHECK(array->Get(100)->IsUndefined());
4238 CHECK(!array->Has(100));
4239 array->Set(2, v8_num(7));
4240 CHECK_EQ(3, array->Length());
4241 CHECK(!array->Has(0));
4242 CHECK(!array->Has(1));
4243 CHECK(array->Has(2));
4244 CHECK_EQ(7, array->Get(2)->Int32Value());
4245 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4246 Local<v8::Array> arr = obj.As<v8::Array>();
4247 CHECK_EQ(3, arr->Length());
4248 CHECK_EQ(1, arr->Get(0)->Int32Value());
4249 CHECK_EQ(2, arr->Get(1)->Int32Value());
4250 CHECK_EQ(3, arr->Get(2)->Int32Value());
4251 array = v8::Array::New(context->GetIsolate(), 27);
4252 CHECK_EQ(27, array->Length());
4253 array = v8::Array::New(context->GetIsolate(), -27);
4254 CHECK_EQ(0, array->Length());
4258 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4259 v8::EscapableHandleScope scope(args.GetIsolate());
4260 ApiTestFuzzer::Fuzz();
4261 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4262 for (int i = 0; i < args.Length(); i++)
4263 result->Set(i, args[i]);
4264 args.GetReturnValue().Set(scope.Escape(result));
4268 THREADED_TEST(Vector) {
4269 v8::Isolate* isolate = CcTest::isolate();
4270 v8::HandleScope scope(isolate);
4271 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4272 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4273 LocalContext context(0, global);
4275 const char* fun = "f()";
4276 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4277 CHECK_EQ(0, a0->Length());
4279 const char* fun2 = "f(11)";
4280 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4281 CHECK_EQ(1, a1->Length());
4282 CHECK_EQ(11, a1->Get(0)->Int32Value());
4284 const char* fun3 = "f(12, 13)";
4285 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4286 CHECK_EQ(2, a2->Length());
4287 CHECK_EQ(12, a2->Get(0)->Int32Value());
4288 CHECK_EQ(13, a2->Get(1)->Int32Value());
4290 const char* fun4 = "f(14, 15, 16)";
4291 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4292 CHECK_EQ(3, a3->Length());
4293 CHECK_EQ(14, a3->Get(0)->Int32Value());
4294 CHECK_EQ(15, a3->Get(1)->Int32Value());
4295 CHECK_EQ(16, a3->Get(2)->Int32Value());
4297 const char* fun5 = "f(17, 18, 19, 20)";
4298 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4299 CHECK_EQ(4, a4->Length());
4300 CHECK_EQ(17, a4->Get(0)->Int32Value());
4301 CHECK_EQ(18, a4->Get(1)->Int32Value());
4302 CHECK_EQ(19, a4->Get(2)->Int32Value());
4303 CHECK_EQ(20, a4->Get(3)->Int32Value());
4307 THREADED_TEST(FunctionCall) {
4308 LocalContext context;
4309 v8::Isolate* isolate = context->GetIsolate();
4310 v8::HandleScope scope(isolate);
4314 " for (var i = 0; i < arguments.length; i++) {"
4315 " result.push(arguments[i]);"
4319 "function ReturnThisSloppy() {"
4322 "function ReturnThisStrict() {"
4326 Local<Function> Foo =
4327 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4328 Local<Function> ReturnThisSloppy =
4329 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4330 Local<Function> ReturnThisStrict =
4331 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4333 v8::Handle<Value>* args0 = NULL;
4334 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4335 CHECK_EQ(0, a0->Length());
4337 v8::Handle<Value> args1[] = { v8_num(1.1) };
4338 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4339 CHECK_EQ(1, a1->Length());
4340 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4342 v8::Handle<Value> args2[] = { v8_num(2.2),
4344 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4345 CHECK_EQ(2, a2->Length());
4346 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4347 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4349 v8::Handle<Value> args3[] = { v8_num(4.4),
4352 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4353 CHECK_EQ(3, a3->Length());
4354 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4355 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4356 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4358 v8::Handle<Value> args4[] = { v8_num(7.7),
4362 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4363 CHECK_EQ(4, a4->Length());
4364 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4365 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4366 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4367 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4369 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4370 CHECK(r1->StrictEquals(context->Global()));
4371 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4372 CHECK(r2->StrictEquals(context->Global()));
4373 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4374 CHECK(r3->IsNumberObject());
4375 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4376 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4377 CHECK(r4->IsStringObject());
4378 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4379 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4380 CHECK(r5->IsBooleanObject());
4381 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4383 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4384 CHECK(r6->IsUndefined());
4385 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4386 CHECK(r7->IsNull());
4387 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4388 CHECK(r8->StrictEquals(v8_num(42)));
4389 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4390 CHECK(r9->StrictEquals(v8_str("hello")));
4391 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4392 CHECK(r10->StrictEquals(v8::True(isolate)));
4396 static const char* js_code_causing_out_of_memory =
4397 "var a = new Array(); while(true) a.push(a);";
4400 // These tests run for a long time and prevent us from running tests
4401 // that come after them so they cannot run in parallel.
4403 // It's not possible to read a snapshot into a heap with different dimensions.
4404 if (i::Snapshot::IsEnabled()) return;
4406 static const int K = 1024;
4407 v8::ResourceConstraints constraints;
4408 constraints.set_max_young_space_size(256 * K);
4409 constraints.set_max_old_space_size(5 * K * K);
4410 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4412 // Execute a script that causes out of memory.
4413 LocalContext context;
4414 v8::HandleScope scope(context->GetIsolate());
4415 v8::V8::IgnoreOutOfMemoryException();
4416 Local<Script> script = Script::Compile(String::NewFromUtf8(
4417 context->GetIsolate(), js_code_causing_out_of_memory));
4418 Local<Value> result = script->Run();
4420 // Check for out of memory state.
4421 CHECK(result.IsEmpty());
4422 CHECK(context->HasOutOfMemoryException());
4426 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4427 ApiTestFuzzer::Fuzz();
4429 LocalContext context;
4430 v8::HandleScope scope(context->GetIsolate());
4431 Local<Script> script = Script::Compile(String::NewFromUtf8(
4432 context->GetIsolate(), js_code_causing_out_of_memory));
4433 Local<Value> result = script->Run();
4435 // Check for out of memory state.
4436 CHECK(result.IsEmpty());
4437 CHECK(context->HasOutOfMemoryException());
4439 args.GetReturnValue().Set(result);
4443 TEST(OutOfMemoryNested) {
4444 // It's not possible to read a snapshot into a heap with different dimensions.
4445 if (i::Snapshot::IsEnabled()) return;
4447 static const int K = 1024;
4448 v8::ResourceConstraints constraints;
4449 constraints.set_max_young_space_size(256 * K);
4450 constraints.set_max_old_space_size(5 * K * K);
4451 v8::Isolate* isolate = CcTest::isolate();
4452 v8::SetResourceConstraints(isolate, &constraints);
4454 v8::HandleScope scope(isolate);
4455 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4456 templ->Set(v8_str("ProvokeOutOfMemory"),
4457 v8::FunctionTemplate::New(isolate, ProvokeOutOfMemory));
4458 LocalContext context(0, templ);
4459 v8::V8::IgnoreOutOfMemoryException();
4460 Local<Value> result = CompileRun(
4461 "var thrown = false;"
4463 " ProvokeOutOfMemory();"
4467 // Check for out of memory state.
4468 CHECK(result.IsEmpty());
4469 CHECK(context->HasOutOfMemoryException());
4473 void OOMCallback(const char* location, const char* message) {
4478 TEST(HugeConsStringOutOfMemory) {
4479 // It's not possible to read a snapshot into a heap with different dimensions.
4480 if (i::Snapshot::IsEnabled()) return;
4482 static const int K = 1024;
4483 v8::ResourceConstraints constraints;
4484 constraints.set_max_young_space_size(256 * K);
4485 constraints.set_max_old_space_size(4 * K * K);
4486 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4488 // Execute a script that causes out of memory.
4489 v8::V8::SetFatalErrorHandler(OOMCallback);
4491 LocalContext context;
4492 v8::HandleScope scope(context->GetIsolate());
4494 // Build huge string. This should fail with out of memory exception.
4496 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4497 "for (var i = 0; i < 22; i++) { str = str + str; }");
4499 CHECK(false); // Should not return.
4503 THREADED_TEST(ConstructCall) {
4504 LocalContext context;
4505 v8::Isolate* isolate = context->GetIsolate();
4506 v8::HandleScope scope(isolate);
4510 " for (var i = 0; i < arguments.length; i++) {"
4511 " result.push(arguments[i]);"
4515 Local<Function> Foo =
4516 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4518 v8::Handle<Value>* args0 = NULL;
4519 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4520 CHECK_EQ(0, a0->Length());
4522 v8::Handle<Value> args1[] = { v8_num(1.1) };
4523 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4524 CHECK_EQ(1, a1->Length());
4525 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4527 v8::Handle<Value> args2[] = { v8_num(2.2),
4529 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4530 CHECK_EQ(2, a2->Length());
4531 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4532 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4534 v8::Handle<Value> args3[] = { v8_num(4.4),
4537 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4538 CHECK_EQ(3, a3->Length());
4539 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4540 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4541 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4543 v8::Handle<Value> args4[] = { v8_num(7.7),
4547 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4548 CHECK_EQ(4, a4->Length());
4549 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4550 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4551 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4552 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4556 static void CheckUncle(v8::TryCatch* try_catch) {
4557 CHECK(try_catch->HasCaught());
4558 String::Utf8Value str_value(try_catch->Exception());
4559 CHECK_EQ(*str_value, "uncle?");
4564 THREADED_TEST(ConversionNumber) {
4566 v8::HandleScope scope(env->GetIsolate());
4567 // Very large number.
4568 CompileRun("var obj = Math.pow(2,32) * 1237;");
4569 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4570 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4571 CHECK_EQ(0, obj->ToInt32()->Value());
4572 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4574 CompileRun("var obj = -1234567890123;");
4575 obj = env->Global()->Get(v8_str("obj"));
4576 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4577 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4578 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4579 // Small positive integer.
4580 CompileRun("var obj = 42;");
4581 obj = env->Global()->Get(v8_str("obj"));
4582 CHECK_EQ(42.0, obj->ToNumber()->Value());
4583 CHECK_EQ(42, obj->ToInt32()->Value());
4584 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4585 // Negative integer.
4586 CompileRun("var obj = -37;");
4587 obj = env->Global()->Get(v8_str("obj"));
4588 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4589 CHECK_EQ(-37, obj->ToInt32()->Value());
4590 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4591 // Positive non-int32 integer.
4592 CompileRun("var obj = 0x81234567;");
4593 obj = env->Global()->Get(v8_str("obj"));
4594 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4595 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4596 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4598 CompileRun("var obj = 42.3;");
4599 obj = env->Global()->Get(v8_str("obj"));
4600 CHECK_EQ(42.3, obj->ToNumber()->Value());
4601 CHECK_EQ(42, obj->ToInt32()->Value());
4602 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4603 // Large negative fraction.
4604 CompileRun("var obj = -5726623061.75;");
4605 obj = env->Global()->Get(v8_str("obj"));
4606 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4607 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4608 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4612 THREADED_TEST(isNumberType) {
4614 v8::HandleScope scope(env->GetIsolate());
4615 // Very large number.
4616 CompileRun("var obj = Math.pow(2,32) * 1237;");
4617 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4618 CHECK(!obj->IsInt32());
4619 CHECK(!obj->IsUint32());
4620 // Large negative number.
4621 CompileRun("var obj = -1234567890123;");
4622 obj = env->Global()->Get(v8_str("obj"));
4623 CHECK(!obj->IsInt32());
4624 CHECK(!obj->IsUint32());
4625 // Small positive integer.
4626 CompileRun("var obj = 42;");
4627 obj = env->Global()->Get(v8_str("obj"));
4628 CHECK(obj->IsInt32());
4629 CHECK(obj->IsUint32());
4630 // Negative integer.
4631 CompileRun("var obj = -37;");
4632 obj = env->Global()->Get(v8_str("obj"));
4633 CHECK(obj->IsInt32());
4634 CHECK(!obj->IsUint32());
4635 // Positive non-int32 integer.
4636 CompileRun("var obj = 0x81234567;");
4637 obj = env->Global()->Get(v8_str("obj"));
4638 CHECK(!obj->IsInt32());
4639 CHECK(obj->IsUint32());
4641 CompileRun("var obj = 42.3;");
4642 obj = env->Global()->Get(v8_str("obj"));
4643 CHECK(!obj->IsInt32());
4644 CHECK(!obj->IsUint32());
4645 // Large negative fraction.
4646 CompileRun("var obj = -5726623061.75;");
4647 obj = env->Global()->Get(v8_str("obj"));
4648 CHECK(!obj->IsInt32());
4649 CHECK(!obj->IsUint32());
4651 CompileRun("var obj = 0.0;");
4652 obj = env->Global()->Get(v8_str("obj"));
4653 CHECK(obj->IsInt32());
4654 CHECK(obj->IsUint32());
4656 CompileRun("var obj = -0.0;");
4657 obj = env->Global()->Get(v8_str("obj"));
4658 CHECK(!obj->IsInt32());
4659 CHECK(!obj->IsUint32());
4663 THREADED_TEST(ConversionException) {
4665 v8::Isolate* isolate = env->GetIsolate();
4666 v8::HandleScope scope(isolate);
4668 "function TestClass() { };"
4669 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4670 "var obj = new TestClass();");
4671 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4673 v8::TryCatch try_catch;
4675 Local<Value> to_string_result = obj->ToString();
4676 CHECK(to_string_result.IsEmpty());
4677 CheckUncle(&try_catch);
4679 Local<Value> to_number_result = obj->ToNumber();
4680 CHECK(to_number_result.IsEmpty());
4681 CheckUncle(&try_catch);
4683 Local<Value> to_integer_result = obj->ToInteger();
4684 CHECK(to_integer_result.IsEmpty());
4685 CheckUncle(&try_catch);
4687 Local<Value> to_uint32_result = obj->ToUint32();
4688 CHECK(to_uint32_result.IsEmpty());
4689 CheckUncle(&try_catch);
4691 Local<Value> to_int32_result = obj->ToInt32();
4692 CHECK(to_int32_result.IsEmpty());
4693 CheckUncle(&try_catch);
4695 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4696 CHECK(to_object_result.IsEmpty());
4697 CHECK(try_catch.HasCaught());
4700 int32_t int32_value = obj->Int32Value();
4701 CHECK_EQ(0, int32_value);
4702 CheckUncle(&try_catch);
4704 uint32_t uint32_value = obj->Uint32Value();
4705 CHECK_EQ(0, uint32_value);
4706 CheckUncle(&try_catch);
4708 double number_value = obj->NumberValue();
4709 CHECK_NE(0, std::isnan(number_value));
4710 CheckUncle(&try_catch);
4712 int64_t integer_value = obj->IntegerValue();
4713 CHECK_EQ(0.0, static_cast<double>(integer_value));
4714 CheckUncle(&try_catch);
4718 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4719 ApiTestFuzzer::Fuzz();
4720 args.GetIsolate()->ThrowException(v8_str("konto"));
4724 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4725 if (args.Length() < 1) {
4726 args.GetReturnValue().Set(false);
4729 v8::HandleScope scope(args.GetIsolate());
4730 v8::TryCatch try_catch;
4731 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4732 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4733 args.GetReturnValue().Set(try_catch.HasCaught());
4737 THREADED_TEST(APICatch) {
4738 v8::Isolate* isolate = CcTest::isolate();
4739 v8::HandleScope scope(isolate);
4740 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4741 templ->Set(v8_str("ThrowFromC"),
4742 v8::FunctionTemplate::New(isolate, ThrowFromC));
4743 LocalContext context(0, templ);
4745 "var thrown = false;"
4751 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4752 CHECK(thrown->BooleanValue());
4756 THREADED_TEST(APIThrowTryCatch) {
4757 v8::Isolate* isolate = CcTest::isolate();
4758 v8::HandleScope scope(isolate);
4759 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4760 templ->Set(v8_str("ThrowFromC"),
4761 v8::FunctionTemplate::New(isolate, ThrowFromC));
4762 LocalContext context(0, templ);
4763 v8::TryCatch try_catch;
4764 CompileRun("ThrowFromC();");
4765 CHECK(try_catch.HasCaught());
4769 // Test that a try-finally block doesn't shadow a try-catch block
4770 // when setting up an external handler.
4772 // BUG(271): Some of the exception propagation does not work on the
4773 // ARM simulator because the simulator separates the C++ stack and the
4774 // JS stack. This test therefore fails on the simulator. The test is
4775 // not threaded to allow the threading tests to run on the simulator.
4776 TEST(TryCatchInTryFinally) {
4777 v8::Isolate* isolate = CcTest::isolate();
4778 v8::HandleScope scope(isolate);
4779 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4780 templ->Set(v8_str("CCatcher"),
4781 v8::FunctionTemplate::New(isolate, CCatcher));
4782 LocalContext context(0, templ);
4783 Local<Value> result = CompileRun("try {"
4785 " CCatcher('throw 7;');"
4790 CHECK(result->IsTrue());
4794 static void check_reference_error_message(
4795 v8::Handle<v8::Message> message,
4796 v8::Handle<v8::Value> data) {
4797 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4798 CHECK(message->Get()->Equals(v8_str(reference_error)));
4802 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4803 ApiTestFuzzer::Fuzz();
4808 // Test that overwritten methods are not invoked on uncaught exception
4809 // formatting. However, they are invoked when performing normal error
4810 // string conversions.
4811 TEST(APIThrowMessageOverwrittenToString) {
4812 v8::Isolate* isolate = CcTest::isolate();
4813 v8::HandleScope scope(isolate);
4814 v8::V8::AddMessageListener(check_reference_error_message);
4815 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4816 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4817 LocalContext context(NULL, templ);
4818 CompileRun("asdf;");
4819 CompileRun("var limit = {};"
4820 "limit.valueOf = fail;"
4821 "Error.stackTraceLimit = limit;");
4823 CompileRun("Array.prototype.pop = fail;");
4824 CompileRun("Object.prototype.hasOwnProperty = fail;");
4825 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4826 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4827 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4828 CompileRun("ReferenceError.prototype.toString ="
4829 " function() { return 'Whoops' }");
4830 CompileRun("asdf;");
4831 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4832 CompileRun("asdf;");
4833 CompileRun("ReferenceError.prototype.constructor = void 0;");
4834 CompileRun("asdf;");
4835 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4836 CompileRun("asdf;");
4837 CompileRun("ReferenceError.prototype = new Object();");
4838 CompileRun("asdf;");
4839 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4840 CHECK(string->Equals(v8_str("Whoops")));
4841 CompileRun("ReferenceError.prototype.constructor = new Object();"
4842 "ReferenceError.prototype.constructor.name = 1;"
4843 "Number.prototype.toString = function() { return 'Whoops'; };"
4844 "ReferenceError.prototype.toString = Object.prototype.toString;");
4845 CompileRun("asdf;");
4846 v8::V8::RemoveMessageListeners(check_reference_error_message);
4850 static void check_custom_error_tostring(
4851 v8::Handle<v8::Message> message,
4852 v8::Handle<v8::Value> data) {
4853 const char* uncaught_error = "Uncaught MyError toString";
4854 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4858 TEST(CustomErrorToString) {
4859 LocalContext context;
4860 v8::HandleScope scope(context->GetIsolate());
4861 v8::V8::AddMessageListener(check_custom_error_tostring);
4863 "function MyError(name, message) { "
4864 " this.name = name; "
4865 " this.message = message; "
4867 "MyError.prototype = Object.create(Error.prototype); "
4868 "MyError.prototype.toString = function() { "
4869 " return 'MyError toString'; "
4871 "throw new MyError('my name', 'my message'); ");
4872 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4876 static void check_custom_error_message(
4877 v8::Handle<v8::Message> message,
4878 v8::Handle<v8::Value> data) {
4879 const char* uncaught_error = "Uncaught MyError: my message";
4880 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4881 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4885 TEST(CustomErrorMessage) {
4886 LocalContext context;
4887 v8::HandleScope scope(context->GetIsolate());
4888 v8::V8::AddMessageListener(check_custom_error_message);
4892 "function MyError(msg) { "
4893 " this.name = 'MyError'; "
4894 " this.message = msg; "
4896 "MyError.prototype = new Error(); "
4897 "throw new MyError('my message'); ");
4901 "function MyError(msg) { "
4902 " this.name = 'MyError'; "
4903 " this.message = msg; "
4905 "inherits = function(childCtor, parentCtor) { "
4906 " function tempCtor() {}; "
4907 " tempCtor.prototype = parentCtor.prototype; "
4908 " childCtor.superClass_ = parentCtor.prototype; "
4909 " childCtor.prototype = new tempCtor(); "
4910 " childCtor.prototype.constructor = childCtor; "
4912 "inherits(MyError, Error); "
4913 "throw new MyError('my message'); ");
4917 "function MyError(msg) { "
4918 " this.name = 'MyError'; "
4919 " this.message = msg; "
4921 "MyError.prototype = Object.create(Error.prototype); "
4922 "throw new MyError('my message'); ");
4924 v8::V8::RemoveMessageListeners(check_custom_error_message);
4928 static void receive_message(v8::Handle<v8::Message> message,
4929 v8::Handle<v8::Value> data) {
4931 message_received = true;
4935 TEST(APIThrowMessage) {
4936 message_received = false;
4937 v8::Isolate* isolate = CcTest::isolate();
4938 v8::HandleScope scope(isolate);
4939 v8::V8::AddMessageListener(receive_message);
4940 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4941 templ->Set(v8_str("ThrowFromC"),
4942 v8::FunctionTemplate::New(isolate, ThrowFromC));
4943 LocalContext context(0, templ);
4944 CompileRun("ThrowFromC();");
4945 CHECK(message_received);
4946 v8::V8::RemoveMessageListeners(receive_message);
4950 TEST(APIThrowMessageAndVerboseTryCatch) {
4951 message_received = false;
4952 v8::Isolate* isolate = CcTest::isolate();
4953 v8::HandleScope scope(isolate);
4954 v8::V8::AddMessageListener(receive_message);
4955 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4956 templ->Set(v8_str("ThrowFromC"),
4957 v8::FunctionTemplate::New(isolate, ThrowFromC));
4958 LocalContext context(0, templ);
4959 v8::TryCatch try_catch;
4960 try_catch.SetVerbose(true);
4961 Local<Value> result = CompileRun("ThrowFromC();");
4962 CHECK(try_catch.HasCaught());
4963 CHECK(result.IsEmpty());
4964 CHECK(message_received);
4965 v8::V8::RemoveMessageListeners(receive_message);
4969 TEST(APIStackOverflowAndVerboseTryCatch) {
4970 message_received = false;
4971 LocalContext context;
4972 v8::HandleScope scope(context->GetIsolate());
4973 v8::V8::AddMessageListener(receive_message);
4974 v8::TryCatch try_catch;
4975 try_catch.SetVerbose(true);
4976 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4977 CHECK(try_catch.HasCaught());
4978 CHECK(result.IsEmpty());
4979 CHECK(message_received);
4980 v8::V8::RemoveMessageListeners(receive_message);
4984 THREADED_TEST(ExternalScriptException) {
4985 v8::Isolate* isolate = CcTest::isolate();
4986 v8::HandleScope scope(isolate);
4987 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4988 templ->Set(v8_str("ThrowFromC"),
4989 v8::FunctionTemplate::New(isolate, ThrowFromC));
4990 LocalContext context(0, templ);
4992 v8::TryCatch try_catch;
4993 Local<Script> script
4994 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4995 Local<Value> result = script->Run();
4996 CHECK(result.IsEmpty());
4997 CHECK(try_catch.HasCaught());
4998 String::Utf8Value exception_value(try_catch.Exception());
4999 CHECK_EQ("konto", *exception_value);
5004 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5005 ApiTestFuzzer::Fuzz();
5006 CHECK_EQ(4, args.Length());
5007 int count = args[0]->Int32Value();
5008 int cInterval = args[2]->Int32Value();
5010 args.GetIsolate()->ThrowException(v8_str("FromC"));
5013 Local<v8::Object> global =
5014 args.GetIsolate()->GetCurrentContext()->Global();
5015 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5016 v8::Handle<Value> argv[] = { v8_num(count - 1),
5020 if (count % cInterval == 0) {
5021 v8::TryCatch try_catch;
5022 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5023 int expected = args[3]->Int32Value();
5024 if (try_catch.HasCaught()) {
5025 CHECK_EQ(expected, count);
5026 CHECK(result.IsEmpty());
5027 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5029 CHECK_NE(expected, count);
5031 args.GetReturnValue().Set(result);
5034 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5041 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5042 ApiTestFuzzer::Fuzz();
5043 CHECK_EQ(3, args.Length());
5044 bool equality = args[0]->BooleanValue();
5045 int count = args[1]->Int32Value();
5046 int expected = args[2]->Int32Value();
5048 CHECK_EQ(count, expected);
5050 CHECK_NE(count, expected);
5055 THREADED_TEST(EvalInTryFinally) {
5056 LocalContext context;
5057 v8::HandleScope scope(context->GetIsolate());
5058 v8::TryCatch try_catch;
5059 CompileRun("(function() {"
5061 " eval('asldkf (*&^&*^');"
5066 CHECK(!try_catch.HasCaught());
5070 // This test works by making a stack of alternating JavaScript and C
5071 // activations. These activations set up exception handlers with regular
5072 // intervals, one interval for C activations and another for JavaScript
5073 // activations. When enough activations have been created an exception is
5074 // thrown and we check that the right activation catches the exception and that
5075 // no other activations do. The right activation is always the topmost one with
5076 // a handler, regardless of whether it is in JavaScript or C.
5078 // The notation used to describe a test case looks like this:
5080 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5082 // Each entry is an activation, either JS or C. The index is the count at that
5083 // level. Stars identify activations with exception handlers, the @ identifies
5084 // the exception handler that should catch the exception.
5086 // BUG(271): Some of the exception propagation does not work on the
5087 // ARM simulator because the simulator separates the C++ stack and the
5088 // JS stack. This test therefore fails on the simulator. The test is
5089 // not threaded to allow the threading tests to run on the simulator.
5090 TEST(ExceptionOrder) {
5091 v8::Isolate* isolate = CcTest::isolate();
5092 v8::HandleScope scope(isolate);
5093 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5094 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5095 templ->Set(v8_str("CThrowCountDown"),
5096 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5097 LocalContext context(0, templ);
5099 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5100 " if (count == 0) throw 'FromJS';"
5101 " if (count % jsInterval == 0) {"
5103 " var value = CThrowCountDown(count - 1,"
5107 " check(false, count, expected);"
5110 " check(true, count, expected);"
5113 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5116 Local<Function> fun =
5117 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5120 // count jsInterval cInterval expected
5122 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5123 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5124 fun->Call(fun, argc, a0);
5126 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5127 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5128 fun->Call(fun, argc, a1);
5130 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5131 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5132 fun->Call(fun, argc, a2);
5134 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5135 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5136 fun->Call(fun, argc, a3);
5138 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5139 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5140 fun->Call(fun, argc, a4);
5142 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5143 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5144 fun->Call(fun, argc, a5);
5148 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5149 ApiTestFuzzer::Fuzz();
5150 CHECK_EQ(1, args.Length());
5151 args.GetIsolate()->ThrowException(args[0]);
5155 THREADED_TEST(ThrowValues) {
5156 v8::Isolate* isolate = CcTest::isolate();
5157 v8::HandleScope scope(isolate);
5158 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5159 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5160 LocalContext context(0, templ);
5161 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5162 "function Run(obj) {"
5168 " return 'no exception';"
5170 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5171 CHECK_EQ(5, result->Length());
5172 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5173 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5174 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5175 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5176 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5177 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5178 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5182 THREADED_TEST(CatchZero) {
5183 LocalContext context;
5184 v8::HandleScope scope(context->GetIsolate());
5185 v8::TryCatch try_catch;
5186 CHECK(!try_catch.HasCaught());
5187 Script::Compile(v8_str("throw 10"))->Run();
5188 CHECK(try_catch.HasCaught());
5189 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5191 CHECK(!try_catch.HasCaught());
5192 Script::Compile(v8_str("throw 0"))->Run();
5193 CHECK(try_catch.HasCaught());
5194 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5198 THREADED_TEST(CatchExceptionFromWith) {
5199 LocalContext context;
5200 v8::HandleScope scope(context->GetIsolate());
5201 v8::TryCatch try_catch;
5202 CHECK(!try_catch.HasCaught());
5203 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
5204 CHECK(try_catch.HasCaught());
5208 THREADED_TEST(TryCatchAndFinallyHidingException) {
5209 LocalContext context;
5210 v8::HandleScope scope(context->GetIsolate());
5211 v8::TryCatch try_catch;
5212 CHECK(!try_catch.HasCaught());
5213 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5214 CompileRun("f({toString: function() { throw 42; }});");
5215 CHECK(!try_catch.HasCaught());
5219 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5220 v8::TryCatch try_catch;
5224 THREADED_TEST(TryCatchAndFinally) {
5225 LocalContext context;
5226 v8::Isolate* isolate = context->GetIsolate();
5227 v8::HandleScope scope(isolate);
5228 context->Global()->Set(
5229 v8_str("native_with_try_catch"),
5230 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5231 v8::TryCatch try_catch;
5232 CHECK(!try_catch.HasCaught());
5235 " throw new Error('a');\n"
5237 " native_with_try_catch();\n"
5239 CHECK(try_catch.HasCaught());
5243 static void TryCatchNestedHelper(int depth) {
5245 v8::TryCatch try_catch;
5246 try_catch.SetVerbose(true);
5247 TryCatchNestedHelper(depth - 1);
5248 CHECK(try_catch.HasCaught());
5249 try_catch.ReThrow();
5251 CcTest::isolate()->ThrowException(v8_str("back"));
5256 TEST(TryCatchNested) {
5257 v8::V8::Initialize();
5258 LocalContext context;
5259 v8::HandleScope scope(context->GetIsolate());
5260 v8::TryCatch try_catch;
5261 TryCatchNestedHelper(5);
5262 CHECK(try_catch.HasCaught());
5263 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5267 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5268 CHECK(try_catch->HasCaught());
5269 Handle<Message> message = try_catch->Message();
5270 Handle<Value> resource = message->GetScriptResourceName();
5271 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5272 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5273 "Uncaught Error: a"));
5274 CHECK_EQ(1, message->GetLineNumber());
5275 CHECK_EQ(6, message->GetStartColumn());
5279 void TryCatchMixedNestingHelper(
5280 const v8::FunctionCallbackInfo<v8::Value>& args) {
5281 ApiTestFuzzer::Fuzz();
5282 v8::TryCatch try_catch;
5283 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5284 CHECK(try_catch.HasCaught());
5285 TryCatchMixedNestingCheck(&try_catch);
5286 try_catch.ReThrow();
5290 // This test ensures that an outer TryCatch in the following situation:
5291 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5292 // does not clobber the Message object generated for the inner TryCatch.
5293 // This exercises the ability of TryCatch.ReThrow() to restore the
5294 // inner pending Message before throwing the exception again.
5295 TEST(TryCatchMixedNesting) {
5296 v8::Isolate* isolate = CcTest::isolate();
5297 v8::HandleScope scope(isolate);
5298 v8::V8::Initialize();
5299 v8::TryCatch try_catch;
5300 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5301 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5302 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5303 LocalContext context(0, templ);
5304 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5305 TryCatchMixedNestingCheck(&try_catch);
5309 THREADED_TEST(Equality) {
5310 LocalContext context;
5311 v8::Isolate* isolate = context->GetIsolate();
5312 v8::HandleScope scope(context->GetIsolate());
5313 // Check that equality works at all before relying on CHECK_EQ
5314 CHECK(v8_str("a")->Equals(v8_str("a")));
5315 CHECK(!v8_str("a")->Equals(v8_str("b")));
5317 CHECK_EQ(v8_str("a"), v8_str("a"));
5318 CHECK_NE(v8_str("a"), v8_str("b"));
5319 CHECK_EQ(v8_num(1), v8_num(1));
5320 CHECK_EQ(v8_num(1.00), v8_num(1));
5321 CHECK_NE(v8_num(1), v8_num(2));
5323 // Assume String is not internalized.
5324 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5325 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5326 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5327 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5328 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5329 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5330 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5331 CHECK(!not_a_number->StrictEquals(not_a_number));
5332 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5333 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5335 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5336 v8::Persistent<v8::Object> alias(isolate, obj);
5337 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5340 CHECK(v8_str("a")->SameValue(v8_str("a")));
5341 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5342 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5343 CHECK(v8_num(1)->SameValue(v8_num(1)));
5344 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5345 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5346 CHECK(not_a_number->SameValue(not_a_number));
5347 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5348 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5352 THREADED_TEST(MultiRun) {
5353 LocalContext context;
5354 v8::HandleScope scope(context->GetIsolate());
5355 Local<Script> script = Script::Compile(v8_str("x"));
5356 for (int i = 0; i < 10; i++)
5361 static void GetXValue(Local<String> name,
5362 const v8::PropertyCallbackInfo<v8::Value>& info) {
5363 ApiTestFuzzer::Fuzz();
5364 CHECK_EQ(info.Data(), v8_str("donut"));
5365 CHECK_EQ(name, v8_str("x"));
5366 info.GetReturnValue().Set(name);
5370 THREADED_TEST(SimplePropertyRead) {
5371 LocalContext context;
5372 v8::Isolate* isolate = context->GetIsolate();
5373 v8::HandleScope scope(isolate);
5374 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5375 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5376 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5377 Local<Script> script = Script::Compile(v8_str("obj.x"));
5378 for (int i = 0; i < 10; i++) {
5379 Local<Value> result = script->Run();
5380 CHECK_EQ(result, v8_str("x"));
5385 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5386 LocalContext context;
5387 v8::Isolate* isolate = context->GetIsolate();
5388 v8::HandleScope scope(isolate);
5389 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5390 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5391 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5393 // Uses getOwnPropertyDescriptor to check the configurable status
5394 Local<Script> script_desc
5395 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5397 "prop.configurable;"));
5398 Local<Value> result = script_desc->Run();
5399 CHECK_EQ(result->BooleanValue(), true);
5401 // Redefine get - but still configurable
5402 Local<Script> script_define
5403 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5404 " configurable: true };"
5405 "Object.defineProperty(obj, 'x', desc);"
5407 result = script_define->Run();
5408 CHECK_EQ(result, v8_num(42));
5410 // Check that the accessor is still configurable
5411 result = script_desc->Run();
5412 CHECK_EQ(result->BooleanValue(), true);
5414 // Redefine to a non-configurable
5416 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5417 " configurable: false };"
5418 "Object.defineProperty(obj, 'x', desc);"
5420 result = script_define->Run();
5421 CHECK_EQ(result, v8_num(43));
5422 result = script_desc->Run();
5423 CHECK_EQ(result->BooleanValue(), false);
5425 // Make sure that it is not possible to redefine again
5426 v8::TryCatch try_catch;
5427 result = script_define->Run();
5428 CHECK(try_catch.HasCaught());
5429 String::Utf8Value exception_value(try_catch.Exception());
5430 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5434 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5435 v8::Isolate* isolate = CcTest::isolate();
5436 v8::HandleScope scope(isolate);
5437 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5438 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5439 LocalContext context;
5440 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5442 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5443 "Object.getOwnPropertyDescriptor( "
5445 "prop.configurable;"));
5446 Local<Value> result = script_desc->Run();
5447 CHECK_EQ(result->BooleanValue(), true);
5449 Local<Script> script_define =
5450 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5451 " configurable: true };"
5452 "Object.defineProperty(obj, 'x', desc);"
5454 result = script_define->Run();
5455 CHECK_EQ(result, v8_num(42));
5458 result = script_desc->Run();
5459 CHECK_EQ(result->BooleanValue(), true);
5463 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5464 " configurable: false };"
5465 "Object.defineProperty(obj, 'x', desc);"
5467 result = script_define->Run();
5468 CHECK_EQ(result, v8_num(43));
5469 result = script_desc->Run();
5471 CHECK_EQ(result->BooleanValue(), false);
5473 v8::TryCatch try_catch;
5474 result = script_define->Run();
5475 CHECK(try_catch.HasCaught());
5476 String::Utf8Value exception_value(try_catch.Exception());
5477 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5481 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5483 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5487 THREADED_TEST(DefineAPIAccessorOnObject) {
5488 v8::Isolate* isolate = CcTest::isolate();
5489 v8::HandleScope scope(isolate);
5490 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5491 LocalContext context;
5493 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5494 CompileRun("var obj2 = {};");
5496 CHECK(CompileRun("obj1.x")->IsUndefined());
5497 CHECK(CompileRun("obj2.x")->IsUndefined());
5499 CHECK(GetGlobalProperty(&context, "obj1")->
5500 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5502 ExpectString("obj1.x", "x");
5503 CHECK(CompileRun("obj2.x")->IsUndefined());
5505 CHECK(GetGlobalProperty(&context, "obj2")->
5506 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5508 ExpectString("obj1.x", "x");
5509 ExpectString("obj2.x", "x");
5511 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5512 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5514 CompileRun("Object.defineProperty(obj1, 'x',"
5515 "{ get: function() { return 'y'; }, configurable: true })");
5517 ExpectString("obj1.x", "y");
5518 ExpectString("obj2.x", "x");
5520 CompileRun("Object.defineProperty(obj2, 'x',"
5521 "{ get: function() { return 'y'; }, configurable: true })");
5523 ExpectString("obj1.x", "y");
5524 ExpectString("obj2.x", "y");
5526 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5527 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5529 CHECK(GetGlobalProperty(&context, "obj1")->
5530 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5531 CHECK(GetGlobalProperty(&context, "obj2")->
5532 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5534 ExpectString("obj1.x", "x");
5535 ExpectString("obj2.x", "x");
5537 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5538 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5540 // Define getters/setters, but now make them not configurable.
5541 CompileRun("Object.defineProperty(obj1, 'x',"
5542 "{ get: function() { return 'z'; }, configurable: false })");
5543 CompileRun("Object.defineProperty(obj2, 'x',"
5544 "{ get: function() { return 'z'; }, configurable: false })");
5546 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5547 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5549 ExpectString("obj1.x", "z");
5550 ExpectString("obj2.x", "z");
5552 CHECK(!GetGlobalProperty(&context, "obj1")->
5553 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5554 CHECK(!GetGlobalProperty(&context, "obj2")->
5555 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5557 ExpectString("obj1.x", "z");
5558 ExpectString("obj2.x", "z");
5562 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5563 v8::Isolate* isolate = CcTest::isolate();
5564 v8::HandleScope scope(isolate);
5565 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5566 LocalContext context;
5568 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5569 CompileRun("var obj2 = {};");
5571 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5574 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5575 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5578 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5580 ExpectString("obj1.x", "x");
5581 ExpectString("obj2.x", "x");
5583 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5584 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5586 CHECK(!GetGlobalProperty(&context, "obj1")->
5587 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5588 CHECK(!GetGlobalProperty(&context, "obj2")->
5589 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5592 v8::TryCatch try_catch;
5593 CompileRun("Object.defineProperty(obj1, 'x',"
5594 "{get: function() { return 'func'; }})");
5595 CHECK(try_catch.HasCaught());
5596 String::Utf8Value exception_value(try_catch.Exception());
5597 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5600 v8::TryCatch try_catch;
5601 CompileRun("Object.defineProperty(obj2, 'x',"
5602 "{get: function() { return 'func'; }})");
5603 CHECK(try_catch.HasCaught());
5604 String::Utf8Value exception_value(try_catch.Exception());
5605 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5610 static void Get239Value(Local<String> name,
5611 const v8::PropertyCallbackInfo<v8::Value>& info) {
5612 ApiTestFuzzer::Fuzz();
5613 CHECK_EQ(info.Data(), v8_str("donut"));
5614 CHECK_EQ(name, v8_str("239"));
5615 info.GetReturnValue().Set(name);
5619 THREADED_TEST(ElementAPIAccessor) {
5620 v8::Isolate* isolate = CcTest::isolate();
5621 v8::HandleScope scope(isolate);
5622 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5623 LocalContext context;
5625 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5626 CompileRun("var obj2 = {};");
5628 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5632 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5637 ExpectString("obj1[239]", "239");
5638 ExpectString("obj2[239]", "239");
5639 ExpectString("obj1['239']", "239");
5640 ExpectString("obj2['239']", "239");
5644 v8::Persistent<Value> xValue;
5647 static void SetXValue(Local<String> name,
5649 const v8::PropertyCallbackInfo<void>& info) {
5650 CHECK_EQ(value, v8_num(4));
5651 CHECK_EQ(info.Data(), v8_str("donut"));
5652 CHECK_EQ(name, v8_str("x"));
5653 CHECK(xValue.IsEmpty());
5654 xValue.Reset(info.GetIsolate(), value);
5658 THREADED_TEST(SimplePropertyWrite) {
5659 v8::Isolate* isolate = CcTest::isolate();
5660 v8::HandleScope scope(isolate);
5661 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5662 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5663 LocalContext context;
5664 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5665 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5666 for (int i = 0; i < 10; i++) {
5667 CHECK(xValue.IsEmpty());
5669 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5675 THREADED_TEST(SetterOnly) {
5676 v8::Isolate* isolate = CcTest::isolate();
5677 v8::HandleScope scope(isolate);
5678 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5679 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5680 LocalContext context;
5681 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5682 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5683 for (int i = 0; i < 10; i++) {
5684 CHECK(xValue.IsEmpty());
5686 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5692 THREADED_TEST(NoAccessors) {
5693 v8::Isolate* isolate = CcTest::isolate();
5694 v8::HandleScope scope(isolate);
5695 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5696 templ->SetAccessor(v8_str("x"),
5697 static_cast<v8::AccessorGetterCallback>(NULL),
5700 LocalContext context;
5701 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5702 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5703 for (int i = 0; i < 10; i++) {
5709 static void XPropertyGetter(Local<String> property,
5710 const v8::PropertyCallbackInfo<v8::Value>& info) {
5711 ApiTestFuzzer::Fuzz();
5712 CHECK(info.Data()->IsUndefined());
5713 info.GetReturnValue().Set(property);
5717 THREADED_TEST(NamedInterceptorPropertyRead) {
5718 v8::Isolate* isolate = CcTest::isolate();
5719 v8::HandleScope scope(isolate);
5720 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5721 templ->SetNamedPropertyHandler(XPropertyGetter);
5722 LocalContext context;
5723 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5724 Local<Script> script = Script::Compile(v8_str("obj.x"));
5725 for (int i = 0; i < 10; i++) {
5726 Local<Value> result = script->Run();
5727 CHECK_EQ(result, v8_str("x"));
5732 THREADED_TEST(NamedInterceptorDictionaryIC) {
5733 v8::Isolate* isolate = CcTest::isolate();
5734 v8::HandleScope scope(isolate);
5735 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5736 templ->SetNamedPropertyHandler(XPropertyGetter);
5737 LocalContext context;
5738 // Create an object with a named interceptor.
5739 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5740 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5741 for (int i = 0; i < 10; i++) {
5742 Local<Value> result = script->Run();
5743 CHECK_EQ(result, v8_str("x"));
5745 // Create a slow case object and a function accessing a property in
5746 // that slow case object (with dictionary probing in generated
5747 // code). Then force object with a named interceptor into slow-case,
5748 // pass it to the function, and check that the interceptor is called
5749 // instead of accessing the local property.
5750 Local<Value> result =
5751 CompileRun("function get_x(o) { return o.x; };"
5752 "var obj = { x : 42, y : 0 };"
5754 "for (var i = 0; i < 10; i++) get_x(obj);"
5755 "interceptor_obj.x = 42;"
5756 "interceptor_obj.y = 10;"
5757 "delete interceptor_obj.y;"
5758 "get_x(interceptor_obj)");
5759 CHECK_EQ(result, v8_str("x"));
5763 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5764 v8::Isolate* isolate = CcTest::isolate();
5765 v8::HandleScope scope(isolate);
5766 v8::Local<Context> context1 = Context::New(isolate);
5769 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5770 templ->SetNamedPropertyHandler(XPropertyGetter);
5771 // Create an object with a named interceptor.
5772 v8::Local<v8::Object> object = templ->NewInstance();
5773 context1->Global()->Set(v8_str("interceptor_obj"), object);
5775 // Force the object into the slow case.
5776 CompileRun("interceptor_obj.y = 0;"
5777 "delete interceptor_obj.y;");
5781 // Introduce the object into a different context.
5782 // Repeat named loads to exercise ICs.
5783 LocalContext context2;
5784 context2->Global()->Set(v8_str("interceptor_obj"), object);
5785 Local<Value> result =
5786 CompileRun("function get_x(o) { return o.x; }"
5787 "interceptor_obj.x = 42;"
5788 "for (var i=0; i != 10; i++) {"
5789 " get_x(interceptor_obj);"
5791 "get_x(interceptor_obj)");
5792 // Check that the interceptor was actually invoked.
5793 CHECK_EQ(result, v8_str("x"));
5796 // Return to the original context and force some object to the slow case
5797 // to cause the NormalizedMapCache to verify.
5799 CompileRun("var obj = { x : 0 }; delete obj.x;");
5804 static void SetXOnPrototypeGetter(
5805 Local<String> property,
5806 const v8::PropertyCallbackInfo<v8::Value>& info) {
5807 // Set x on the prototype object and do not handle the get request.
5808 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5809 proto.As<v8::Object>()->Set(v8_str("x"),
5810 v8::Integer::New(info.GetIsolate(), 23));
5814 // This is a regression test for http://crbug.com/20104. Map
5815 // transitions should not interfere with post interceptor lookup.
5816 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5817 v8::Isolate* isolate = CcTest::isolate();
5818 v8::HandleScope scope(isolate);
5819 Local<v8::FunctionTemplate> function_template =
5820 v8::FunctionTemplate::New(isolate);
5821 Local<v8::ObjectTemplate> instance_template
5822 = function_template->InstanceTemplate();
5823 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5824 LocalContext context;
5825 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5826 // Create an instance of F and introduce a map transition for x.
5827 CompileRun("var o = new F(); o.x = 23;");
5828 // Create an instance of F and invoke the getter. The result should be 23.
5829 Local<Value> result = CompileRun("o = new F(); o.x");
5830 CHECK_EQ(result->Int32Value(), 23);
5834 static void IndexedPropertyGetter(
5836 const v8::PropertyCallbackInfo<v8::Value>& info) {
5837 ApiTestFuzzer::Fuzz();
5839 info.GetReturnValue().Set(v8_num(625));
5844 static void IndexedPropertySetter(
5847 const v8::PropertyCallbackInfo<v8::Value>& info) {
5848 ApiTestFuzzer::Fuzz();
5850 info.GetReturnValue().Set(value);
5855 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5856 v8::Isolate* isolate = CcTest::isolate();
5857 v8::HandleScope scope(isolate);
5858 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5859 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5860 IndexedPropertySetter);
5861 LocalContext context;
5862 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5863 Local<Script> getter_script = Script::Compile(v8_str(
5864 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5865 Local<Script> setter_script = Script::Compile(v8_str(
5866 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5869 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5870 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5872 "obj.foo;")); // This setter should not run, due to the interceptor.
5873 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5875 Local<Value> result = getter_script->Run();
5876 CHECK_EQ(v8_num(5), result);
5877 result = setter_script->Run();
5878 CHECK_EQ(v8_num(23), result);
5879 result = interceptor_setter_script->Run();
5880 CHECK_EQ(v8_num(23), result);
5881 result = interceptor_getter_script->Run();
5882 CHECK_EQ(v8_num(625), result);
5886 static void UnboxedDoubleIndexedPropertyGetter(
5888 const v8::PropertyCallbackInfo<v8::Value>& info) {
5889 ApiTestFuzzer::Fuzz();
5891 info.GetReturnValue().Set(v8_num(index));
5896 static void UnboxedDoubleIndexedPropertySetter(
5899 const v8::PropertyCallbackInfo<v8::Value>& info) {
5900 ApiTestFuzzer::Fuzz();
5902 info.GetReturnValue().Set(v8_num(index));
5907 void UnboxedDoubleIndexedPropertyEnumerator(
5908 const v8::PropertyCallbackInfo<v8::Array>& info) {
5909 // Force the list of returned keys to be stored in a FastDoubleArray.
5910 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5911 "keys = new Array(); keys[125000] = 1;"
5912 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5913 "keys.length = 25; keys;"));
5914 Local<Value> result = indexed_property_names_script->Run();
5915 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5919 // Make sure that the the interceptor code in the runtime properly handles
5920 // merging property name lists for double-array-backed arrays.
5921 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5922 v8::Isolate* isolate = CcTest::isolate();
5923 v8::HandleScope scope(isolate);
5924 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5925 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5926 UnboxedDoubleIndexedPropertySetter,
5929 UnboxedDoubleIndexedPropertyEnumerator);
5930 LocalContext context;
5931 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5932 // When obj is created, force it to be Stored in a FastDoubleArray.
5933 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5934 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5936 "for (x in obj) {key_count++;};"
5938 Local<Value> result = create_unboxed_double_script->Run();
5939 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5940 Local<Script> key_count_check = Script::Compile(v8_str(
5942 result = key_count_check->Run();
5943 CHECK_EQ(v8_num(40013), result);
5947 void NonStrictArgsIndexedPropertyEnumerator(
5948 const v8::PropertyCallbackInfo<v8::Array>& info) {
5949 // Force the list of returned keys to be stored in a Arguments object.
5950 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5952 " return arguments;"
5954 "keys = f(0, 1, 2, 3);"
5956 Local<Object> result =
5957 Local<Object>::Cast(indexed_property_names_script->Run());
5958 // Have to populate the handle manually, as it's not Cast-able.
5959 i::Handle<i::JSObject> o =
5960 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5961 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5962 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5966 static void NonStrictIndexedPropertyGetter(
5968 const v8::PropertyCallbackInfo<v8::Value>& info) {
5969 ApiTestFuzzer::Fuzz();
5971 info.GetReturnValue().Set(v8_num(index));
5976 // Make sure that the the interceptor code in the runtime properly handles
5977 // merging property name lists for non-string arguments arrays.
5978 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5979 v8::Isolate* isolate = CcTest::isolate();
5980 v8::HandleScope scope(isolate);
5981 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5982 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5986 NonStrictArgsIndexedPropertyEnumerator);
5987 LocalContext context;
5988 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5989 Local<Script> create_args_script =
5990 Script::Compile(v8_str(
5991 "var key_count = 0;"
5992 "for (x in obj) {key_count++;} key_count;"));
5993 Local<Value> result = create_args_script->Run();
5994 CHECK_EQ(v8_num(4), result);
5998 static void IdentityIndexedPropertyGetter(
6000 const v8::PropertyCallbackInfo<v8::Value>& info) {
6001 info.GetReturnValue().Set(index);
6005 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6006 v8::Isolate* isolate = CcTest::isolate();
6007 v8::HandleScope scope(isolate);
6008 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6009 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6011 LocalContext context;
6012 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6014 // Check fast object case.
6015 const char* fast_case_code =
6016 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6017 ExpectString(fast_case_code, "0");
6020 const char* slow_case_code =
6021 "obj.x = 1; delete obj.x;"
6022 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6023 ExpectString(slow_case_code, "1");
6027 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6028 v8::Isolate* isolate = CcTest::isolate();
6029 v8::HandleScope scope(isolate);
6030 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6031 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6033 LocalContext context;
6034 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6039 " for (var i = 0; i < 100; i++) {"
6041 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6047 ExpectString(code, "PASSED");
6051 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6052 v8::Isolate* isolate = CcTest::isolate();
6053 v8::HandleScope scope(isolate);
6054 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6055 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6057 LocalContext context;
6058 Local<v8::Object> obj = templ->NewInstance();
6059 obj->TurnOnAccessCheck();
6060 context->Global()->Set(v8_str("obj"), obj);
6064 " for (var i = 0; i < 100; i++) {"
6066 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6072 ExpectString(code, "PASSED");
6076 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6077 i::FLAG_allow_natives_syntax = true;
6078 v8::Isolate* isolate = CcTest::isolate();
6079 v8::HandleScope scope(isolate);
6080 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6081 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6083 LocalContext context;
6084 Local<v8::Object> obj = templ->NewInstance();
6085 context->Global()->Set(v8_str("obj"), obj);
6089 " for (var i = 0; i < 100; i++) {"
6090 " var expected = i;"
6092 " %EnableAccessChecks(obj);"
6093 " expected = undefined;"
6096 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6097 " if (i == 5) %DisableAccessChecks(obj);"
6103 ExpectString(code, "PASSED");
6107 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6108 v8::Isolate* isolate = CcTest::isolate();
6109 v8::HandleScope scope(isolate);
6110 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6113 LocalContext context;
6114 Local<v8::Object> obj = templ->NewInstance();
6115 context->Global()->Set(v8_str("obj"), obj);
6119 " for (var i = 0; i < 100; i++) {"
6121 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6127 ExpectString(code, "PASSED");
6131 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6132 v8::Isolate* isolate = CcTest::isolate();
6133 v8::HandleScope scope(isolate);
6134 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6135 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6137 LocalContext context;
6138 Local<v8::Object> obj = templ->NewInstance();
6139 context->Global()->Set(v8_str("obj"), obj);
6143 " for (var i = 0; i < 100; i++) {"
6144 " var expected = i;"
6148 " expected = undefined;"
6151 " /* probe minimal Smi number on 32-bit platforms */"
6152 " key = -(1 << 30);"
6153 " expected = undefined;"
6156 " /* probe minimal Smi number on 64-bit platforms */"
6158 " expected = undefined;"
6160 " var v = obj[key];"
6161 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6167 ExpectString(code, "PASSED");
6171 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6172 v8::Isolate* isolate = CcTest::isolate();
6173 v8::HandleScope scope(isolate);
6174 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6175 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6177 LocalContext context;
6178 Local<v8::Object> obj = templ->NewInstance();
6179 context->Global()->Set(v8_str("obj"), obj);
6183 " for (var i = 0; i < 100; i++) {"
6184 " var expected = i;"
6188 " expected = undefined;"
6190 " var v = obj[key];"
6191 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6197 ExpectString(code, "PASSED");
6201 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6202 v8::Isolate* isolate = CcTest::isolate();
6203 v8::HandleScope scope(isolate);
6204 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6205 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6207 LocalContext context;
6208 Local<v8::Object> obj = templ->NewInstance();
6209 context->Global()->Set(v8_str("obj"), obj);
6212 "var original = obj;"
6214 " for (var i = 0; i < 100; i++) {"
6215 " var expected = i;"
6217 " obj = {50: 'foobar'};"
6218 " expected = 'foobar';"
6221 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6222 " if (i == 50) obj = original;"
6228 ExpectString(code, "PASSED");
6232 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6233 v8::Isolate* isolate = CcTest::isolate();
6234 v8::HandleScope scope(isolate);
6235 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6236 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6238 LocalContext context;
6239 Local<v8::Object> obj = templ->NewInstance();
6240 context->Global()->Set(v8_str("obj"), obj);
6243 "var original = obj;"
6245 " for (var i = 0; i < 100; i++) {"
6246 " var expected = i;"
6249 " expected = undefined;"
6252 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6253 " if (i == 5) obj = original;"
6259 ExpectString(code, "PASSED");
6263 THREADED_TEST(IndexedInterceptorOnProto) {
6264 v8::Isolate* isolate = CcTest::isolate();
6265 v8::HandleScope scope(isolate);
6266 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6267 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6269 LocalContext context;
6270 Local<v8::Object> obj = templ->NewInstance();
6271 context->Global()->Set(v8_str("obj"), obj);
6274 "var o = {__proto__: obj};"
6276 " for (var i = 0; i < 100; i++) {"
6278 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6284 ExpectString(code, "PASSED");
6288 THREADED_TEST(MultiContexts) {
6289 v8::Isolate* isolate = CcTest::isolate();
6290 v8::HandleScope scope(isolate);
6291 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6292 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6295 Local<String> password = v8_str("Password");
6297 // Create an environment
6298 LocalContext context0(0, templ);
6299 context0->SetSecurityToken(password);
6300 v8::Handle<v8::Object> global0 = context0->Global();
6301 global0->Set(v8_str("custom"), v8_num(1234));
6302 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6304 // Create an independent environment
6305 LocalContext context1(0, templ);
6306 context1->SetSecurityToken(password);
6307 v8::Handle<v8::Object> global1 = context1->Global();
6308 global1->Set(v8_str("custom"), v8_num(1234));
6309 CHECK_NE(global0, global1);
6310 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6311 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6313 // Now create a new context with the old global
6314 LocalContext context2(0, templ, global1);
6315 context2->SetSecurityToken(password);
6316 v8::Handle<v8::Object> global2 = context2->Global();
6317 CHECK_EQ(global1, global2);
6318 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6319 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6323 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6324 // Make sure that functions created by cloning boilerplates cannot
6325 // communicate through their __proto__ field.
6327 v8::HandleScope scope(CcTest::isolate());
6330 v8::Handle<v8::Object> global0 =
6332 v8::Handle<v8::Object> object0 =
6333 global0->Get(v8_str("Object")).As<v8::Object>();
6334 v8::Handle<v8::Object> tostring0 =
6335 object0->Get(v8_str("toString")).As<v8::Object>();
6336 v8::Handle<v8::Object> proto0 =
6337 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6338 proto0->Set(v8_str("custom"), v8_num(1234));
6341 v8::Handle<v8::Object> global1 =
6343 v8::Handle<v8::Object> object1 =
6344 global1->Get(v8_str("Object")).As<v8::Object>();
6345 v8::Handle<v8::Object> tostring1 =
6346 object1->Get(v8_str("toString")).As<v8::Object>();
6347 v8::Handle<v8::Object> proto1 =
6348 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6349 CHECK(!proto1->Has(v8_str("custom")));
6353 THREADED_TEST(Regress892105) {
6354 // Make sure that object and array literals created by cloning
6355 // boilerplates cannot communicate through their __proto__
6356 // field. This is rather difficult to check, but we try to add stuff
6357 // to Object.prototype and Array.prototype and create a new
6358 // environment. This should succeed.
6360 v8::HandleScope scope(CcTest::isolate());
6362 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6363 "Array.prototype.arr = 4567;"
6367 Local<Script> script0 = Script::Compile(source);
6368 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6371 Local<Script> script1 = Script::Compile(source);
6372 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6376 THREADED_TEST(UndetectableObject) {
6378 v8::HandleScope scope(env->GetIsolate());
6380 Local<v8::FunctionTemplate> desc =
6381 v8::FunctionTemplate::New(env->GetIsolate());
6382 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6384 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6385 env->Global()->Set(v8_str("undetectable"), obj);
6387 ExpectString("undetectable.toString()", "[object Object]");
6388 ExpectString("typeof undetectable", "undefined");
6389 ExpectString("typeof(undetectable)", "undefined");
6390 ExpectBoolean("typeof undetectable == 'undefined'", true);
6391 ExpectBoolean("typeof undetectable == 'object'", false);
6392 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6393 ExpectBoolean("!undetectable", true);
6395 ExpectObject("true&&undetectable", obj);
6396 ExpectBoolean("false&&undetectable", false);
6397 ExpectBoolean("true||undetectable", true);
6398 ExpectObject("false||undetectable", obj);
6400 ExpectObject("undetectable&&true", obj);
6401 ExpectObject("undetectable&&false", obj);
6402 ExpectBoolean("undetectable||true", true);
6403 ExpectBoolean("undetectable||false", false);
6405 ExpectBoolean("undetectable==null", true);
6406 ExpectBoolean("null==undetectable", true);
6407 ExpectBoolean("undetectable==undefined", true);
6408 ExpectBoolean("undefined==undetectable", true);
6409 ExpectBoolean("undetectable==undetectable", true);
6412 ExpectBoolean("undetectable===null", false);
6413 ExpectBoolean("null===undetectable", false);
6414 ExpectBoolean("undetectable===undefined", false);
6415 ExpectBoolean("undefined===undetectable", false);
6416 ExpectBoolean("undetectable===undetectable", true);
6420 THREADED_TEST(VoidLiteral) {
6422 v8::Isolate* isolate = env->GetIsolate();
6423 v8::HandleScope scope(isolate);
6425 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6426 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6428 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6429 env->Global()->Set(v8_str("undetectable"), obj);
6431 ExpectBoolean("undefined == void 0", true);
6432 ExpectBoolean("undetectable == void 0", true);
6433 ExpectBoolean("null == void 0", true);
6434 ExpectBoolean("undefined === void 0", true);
6435 ExpectBoolean("undetectable === void 0", false);
6436 ExpectBoolean("null === void 0", false);
6438 ExpectBoolean("void 0 == undefined", true);
6439 ExpectBoolean("void 0 == undetectable", true);
6440 ExpectBoolean("void 0 == null", true);
6441 ExpectBoolean("void 0 === undefined", true);
6442 ExpectBoolean("void 0 === undetectable", false);
6443 ExpectBoolean("void 0 === null", false);
6445 ExpectString("(function() {"
6447 " return x === void 0;"
6449 " return e.toString();"
6452 "ReferenceError: x is not defined");
6453 ExpectString("(function() {"
6455 " return void 0 === x;"
6457 " return e.toString();"
6460 "ReferenceError: x is not defined");
6464 THREADED_TEST(ExtensibleOnUndetectable) {
6466 v8::Isolate* isolate = env->GetIsolate();
6467 v8::HandleScope scope(isolate);
6469 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6470 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6472 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6473 env->Global()->Set(v8_str("undetectable"), obj);
6475 Local<String> source = v8_str("undetectable.x = 42;"
6478 Local<Script> script = Script::Compile(source);
6480 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6482 ExpectBoolean("Object.isExtensible(undetectable)", true);
6484 source = v8_str("Object.preventExtensions(undetectable);");
6485 script = Script::Compile(source);
6487 ExpectBoolean("Object.isExtensible(undetectable)", false);
6489 source = v8_str("undetectable.y = 2000;");
6490 script = Script::Compile(source);
6492 ExpectBoolean("undetectable.y == undefined", true);
6497 THREADED_TEST(UndetectableString) {
6499 v8::HandleScope scope(env->GetIsolate());
6501 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6502 String::kUndetectableString);
6503 env->Global()->Set(v8_str("undetectable"), obj);
6505 ExpectString("undetectable", "foo");
6506 ExpectString("typeof undetectable", "undefined");
6507 ExpectString("typeof(undetectable)", "undefined");
6508 ExpectBoolean("typeof undetectable == 'undefined'", true);
6509 ExpectBoolean("typeof undetectable == 'string'", false);
6510 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6511 ExpectBoolean("!undetectable", true);
6513 ExpectObject("true&&undetectable", obj);
6514 ExpectBoolean("false&&undetectable", false);
6515 ExpectBoolean("true||undetectable", true);
6516 ExpectObject("false||undetectable", obj);
6518 ExpectObject("undetectable&&true", obj);
6519 ExpectObject("undetectable&&false", obj);
6520 ExpectBoolean("undetectable||true", true);
6521 ExpectBoolean("undetectable||false", false);
6523 ExpectBoolean("undetectable==null", true);
6524 ExpectBoolean("null==undetectable", true);
6525 ExpectBoolean("undetectable==undefined", true);
6526 ExpectBoolean("undefined==undetectable", true);
6527 ExpectBoolean("undetectable==undetectable", true);
6530 ExpectBoolean("undetectable===null", false);
6531 ExpectBoolean("null===undetectable", false);
6532 ExpectBoolean("undetectable===undefined", false);
6533 ExpectBoolean("undefined===undetectable", false);
6534 ExpectBoolean("undetectable===undetectable", true);
6538 TEST(UndetectableOptimized) {
6539 i::FLAG_allow_natives_syntax = true;
6541 v8::HandleScope scope(env->GetIsolate());
6543 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6544 String::kUndetectableString);
6545 env->Global()->Set(v8_str("undetectable"), obj);
6546 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6549 "function testBranch() {"
6550 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6551 " if (%_IsUndetectableObject(detectable)) throw 2;"
6553 "function testBool() {"
6554 " var b1 = !%_IsUndetectableObject(undetectable);"
6555 " var b2 = %_IsUndetectableObject(detectable);"
6560 "%OptimizeFunctionOnNextCall(testBranch);"
6561 "%OptimizeFunctionOnNextCall(testBool);"
6562 "for (var i = 0; i < 10; i++) {"
6571 template <typename T> static void USE(T) { }
6574 // The point of this test is type checking. We run it only so compilers
6575 // don't complain about an unused function.
6576 TEST(PersistentHandles) {
6578 v8::Isolate* isolate = CcTest::isolate();
6579 v8::HandleScope scope(isolate);
6580 Local<String> str = v8_str("foo");
6581 v8::Persistent<String> p_str(isolate, str);
6583 Local<Script> scr = Script::Compile(v8_str(""));
6584 v8::Persistent<Script> p_scr(isolate, scr);
6586 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6587 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6592 static void HandleLogDelegator(
6593 const v8::FunctionCallbackInfo<v8::Value>& args) {
6594 ApiTestFuzzer::Fuzz();
6598 THREADED_TEST(GlobalObjectTemplate) {
6599 v8::Isolate* isolate = CcTest::isolate();
6600 v8::HandleScope handle_scope(isolate);
6601 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6602 global_template->Set(v8_str("JSNI_Log"),
6603 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6604 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6605 Context::Scope context_scope(context);
6606 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6610 static const char* kSimpleExtensionSource =
6616 THREADED_TEST(SimpleExtensions) {
6617 v8::HandleScope handle_scope(CcTest::isolate());
6618 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6619 const char* extension_names[] = { "simpletest" };
6620 v8::ExtensionConfiguration extensions(1, extension_names);
6621 v8::Handle<Context> context =
6622 Context::New(CcTest::isolate(), &extensions);
6623 Context::Scope lock(context);
6624 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6625 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6629 THREADED_TEST(NullExtensions) {
6630 v8::HandleScope handle_scope(CcTest::isolate());
6631 v8::RegisterExtension(new Extension("nulltest", NULL));
6632 const char* extension_names[] = { "nulltest" };
6633 v8::ExtensionConfiguration extensions(1, extension_names);
6634 v8::Handle<Context> context =
6635 Context::New(CcTest::isolate(), &extensions);
6636 Context::Scope lock(context);
6637 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6638 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6642 static const char* kEmbeddedExtensionSource =
6643 "function Ret54321(){return 54321;}~~@@$"
6644 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6645 static const int kEmbeddedExtensionSourceValidLen = 34;
6648 THREADED_TEST(ExtensionMissingSourceLength) {
6649 v8::HandleScope handle_scope(CcTest::isolate());
6650 v8::RegisterExtension(new Extension("srclentest_fail",
6651 kEmbeddedExtensionSource));
6652 const char* extension_names[] = { "srclentest_fail" };
6653 v8::ExtensionConfiguration extensions(1, extension_names);
6654 v8::Handle<Context> context =
6655 Context::New(CcTest::isolate(), &extensions);
6656 CHECK_EQ(0, *context);
6660 THREADED_TEST(ExtensionWithSourceLength) {
6661 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6662 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6663 v8::HandleScope handle_scope(CcTest::isolate());
6664 i::ScopedVector<char> extension_name(32);
6665 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6666 v8::RegisterExtension(new Extension(extension_name.start(),
6667 kEmbeddedExtensionSource, 0, 0,
6669 const char* extension_names[1] = { extension_name.start() };
6670 v8::ExtensionConfiguration extensions(1, extension_names);
6671 v8::Handle<Context> context =
6672 Context::New(CcTest::isolate(), &extensions);
6673 if (source_len == kEmbeddedExtensionSourceValidLen) {
6674 Context::Scope lock(context);
6675 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6676 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6678 // Anything but exactly the right length should fail to compile.
6679 CHECK_EQ(0, *context);
6685 static const char* kEvalExtensionSource1 =
6686 "function UseEval1() {"
6688 " return eval('x');"
6692 static const char* kEvalExtensionSource2 =
6696 " return eval('x');"
6698 " this.UseEval2 = e;"
6702 THREADED_TEST(UseEvalFromExtension) {
6703 v8::HandleScope handle_scope(CcTest::isolate());
6704 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6705 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6706 const char* extension_names[] = { "evaltest1", "evaltest2" };
6707 v8::ExtensionConfiguration extensions(2, extension_names);
6708 v8::Handle<Context> context =
6709 Context::New(CcTest::isolate(), &extensions);
6710 Context::Scope lock(context);
6711 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6712 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6713 result = Script::Compile(v8_str("UseEval2()"))->Run();
6714 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6718 static const char* kWithExtensionSource1 =
6719 "function UseWith1() {"
6721 " with({x:87}) { return x; }"
6726 static const char* kWithExtensionSource2 =
6730 " with ({x:87}) { return x; }"
6732 " this.UseWith2 = e;"
6736 THREADED_TEST(UseWithFromExtension) {
6737 v8::HandleScope handle_scope(CcTest::isolate());
6738 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6739 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6740 const char* extension_names[] = { "withtest1", "withtest2" };
6741 v8::ExtensionConfiguration extensions(2, extension_names);
6742 v8::Handle<Context> context =
6743 Context::New(CcTest::isolate(), &extensions);
6744 Context::Scope lock(context);
6745 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6746 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6747 result = Script::Compile(v8_str("UseWith2()"))->Run();
6748 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6752 THREADED_TEST(AutoExtensions) {
6753 v8::HandleScope handle_scope(CcTest::isolate());
6754 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6755 extension->set_auto_enable(true);
6756 v8::RegisterExtension(extension);
6757 v8::Handle<Context> context =
6758 Context::New(CcTest::isolate());
6759 Context::Scope lock(context);
6760 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6761 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6765 static const char* kSyntaxErrorInExtensionSource =
6769 // Test that a syntax error in an extension does not cause a fatal
6770 // error but results in an empty context.
6771 THREADED_TEST(SyntaxErrorExtensions) {
6772 v8::HandleScope handle_scope(CcTest::isolate());
6773 v8::RegisterExtension(new Extension("syntaxerror",
6774 kSyntaxErrorInExtensionSource));
6775 const char* extension_names[] = { "syntaxerror" };
6776 v8::ExtensionConfiguration extensions(1, extension_names);
6777 v8::Handle<Context> context =
6778 Context::New(CcTest::isolate(), &extensions);
6779 CHECK(context.IsEmpty());
6783 static const char* kExceptionInExtensionSource =
6787 // Test that an exception when installing an extension does not cause
6788 // a fatal error but results in an empty context.
6789 THREADED_TEST(ExceptionExtensions) {
6790 v8::HandleScope handle_scope(CcTest::isolate());
6791 v8::RegisterExtension(new Extension("exception",
6792 kExceptionInExtensionSource));
6793 const char* extension_names[] = { "exception" };
6794 v8::ExtensionConfiguration extensions(1, extension_names);
6795 v8::Handle<Context> context =
6796 Context::New(CcTest::isolate(), &extensions);
6797 CHECK(context.IsEmpty());
6801 static const char* kNativeCallInExtensionSource =
6802 "function call_runtime_last_index_of(x) {"
6803 " return %StringLastIndexOf(x, 'bob', 10);"
6807 static const char* kNativeCallTest =
6808 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6810 // Test that a native runtime calls are supported in extensions.
6811 THREADED_TEST(NativeCallInExtensions) {
6812 v8::HandleScope handle_scope(CcTest::isolate());
6813 v8::RegisterExtension(new Extension("nativecall",
6814 kNativeCallInExtensionSource));
6815 const char* extension_names[] = { "nativecall" };
6816 v8::ExtensionConfiguration extensions(1, extension_names);
6817 v8::Handle<Context> context =
6818 Context::New(CcTest::isolate(), &extensions);
6819 Context::Scope lock(context);
6820 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6821 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6825 class NativeFunctionExtension : public Extension {
6827 NativeFunctionExtension(const char* name,
6829 v8::FunctionCallback fun = &Echo)
6830 : Extension(name, source),
6833 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6834 v8::Isolate* isolate,
6835 v8::Handle<v8::String> name) {
6836 return v8::FunctionTemplate::New(isolate, function_);
6839 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6840 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6843 v8::FunctionCallback function_;
6847 THREADED_TEST(NativeFunctionDeclaration) {
6848 v8::HandleScope handle_scope(CcTest::isolate());
6849 const char* name = "nativedecl";
6850 v8::RegisterExtension(new NativeFunctionExtension(name,
6851 "native function foo();"));
6852 const char* extension_names[] = { name };
6853 v8::ExtensionConfiguration extensions(1, extension_names);
6854 v8::Handle<Context> context =
6855 Context::New(CcTest::isolate(), &extensions);
6856 Context::Scope lock(context);
6857 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6858 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6862 THREADED_TEST(NativeFunctionDeclarationError) {
6863 v8::HandleScope handle_scope(CcTest::isolate());
6864 const char* name = "nativedeclerr";
6865 // Syntax error in extension code.
6866 v8::RegisterExtension(new NativeFunctionExtension(name,
6867 "native\nfunction foo();"));
6868 const char* extension_names[] = { name };
6869 v8::ExtensionConfiguration extensions(1, extension_names);
6870 v8::Handle<Context> context =
6871 Context::New(CcTest::isolate(), &extensions);
6872 CHECK(context.IsEmpty());
6876 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6877 v8::HandleScope handle_scope(CcTest::isolate());
6878 const char* name = "nativedeclerresc";
6879 // Syntax error in extension code - escape code in "native" means that
6880 // it's not treated as a keyword.
6881 v8::RegisterExtension(new NativeFunctionExtension(
6883 "nativ\\u0065 function foo();"));
6884 const char* extension_names[] = { name };
6885 v8::ExtensionConfiguration extensions(1, extension_names);
6886 v8::Handle<Context> context =
6887 Context::New(CcTest::isolate(), &extensions);
6888 CHECK(context.IsEmpty());
6892 static void CheckDependencies(const char* name, const char* expected) {
6893 v8::HandleScope handle_scope(CcTest::isolate());
6894 v8::ExtensionConfiguration config(1, &name);
6895 LocalContext context(&config);
6896 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6897 context->Global()->Get(v8_str("loaded")));
6908 THREADED_TEST(ExtensionDependency) {
6909 static const char* kEDeps[] = { "D" };
6910 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6911 static const char* kDDeps[] = { "B", "C" };
6912 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6913 static const char* kBCDeps[] = { "A" };
6914 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6915 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6916 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6917 CheckDependencies("A", "undefinedA");
6918 CheckDependencies("B", "undefinedAB");
6919 CheckDependencies("C", "undefinedAC");
6920 CheckDependencies("D", "undefinedABCD");
6921 CheckDependencies("E", "undefinedABCDE");
6922 v8::HandleScope handle_scope(CcTest::isolate());
6923 static const char* exts[2] = { "C", "E" };
6924 v8::ExtensionConfiguration config(2, exts);
6925 LocalContext context(&config);
6926 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6930 static const char* kExtensionTestScript =
6931 "native function A();"
6932 "native function B();"
6933 "native function C();"
6935 " if (i == 0) return A();"
6936 " if (i == 1) return B();"
6937 " if (i == 2) return C();"
6941 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6942 ApiTestFuzzer::Fuzz();
6943 if (args.IsConstructCall()) {
6944 args.This()->Set(v8_str("data"), args.Data());
6945 args.GetReturnValue().SetNull();
6948 args.GetReturnValue().Set(args.Data());
6952 class FunctionExtension : public Extension {
6954 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6955 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6956 v8::Isolate* isolate,
6957 v8::Handle<String> name);
6961 static int lookup_count = 0;
6962 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6963 v8::Isolate* isolate, v8::Handle<String> name) {
6965 if (name->Equals(v8_str("A"))) {
6966 return v8::FunctionTemplate::New(
6967 isolate, CallFun, v8::Integer::New(isolate, 8));
6968 } else if (name->Equals(v8_str("B"))) {
6969 return v8::FunctionTemplate::New(
6970 isolate, CallFun, v8::Integer::New(isolate, 7));
6971 } else if (name->Equals(v8_str("C"))) {
6972 return v8::FunctionTemplate::New(
6973 isolate, CallFun, v8::Integer::New(isolate, 6));
6975 return v8::Handle<v8::FunctionTemplate>();
6980 THREADED_TEST(FunctionLookup) {
6981 v8::RegisterExtension(new FunctionExtension());
6982 v8::HandleScope handle_scope(CcTest::isolate());
6983 static const char* exts[1] = { "functiontest" };
6984 v8::ExtensionConfiguration config(1, exts);
6985 LocalContext context(&config);
6986 CHECK_EQ(3, lookup_count);
6987 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
6988 Script::Compile(v8_str("Foo(0)"))->Run());
6989 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
6990 Script::Compile(v8_str("Foo(1)"))->Run());
6991 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
6992 Script::Compile(v8_str("Foo(2)"))->Run());
6996 THREADED_TEST(NativeFunctionConstructCall) {
6997 v8::RegisterExtension(new FunctionExtension());
6998 v8::HandleScope handle_scope(CcTest::isolate());
6999 static const char* exts[1] = { "functiontest" };
7000 v8::ExtensionConfiguration config(1, exts);
7001 LocalContext context(&config);
7002 for (int i = 0; i < 10; i++) {
7003 // Run a few times to ensure that allocation of objects doesn't
7004 // change behavior of a constructor function.
7005 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7006 Script::Compile(v8_str("(new A()).data"))->Run());
7007 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7008 Script::Compile(v8_str("(new B()).data"))->Run());
7009 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7010 Script::Compile(v8_str("(new C()).data"))->Run());
7015 static const char* last_location;
7016 static const char* last_message;
7017 void StoringErrorCallback(const char* location, const char* message) {
7018 if (last_location == NULL) {
7019 last_location = location;
7020 last_message = message;
7025 // ErrorReporting creates a circular extensions configuration and
7026 // tests that the fatal error handler gets called. This renders V8
7027 // unusable and therefore this test cannot be run in parallel.
7028 TEST(ErrorReporting) {
7029 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7030 static const char* aDeps[] = { "B" };
7031 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7032 static const char* bDeps[] = { "A" };
7033 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7034 last_location = NULL;
7035 v8::ExtensionConfiguration config(1, bDeps);
7036 v8::Handle<Context> context =
7037 Context::New(CcTest::isolate(), &config);
7038 CHECK(context.IsEmpty());
7039 CHECK_NE(last_location, NULL);
7043 static const char* js_code_causing_huge_string_flattening =
7045 "for (var i = 0; i < 30; i++) {"
7051 TEST(RegexpOutOfMemory) {
7052 // Execute a script that causes out of memory when flattening a string.
7053 v8::HandleScope scope(CcTest::isolate());
7054 v8::V8::SetFatalErrorHandler(OOMCallback);
7055 LocalContext context;
7056 Local<Script> script = Script::Compile(String::NewFromUtf8(
7057 CcTest::isolate(), js_code_causing_huge_string_flattening));
7058 last_location = NULL;
7061 CHECK(false); // Should not return.
7065 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7066 v8::Handle<Value> data) {
7067 CHECK(message->GetScriptResourceName()->IsUndefined());
7068 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7069 message->GetLineNumber();
7070 message->GetSourceLine();
7074 THREADED_TEST(ErrorWithMissingScriptInfo) {
7075 LocalContext context;
7076 v8::HandleScope scope(context->GetIsolate());
7077 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7078 Script::Compile(v8_str("throw Error()"))->Run();
7079 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7083 int global_index = 0;
7085 template<typename T>
7088 explicit Snorkel(v8::Persistent<T>* handle) : handle_(handle) {
7089 index_ = global_index++;
7091 v8::Persistent<T>* handle_;
7097 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
7098 ~Whammy() { script_.Reset(); }
7099 v8::Handle<Script> getScript() {
7100 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
7101 return Local<Script>::New(isolate_, script_);
7105 static const int kObjectCount = 256;
7107 v8::Isolate* isolate_;
7108 v8::Persistent<v8::Object> objects_[kObjectCount];
7109 v8::Persistent<Script> script_;
7112 static void HandleWeakReference(
7113 const v8::WeakCallbackData<v8::Value, Snorkel<v8::Value> >& data) {
7114 data.GetParameter()->handle_->ClearWeak();
7115 delete data.GetParameter();
7118 void WhammyPropertyGetter(Local<String> name,
7119 const v8::PropertyCallbackInfo<v8::Value>& info) {
7121 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
7123 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
7125 v8::Handle<v8::Object> obj = v8::Object::New(info.GetIsolate());
7126 if (!prev.IsEmpty()) {
7127 v8::Local<v8::Object>::New(info.GetIsolate(), prev)
7128 ->Set(v8_str("next"), obj);
7129 prev.SetWeak<Value, Snorkel<Value> >(new Snorkel<Value>(&prev.As<Value>()),
7130 &HandleWeakReference);
7132 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
7133 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
7134 info.GetReturnValue().Set(whammy->getScript()->Run());
7138 THREADED_TEST(WeakReference) {
7139 i::FLAG_expose_gc = true;
7140 v8::Isolate* isolate = CcTest::isolate();
7141 v8::HandleScope handle_scope(isolate);
7142 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(isolate);
7143 Whammy* whammy = new Whammy(CcTest::isolate());
7144 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
7146 v8::External::New(CcTest::isolate(), whammy));
7147 const char* extension_list[] = { "v8/gc" };
7148 v8::ExtensionConfiguration extensions(1, extension_list);
7149 v8::Handle<Context> context =
7150 Context::New(CcTest::isolate(), &extensions);
7151 Context::Scope context_scope(context);
7153 v8::Handle<v8::Object> interceptor = templ->NewInstance();
7154 context->Global()->Set(v8_str("whammy"), interceptor);
7157 "for (var i = 0; i < 10000; i++) {"
7158 " var obj = whammy.length;"
7159 " if (last) last.next = obj;"
7164 v8::Handle<Value> result = CompileRun(code);
7165 CHECK_EQ(4.0, result->NumberValue());
7170 struct FlagAndPersistent {
7172 v8::Persistent<v8::Object> handle;
7176 static void DisposeAndSetFlag(
7177 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7178 data.GetParameter()->handle.Reset();
7179 data.GetParameter()->flag = true;
7183 THREADED_TEST(IndependentWeakHandle) {
7184 v8::Isolate* iso = CcTest::isolate();
7185 v8::HandleScope scope(iso);
7186 v8::Handle<Context> context = Context::New(iso);
7187 Context::Scope context_scope(context);
7189 FlagAndPersistent object_a, object_b;
7192 v8::HandleScope handle_scope(iso);
7193 object_a.handle.Reset(iso, v8::Object::New(iso));
7194 object_b.handle.Reset(iso, v8::Object::New(iso));
7197 object_a.flag = false;
7198 object_b.flag = false;
7199 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7200 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7201 CHECK(!object_b.handle.IsIndependent());
7202 object_a.handle.MarkIndependent();
7203 object_b.handle.MarkIndependent();
7204 CHECK(object_b.handle.IsIndependent());
7205 CcTest::heap()->PerformScavenge();
7206 CHECK(object_a.flag);
7207 CHECK(object_b.flag);
7211 static void InvokeScavenge() {
7212 CcTest::heap()->PerformScavenge();
7216 static void InvokeMarkSweep() {
7217 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7221 static void ForceScavenge(
7222 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7223 data.GetParameter()->handle.Reset();
7224 data.GetParameter()->flag = true;
7229 static void ForceMarkSweep(
7230 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7231 data.GetParameter()->handle.Reset();
7232 data.GetParameter()->flag = true;
7237 THREADED_TEST(GCFromWeakCallbacks) {
7238 v8::Isolate* isolate = CcTest::isolate();
7239 v8::HandleScope scope(isolate);
7240 v8::Handle<Context> context = Context::New(isolate);
7241 Context::Scope context_scope(context);
7243 static const int kNumberOfGCTypes = 2;
7244 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7246 Callback gc_forcing_callback[kNumberOfGCTypes] =
7247 {&ForceScavenge, &ForceMarkSweep};
7249 typedef void (*GCInvoker)();
7250 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7252 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7253 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7254 FlagAndPersistent object;
7256 v8::HandleScope handle_scope(isolate);
7257 object.handle.Reset(isolate, v8::Object::New(isolate));
7259 object.flag = false;
7260 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7261 object.handle.MarkIndependent();
7262 invoke_gc[outer_gc]();
7269 static void RevivingCallback(
7270 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7271 data.GetParameter()->handle.ClearWeak();
7272 data.GetParameter()->flag = true;
7276 THREADED_TEST(IndependentHandleRevival) {
7277 v8::Isolate* isolate = CcTest::isolate();
7278 v8::HandleScope scope(isolate);
7279 v8::Handle<Context> context = Context::New(isolate);
7280 Context::Scope context_scope(context);
7282 FlagAndPersistent object;
7284 v8::HandleScope handle_scope(isolate);
7285 v8::Local<v8::Object> o = v8::Object::New(isolate);
7286 object.handle.Reset(isolate, o);
7287 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7288 v8::Local<String> y_str = v8_str("y");
7289 o->Set(y_str, y_str);
7291 object.flag = false;
7292 object.handle.SetWeak(&object, &RevivingCallback);
7293 object.handle.MarkIndependent();
7294 CcTest::heap()->PerformScavenge();
7296 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7298 v8::HandleScope handle_scope(isolate);
7299 v8::Local<v8::Object> o =
7300 v8::Local<v8::Object>::New(isolate, object.handle);
7301 v8::Local<String> y_str = v8_str("y");
7302 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7303 CHECK(o->Get(y_str)->Equals(y_str));
7308 v8::Handle<Function> args_fun;
7311 static void ArgumentsTestCallback(
7312 const v8::FunctionCallbackInfo<v8::Value>& args) {
7313 ApiTestFuzzer::Fuzz();
7314 v8::Isolate* isolate = args.GetIsolate();
7315 CHECK_EQ(args_fun, args.Callee());
7316 CHECK_EQ(3, args.Length());
7317 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7318 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7319 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7320 CHECK_EQ(v8::Undefined(isolate), args[3]);
7321 v8::HandleScope scope(args.GetIsolate());
7322 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7326 THREADED_TEST(Arguments) {
7327 v8::Isolate* isolate = CcTest::isolate();
7328 v8::HandleScope scope(isolate);
7329 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7330 global->Set(v8_str("f"),
7331 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7332 LocalContext context(NULL, global);
7333 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7334 v8_compile("f(1, 2, 3)")->Run();
7338 static void NoBlockGetterX(Local<String> name,
7339 const v8::PropertyCallbackInfo<v8::Value>&) {
7343 static void NoBlockGetterI(uint32_t index,
7344 const v8::PropertyCallbackInfo<v8::Value>&) {
7348 static void PDeleter(Local<String> name,
7349 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7350 if (!name->Equals(v8_str("foo"))) {
7351 return; // not intercepted
7354 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7358 static void IDeleter(uint32_t index,
7359 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7361 return; // not intercepted
7364 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7368 THREADED_TEST(Deleter) {
7369 v8::Isolate* isolate = CcTest::isolate();
7370 v8::HandleScope scope(isolate);
7371 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7372 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7373 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7374 LocalContext context;
7375 context->Global()->Set(v8_str("k"), obj->NewInstance());
7381 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7382 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7384 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7385 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7387 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7388 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7390 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7391 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7395 static void GetK(Local<String> name,
7396 const v8::PropertyCallbackInfo<v8::Value>& info) {
7397 ApiTestFuzzer::Fuzz();
7398 if (name->Equals(v8_str("foo")) ||
7399 name->Equals(v8_str("bar")) ||
7400 name->Equals(v8_str("baz"))) {
7401 info.GetReturnValue().SetUndefined();
7406 static void IndexedGetK(uint32_t index,
7407 const v8::PropertyCallbackInfo<v8::Value>& info) {
7408 ApiTestFuzzer::Fuzz();
7409 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7413 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7414 ApiTestFuzzer::Fuzz();
7415 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7416 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7417 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7418 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7419 info.GetReturnValue().Set(result);
7423 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7424 ApiTestFuzzer::Fuzz();
7425 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7426 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7427 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7428 info.GetReturnValue().Set(result);
7432 THREADED_TEST(Enumerators) {
7433 v8::Isolate* isolate = CcTest::isolate();
7434 v8::HandleScope scope(isolate);
7435 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7436 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7437 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7438 LocalContext context;
7439 context->Global()->Set(v8_str("k"), obj->NewInstance());
7440 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7445 "k[4294967295] = 0;"
7447 "k[4294967296] = 0;"
7451 "k[30000000000] = 0;"
7454 "for (var prop in k) {"
7455 " result.push(prop);"
7458 // Check that we get all the property names returned including the
7459 // ones from the enumerators in the right order: indexed properties
7460 // in numerical order, indexed interceptor properties, named
7461 // properties in insertion order, named interceptor properties.
7462 // This order is not mandated by the spec, so this test is just
7463 // documenting our behavior.
7464 CHECK_EQ(17, result->Length());
7465 // Indexed properties in numerical order.
7466 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7467 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7468 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7469 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7470 // Indexed interceptor properties in the order they are returned
7471 // from the enumerator interceptor.
7472 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7473 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7474 // Named properties in insertion order.
7475 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7476 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7477 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7478 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7479 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7480 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7481 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7482 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7483 // Named interceptor properties.
7484 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7485 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7486 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7491 int p_getter_count2;
7494 static void PGetter(Local<String> name,
7495 const v8::PropertyCallbackInfo<v8::Value>& info) {
7496 ApiTestFuzzer::Fuzz();
7498 v8::Handle<v8::Object> global =
7499 info.GetIsolate()->GetCurrentContext()->Global();
7500 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7501 if (name->Equals(v8_str("p1"))) {
7502 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7503 } else if (name->Equals(v8_str("p2"))) {
7504 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7505 } else if (name->Equals(v8_str("p3"))) {
7506 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7507 } else if (name->Equals(v8_str("p4"))) {
7508 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7513 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7514 ApiTestFuzzer::Fuzz();
7515 LocalContext context;
7516 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7518 "o1.__proto__ = { };"
7519 "var o2 = { __proto__: o1 };"
7520 "var o3 = { __proto__: o2 };"
7521 "var o4 = { __proto__: o3 };"
7522 "for (var i = 0; i < 10; i++) o4.p4;"
7523 "for (var i = 0; i < 10; i++) o3.p3;"
7524 "for (var i = 0; i < 10; i++) o2.p2;"
7525 "for (var i = 0; i < 10; i++) o1.p1;");
7529 static void PGetter2(Local<String> name,
7530 const v8::PropertyCallbackInfo<v8::Value>& info) {
7531 ApiTestFuzzer::Fuzz();
7533 v8::Handle<v8::Object> global =
7534 info.GetIsolate()->GetCurrentContext()->Global();
7535 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7536 if (name->Equals(v8_str("p1"))) {
7537 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7538 } else if (name->Equals(v8_str("p2"))) {
7539 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7540 } else if (name->Equals(v8_str("p3"))) {
7541 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7542 } else if (name->Equals(v8_str("p4"))) {
7543 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7548 THREADED_TEST(GetterHolders) {
7549 v8::Isolate* isolate = CcTest::isolate();
7550 v8::HandleScope scope(isolate);
7551 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7552 obj->SetAccessor(v8_str("p1"), PGetter);
7553 obj->SetAccessor(v8_str("p2"), PGetter);
7554 obj->SetAccessor(v8_str("p3"), PGetter);
7555 obj->SetAccessor(v8_str("p4"), PGetter);
7558 CHECK_EQ(40, p_getter_count);
7562 THREADED_TEST(PreInterceptorHolders) {
7563 v8::Isolate* isolate = CcTest::isolate();
7564 v8::HandleScope scope(isolate);
7565 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7566 obj->SetNamedPropertyHandler(PGetter2);
7567 p_getter_count2 = 0;
7569 CHECK_EQ(40, p_getter_count2);
7573 THREADED_TEST(ObjectInstantiation) {
7574 v8::Isolate* isolate = CcTest::isolate();
7575 v8::HandleScope scope(isolate);
7576 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7577 templ->SetAccessor(v8_str("t"), PGetter2);
7578 LocalContext context;
7579 context->Global()->Set(v8_str("o"), templ->NewInstance());
7580 for (int i = 0; i < 100; i++) {
7581 v8::HandleScope inner_scope(CcTest::isolate());
7582 v8::Handle<v8::Object> obj = templ->NewInstance();
7583 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7584 context->Global()->Set(v8_str("o2"), obj);
7585 v8::Handle<Value> value =
7586 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7587 CHECK_EQ(v8::True(isolate), value);
7588 context->Global()->Set(v8_str("o"), obj);
7593 static int StrCmp16(uint16_t* a, uint16_t* b) {
7595 if (*a == 0 && *b == 0) return 0;
7596 if (*a != *b) return 0 + *a - *b;
7603 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7605 if (n-- == 0) return 0;
7606 if (*a == 0 && *b == 0) return 0;
7607 if (*a != *b) return 0 + *a - *b;
7614 int GetUtf8Length(Handle<String> str) {
7615 int len = str->Utf8Length();
7617 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7618 i::FlattenString(istr);
7619 len = str->Utf8Length();
7625 THREADED_TEST(StringWrite) {
7626 LocalContext context;
7627 v8::HandleScope scope(context->GetIsolate());
7628 v8::Handle<String> str = v8_str("abcde");
7629 // abc<Icelandic eth><Unicode snowman>.
7630 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7631 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7632 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7633 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7634 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7635 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7636 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7637 // single lead surrogate
7638 uint16_t lead[1] = { 0xd800 };
7639 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7640 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7641 // single trail surrogate
7642 uint16_t trail[1] = { 0xdc00 };
7643 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7644 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7646 uint16_t pair[2] = { 0xd800, 0xdc00 };
7647 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7648 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7649 const int kStride = 4; // Must match stride in for loops in JS below.
7652 "for (var i = 0; i < 0xd800; i += 4) {"
7653 " left = left + String.fromCharCode(i);"
7657 "for (var i = 0; i < 0xd800; i += 4) {"
7658 " right = String.fromCharCode(i) + right;"
7660 v8::Handle<v8::Object> global = context->Global();
7661 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7662 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7664 CHECK_EQ(5, str2->Length());
7665 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7666 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7669 char utf8buf[0xd800 * 3];
7674 memset(utf8buf, 0x1, 1000);
7675 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7677 CHECK_EQ(5, charlen);
7678 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7680 memset(utf8buf, 0x1, 1000);
7681 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7683 CHECK_EQ(5, charlen);
7684 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7686 memset(utf8buf, 0x1, 1000);
7687 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7689 CHECK_EQ(4, charlen);
7690 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7692 memset(utf8buf, 0x1, 1000);
7693 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7695 CHECK_EQ(4, charlen);
7696 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7698 memset(utf8buf, 0x1, 1000);
7699 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7701 CHECK_EQ(4, charlen);
7702 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7704 memset(utf8buf, 0x1, 1000);
7705 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7707 CHECK_EQ(3, charlen);
7708 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7710 memset(utf8buf, 0x1, 1000);
7711 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7713 CHECK_EQ(3, charlen);
7714 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7716 memset(utf8buf, 0x1, 1000);
7717 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7719 CHECK_EQ(2, charlen);
7720 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7722 // allow orphan surrogates by default
7723 memset(utf8buf, 0x1, 1000);
7724 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7726 CHECK_EQ(8, charlen);
7727 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7729 // replace orphan surrogates with unicode replacement character
7730 memset(utf8buf, 0x1, 1000);
7731 len = orphans_str->WriteUtf8(utf8buf,
7734 String::REPLACE_INVALID_UTF8);
7736 CHECK_EQ(8, charlen);
7737 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7739 // replace single lead surrogate with unicode replacement character
7740 memset(utf8buf, 0x1, 1000);
7741 len = lead_str->WriteUtf8(utf8buf,
7744 String::REPLACE_INVALID_UTF8);
7746 CHECK_EQ(1, charlen);
7747 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7749 // replace single trail surrogate with unicode replacement character
7750 memset(utf8buf, 0x1, 1000);
7751 len = trail_str->WriteUtf8(utf8buf,
7754 String::REPLACE_INVALID_UTF8);
7756 CHECK_EQ(1, charlen);
7757 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7759 // do not replace / write anything if surrogate pair does not fit the buffer
7761 memset(utf8buf, 0x1, 1000);
7762 len = pair_str->WriteUtf8(utf8buf,
7765 String::REPLACE_INVALID_UTF8);
7767 CHECK_EQ(0, charlen);
7769 memset(utf8buf, 0x1, sizeof(utf8buf));
7770 len = GetUtf8Length(left_tree);
7772 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7773 CHECK_EQ(utf8_expected, len);
7774 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7775 CHECK_EQ(utf8_expected, len);
7776 CHECK_EQ(0xd800 / kStride, charlen);
7777 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7778 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7779 CHECK_EQ(0xc0 - kStride,
7780 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7781 CHECK_EQ(1, utf8buf[utf8_expected]);
7783 memset(utf8buf, 0x1, sizeof(utf8buf));
7784 len = GetUtf8Length(right_tree);
7785 CHECK_EQ(utf8_expected, len);
7786 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7787 CHECK_EQ(utf8_expected, len);
7788 CHECK_EQ(0xd800 / kStride, charlen);
7789 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7790 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7791 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7792 CHECK_EQ(1, utf8buf[utf8_expected]);
7794 memset(buf, 0x1, sizeof(buf));
7795 memset(wbuf, 0x1, sizeof(wbuf));
7796 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7798 len = str->Write(wbuf);
7800 CHECK_EQ(0, strcmp("abcde", buf));
7801 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7802 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7804 memset(buf, 0x1, sizeof(buf));
7805 memset(wbuf, 0x1, sizeof(wbuf));
7806 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7808 len = str->Write(wbuf, 0, 4);
7810 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7811 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7812 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7814 memset(buf, 0x1, sizeof(buf));
7815 memset(wbuf, 0x1, sizeof(wbuf));
7816 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7818 len = str->Write(wbuf, 0, 5);
7820 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7821 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7822 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7824 memset(buf, 0x1, sizeof(buf));
7825 memset(wbuf, 0x1, sizeof(wbuf));
7826 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7828 len = str->Write(wbuf, 0, 6);
7830 CHECK_EQ(0, strcmp("abcde", buf));
7831 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7832 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7834 memset(buf, 0x1, sizeof(buf));
7835 memset(wbuf, 0x1, sizeof(wbuf));
7836 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7838 len = str->Write(wbuf, 4, -1);
7840 CHECK_EQ(0, strcmp("e", buf));
7841 uint16_t answer5[] = {'e', '\0'};
7842 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7844 memset(buf, 0x1, sizeof(buf));
7845 memset(wbuf, 0x1, sizeof(wbuf));
7846 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7848 len = str->Write(wbuf, 4, 6);
7850 CHECK_EQ(0, strcmp("e", buf));
7851 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7853 memset(buf, 0x1, sizeof(buf));
7854 memset(wbuf, 0x1, sizeof(wbuf));
7855 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7857 len = str->Write(wbuf, 4, 1);
7859 CHECK_EQ(0, strncmp("e\1", buf, 2));
7860 uint16_t answer6[] = {'e', 0x101};
7861 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7863 memset(buf, 0x1, sizeof(buf));
7864 memset(wbuf, 0x1, sizeof(wbuf));
7865 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7867 len = str->Write(wbuf, 3, 1);
7869 CHECK_EQ(0, strncmp("d\1", buf, 2));
7870 uint16_t answer7[] = {'d', 0x101};
7871 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7873 memset(wbuf, 0x1, sizeof(wbuf));
7875 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7877 CHECK_EQ('X', wbuf[5]);
7878 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7879 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7880 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7881 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7883 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7885 memset(buf, 0x1, sizeof(buf));
7887 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7890 String::NO_NULL_TERMINATION);
7892 CHECK_EQ('X', buf[5]);
7893 CHECK_EQ(0, strncmp("abcde", buf, 5));
7894 CHECK_NE(0, strcmp("abcde", buf));
7896 CHECK_EQ(0, strcmp("abcde", buf));
7898 memset(utf8buf, 0x1, sizeof(utf8buf));
7900 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7901 String::NO_NULL_TERMINATION);
7903 CHECK_EQ('X', utf8buf[8]);
7904 CHECK_EQ(5, charlen);
7905 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7906 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7908 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7910 memset(utf8buf, 0x1, sizeof(utf8buf));
7912 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7913 String::NO_NULL_TERMINATION);
7915 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7916 CHECK_EQ(5, charlen);
7918 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7920 memset(buf, 0x1, sizeof(buf));
7921 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7923 CHECK_EQ(0, strcmp("abc", buf));
7924 CHECK_EQ(0, buf[3]);
7925 CHECK_EQ(0, strcmp("def", buf + 4));
7927 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7928 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7929 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7933 static void Utf16Helper(
7934 LocalContext& context,
7936 const char* lengths_name,
7938 Local<v8::Array> a =
7939 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7940 Local<v8::Array> alens =
7941 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7942 for (int i = 0; i < len; i++) {
7943 Local<v8::String> string =
7944 Local<v8::String>::Cast(a->Get(i));
7945 Local<v8::Number> expected_len =
7946 Local<v8::Number>::Cast(alens->Get(i));
7947 int length = GetUtf8Length(string);
7948 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7953 static uint16_t StringGet(Handle<String> str, int index) {
7954 i::Handle<i::String> istring =
7955 v8::Utils::OpenHandle(String::Cast(*str));
7956 return istring->Get(index);
7960 static void WriteUtf8Helper(
7961 LocalContext& context,
7963 const char* lengths_name,
7965 Local<v8::Array> b =
7966 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7967 Local<v8::Array> alens =
7968 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7971 for (int i = 0; i < len; i++) {
7972 Local<v8::String> string =
7973 Local<v8::String>::Cast(b->Get(i));
7974 Local<v8::Number> expected_len =
7975 Local<v8::Number>::Cast(alens->Get(i));
7976 int utf8_length = static_cast<int>(expected_len->Value());
7977 for (int j = utf8_length + 1; j >= 0; j--) {
7978 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7979 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7982 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7984 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7985 CHECK_GE(utf8_length + 1, utf8_written);
7986 CHECK_GE(utf8_length, utf8_written2);
7987 for (int k = 0; k < utf8_written2; k++) {
7988 CHECK_EQ(buffer[k], buffer2[k]);
7990 CHECK(nchars * 3 >= utf8_written - 1);
7991 CHECK(nchars <= utf8_written);
7992 if (j == utf8_length + 1) {
7993 CHECK_EQ(utf8_written2, utf8_length);
7994 CHECK_EQ(utf8_written2 + 1, utf8_written);
7996 CHECK_EQ(buffer[utf8_written], 42);
7997 if (j > utf8_length) {
7998 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7999 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8000 Handle<String> roundtrip = v8_str(buffer);
8001 CHECK(roundtrip->Equals(string));
8003 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8005 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8007 uint16_t trail = StringGet(string, nchars - 1);
8008 uint16_t lead = StringGet(string, nchars - 2);
8009 if (((lead & 0xfc00) == 0xd800) &&
8010 ((trail & 0xfc00) == 0xdc00)) {
8011 unsigned char u1 = buffer2[utf8_written2 - 4];
8012 unsigned char u2 = buffer2[utf8_written2 - 3];
8013 unsigned char u3 = buffer2[utf8_written2 - 2];
8014 unsigned char u4 = buffer2[utf8_written2 - 1];
8015 CHECK_EQ((u1 & 0xf8), 0xf0);
8016 CHECK_EQ((u2 & 0xc0), 0x80);
8017 CHECK_EQ((u3 & 0xc0), 0x80);
8018 CHECK_EQ((u4 & 0xc0), 0x80);
8019 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8020 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8021 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8022 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8023 CHECK_EQ((u1 & 0x3), c >> 18);
8031 THREADED_TEST(Utf16) {
8032 LocalContext context;
8033 v8::HandleScope scope(context->GetIsolate());
8035 "var pad = '01234567890123456789';"
8037 "var plens = [20, 3, 3];"
8038 "p.push('01234567890123456789');"
8039 "var lead = 0xd800;"
8040 "var trail = 0xdc00;"
8041 "p.push(String.fromCharCode(0xd800));"
8042 "p.push(String.fromCharCode(0xdc00));"
8047 "for (var i = 0; i < 3; i++) {"
8048 " p[1] = String.fromCharCode(lead++);"
8049 " for (var j = 0; j < 3; j++) {"
8050 " p[2] = String.fromCharCode(trail++);"
8051 " a.push(p[i] + p[j]);"
8052 " b.push(p[i] + p[j]);"
8053 " c.push(p[i] + p[j]);"
8054 " alens.push(plens[i] + plens[j]);"
8057 "alens[5] -= 2;" // Here the surrogate pairs match up.
8062 "for (var m = 0; m < 9; m++) {"
8063 " for (var n = 0; n < 9; n++) {"
8064 " a2.push(a[m] + a[n]);"
8065 " b2.push(b[m] + b[n]);"
8066 " var newc = 'x' + c[m] + c[n] + 'y';"
8067 " c2.push(newc.substring(1, newc.length - 1));"
8068 " var utf = alens[m] + alens[n];" // And here.
8069 // The 'n's that start with 0xdc.. are 6-8
8070 // The 'm's that end with 0xd8.. are 1, 4 and 7
8071 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8072 " a2lens.push(utf);"
8075 Utf16Helper(context, "a", "alens", 9);
8076 Utf16Helper(context, "a2", "a2lens", 81);
8077 WriteUtf8Helper(context, "b", "alens", 9);
8078 WriteUtf8Helper(context, "b2", "a2lens", 81);
8079 WriteUtf8Helper(context, "c2", "a2lens", 81);
8083 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8084 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8085 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8086 return *is1 == *is2;
8089 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8091 Handle<String> symbol1 =
8092 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8093 Handle<String> symbol2 =
8094 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8095 CHECK(SameSymbol(symbol1, symbol2));
8099 THREADED_TEST(Utf16Symbol) {
8100 LocalContext context;
8101 v8::HandleScope scope(context->GetIsolate());
8103 Handle<String> symbol1 = v8::String::NewFromUtf8(
8104 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8105 Handle<String> symbol2 = v8::String::NewFromUtf8(
8106 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8107 CHECK(SameSymbol(symbol1, symbol2));
8109 SameSymbolHelper(context->GetIsolate(),
8110 "\360\220\220\205", // 4 byte encoding.
8111 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8112 SameSymbolHelper(context->GetIsolate(),
8113 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8114 "\360\220\220\206"); // 4 byte encoding.
8115 SameSymbolHelper(context->GetIsolate(),
8116 "x\360\220\220\205", // 4 byte encoding.
8117 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8118 SameSymbolHelper(context->GetIsolate(),
8119 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8120 "x\360\220\220\206"); // 4 byte encoding.
8122 "var sym0 = 'benedictus';"
8123 "var sym0b = 'S\303\270ren';"
8124 "var sym1 = '\355\240\201\355\260\207';"
8125 "var sym2 = '\360\220\220\210';"
8126 "var sym3 = 'x\355\240\201\355\260\207';"
8127 "var sym4 = 'x\360\220\220\210';"
8128 "if (sym1.length != 2) throw sym1;"
8129 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8130 "if (sym2.length != 2) throw sym2;"
8131 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8132 "if (sym3.length != 3) throw sym3;"
8133 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8134 "if (sym4.length != 3) throw sym4;"
8135 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8136 Handle<String> sym0 = v8::String::NewFromUtf8(
8137 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8138 Handle<String> sym0b = v8::String::NewFromUtf8(
8139 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8140 Handle<String> sym1 =
8141 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8142 v8::String::kInternalizedString);
8143 Handle<String> sym2 =
8144 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8145 v8::String::kInternalizedString);
8146 Handle<String> sym3 = v8::String::NewFromUtf8(
8147 context->GetIsolate(), "x\355\240\201\355\260\207",
8148 v8::String::kInternalizedString);
8149 Handle<String> sym4 =
8150 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8151 v8::String::kInternalizedString);
8152 v8::Local<v8::Object> global = context->Global();
8153 Local<Value> s0 = global->Get(v8_str("sym0"));
8154 Local<Value> s0b = global->Get(v8_str("sym0b"));
8155 Local<Value> s1 = global->Get(v8_str("sym1"));
8156 Local<Value> s2 = global->Get(v8_str("sym2"));
8157 Local<Value> s3 = global->Get(v8_str("sym3"));
8158 Local<Value> s4 = global->Get(v8_str("sym4"));
8159 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8160 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8161 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8162 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8163 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8164 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8168 THREADED_TEST(ToArrayIndex) {
8169 LocalContext context;
8170 v8::Isolate* isolate = context->GetIsolate();
8171 v8::HandleScope scope(isolate);
8173 v8::Handle<String> str = v8_str("42");
8174 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8175 CHECK(!index.IsEmpty());
8176 CHECK_EQ(42.0, index->Uint32Value());
8177 str = v8_str("42asdf");
8178 index = str->ToArrayIndex();
8179 CHECK(index.IsEmpty());
8180 str = v8_str("-42");
8181 index = str->ToArrayIndex();
8182 CHECK(index.IsEmpty());
8183 str = v8_str("4294967295");
8184 index = str->ToArrayIndex();
8185 CHECK(!index.IsEmpty());
8186 CHECK_EQ(4294967295.0, index->Uint32Value());
8187 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8188 index = num->ToArrayIndex();
8189 CHECK(!index.IsEmpty());
8190 CHECK_EQ(1.0, index->Uint32Value());
8191 num = v8::Number::New(isolate, -1);
8192 index = num->ToArrayIndex();
8193 CHECK(index.IsEmpty());
8194 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8195 index = obj->ToArrayIndex();
8196 CHECK(index.IsEmpty());
8200 THREADED_TEST(ErrorConstruction) {
8201 LocalContext context;
8202 v8::HandleScope scope(context->GetIsolate());
8204 v8::Handle<String> foo = v8_str("foo");
8205 v8::Handle<String> message = v8_str("message");
8206 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8207 CHECK(range_error->IsObject());
8208 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8209 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8210 CHECK(reference_error->IsObject());
8211 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8212 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8213 CHECK(syntax_error->IsObject());
8214 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8215 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8216 CHECK(type_error->IsObject());
8217 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8218 v8::Handle<Value> error = v8::Exception::Error(foo);
8219 CHECK(error->IsObject());
8220 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8224 static void YGetter(Local<String> name,
8225 const v8::PropertyCallbackInfo<v8::Value>& info) {
8226 ApiTestFuzzer::Fuzz();
8227 info.GetReturnValue().Set(v8_num(10));
8231 static void YSetter(Local<String> name,
8233 const v8::PropertyCallbackInfo<void>& info) {
8234 if (info.This()->Has(name)) {
8235 info.This()->Delete(name);
8237 info.This()->Set(name, value);
8241 THREADED_TEST(DeleteAccessor) {
8242 v8::Isolate* isolate = CcTest::isolate();
8243 v8::HandleScope scope(isolate);
8244 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8245 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8246 LocalContext context;
8247 v8::Handle<v8::Object> holder = obj->NewInstance();
8248 context->Global()->Set(v8_str("holder"), holder);
8249 v8::Handle<Value> result = CompileRun(
8250 "holder.y = 11; holder.y = 12; holder.y");
8251 CHECK_EQ(12, result->Uint32Value());
8255 THREADED_TEST(TypeSwitch) {
8256 v8::Isolate* isolate = CcTest::isolate();
8257 v8::HandleScope scope(isolate);
8258 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8259 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8260 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8261 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8262 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8263 LocalContext context;
8264 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8265 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8266 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8267 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8268 for (int i = 0; i < 10; i++) {
8269 CHECK_EQ(0, type_switch->match(obj0));
8270 CHECK_EQ(1, type_switch->match(obj1));
8271 CHECK_EQ(2, type_switch->match(obj2));
8272 CHECK_EQ(3, type_switch->match(obj3));
8273 CHECK_EQ(3, type_switch->match(obj3));
8274 CHECK_EQ(2, type_switch->match(obj2));
8275 CHECK_EQ(1, type_switch->match(obj1));
8276 CHECK_EQ(0, type_switch->match(obj0));
8281 // For use within the TestSecurityHandler() test.
8282 static bool g_security_callback_result = false;
8283 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8285 v8::AccessType type,
8286 Local<Value> data) {
8287 // Always allow read access.
8288 if (type == v8::ACCESS_GET)
8291 // Sometimes allow other access.
8292 return g_security_callback_result;
8296 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8298 v8::AccessType type,
8299 Local<Value> data) {
8300 // Always allow read access.
8301 if (type == v8::ACCESS_GET)
8304 // Sometimes allow other access.
8305 return g_security_callback_result;
8309 static int trouble_nesting = 0;
8310 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8311 ApiTestFuzzer::Fuzz();
8314 // Call a JS function that throws an uncaught exception.
8315 Local<v8::Object> arg_this =
8316 args.GetIsolate()->GetCurrentContext()->Global();
8317 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8318 arg_this->Get(v8_str("trouble_callee")) :
8319 arg_this->Get(v8_str("trouble_caller"));
8320 CHECK(trouble_callee->IsFunction());
8321 args.GetReturnValue().Set(
8322 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8326 static int report_count = 0;
8327 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8328 v8::Handle<Value>) {
8333 // Counts uncaught exceptions, but other tests running in parallel
8334 // also have uncaught exceptions.
8335 TEST(ApiUncaughtException) {
8338 v8::Isolate* isolate = env->GetIsolate();
8339 v8::HandleScope scope(isolate);
8340 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8342 Local<v8::FunctionTemplate> fun =
8343 v8::FunctionTemplate::New(isolate, TroubleCallback);
8344 v8::Local<v8::Object> global = env->Global();
8345 global->Set(v8_str("trouble"), fun->GetFunction());
8347 Script::Compile(v8_str("function trouble_callee() {"
8351 "function trouble_caller() {"
8354 Local<Value> trouble = global->Get(v8_str("trouble"));
8355 CHECK(trouble->IsFunction());
8356 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8357 CHECK(trouble_callee->IsFunction());
8358 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8359 CHECK(trouble_caller->IsFunction());
8360 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8361 CHECK_EQ(1, report_count);
8362 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8365 static const char* script_resource_name = "ExceptionInNativeScript.js";
8366 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8367 v8::Handle<Value>) {
8368 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8369 CHECK(!name_val.IsEmpty() && name_val->IsString());
8370 v8::String::Utf8Value name(message->GetScriptResourceName());
8371 CHECK_EQ(script_resource_name, *name);
8372 CHECK_EQ(3, message->GetLineNumber());
8373 v8::String::Utf8Value source_line(message->GetSourceLine());
8374 CHECK_EQ(" new o.foo();", *source_line);
8378 TEST(ExceptionInNativeScript) {
8380 v8::Isolate* isolate = env->GetIsolate();
8381 v8::HandleScope scope(isolate);
8382 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8384 Local<v8::FunctionTemplate> fun =
8385 v8::FunctionTemplate::New(isolate, TroubleCallback);
8386 v8::Local<v8::Object> global = env->Global();
8387 global->Set(v8_str("trouble"), fun->GetFunction());
8391 "function trouble() {\n"
8395 v8::String::NewFromUtf8(isolate, script_resource_name))->Run();
8396 Local<Value> trouble = global->Get(v8_str("trouble"));
8397 CHECK(trouble->IsFunction());
8398 Function::Cast(*trouble)->Call(global, 0, NULL);
8399 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8403 TEST(CompilationErrorUsingTryCatchHandler) {
8405 v8::HandleScope scope(env->GetIsolate());
8406 v8::TryCatch try_catch;
8407 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8408 CHECK_NE(NULL, *try_catch.Exception());
8409 CHECK(try_catch.HasCaught());
8413 TEST(TryCatchFinallyUsingTryCatchHandler) {
8415 v8::HandleScope scope(env->GetIsolate());
8416 v8::TryCatch try_catch;
8417 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8418 CHECK(!try_catch.HasCaught());
8419 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8420 CHECK(try_catch.HasCaught());
8422 Script::Compile(v8_str("(function() {"
8423 "try { throw ''; } finally { return; }"
8425 CHECK(!try_catch.HasCaught());
8426 Script::Compile(v8_str("(function()"
8427 " { try { throw ''; } finally { throw 0; }"
8429 CHECK(try_catch.HasCaught());
8433 // SecurityHandler can't be run twice
8434 TEST(SecurityHandler) {
8435 v8::Isolate* isolate = CcTest::isolate();
8436 v8::HandleScope scope0(isolate);
8437 v8::Handle<v8::ObjectTemplate> global_template =
8438 v8::ObjectTemplate::New(isolate);
8439 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8440 IndexedSecurityTestCallback);
8441 // Create an environment
8442 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8445 v8::Handle<v8::Object> global0 = context0->Global();
8446 v8::Handle<Script> script0 = v8_compile("foo = 111");
8448 global0->Set(v8_str("0"), v8_num(999));
8449 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8450 CHECK_EQ(111, foo0->Int32Value());
8451 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8452 CHECK_EQ(999, z0->Int32Value());
8454 // Create another environment, should fail security checks.
8455 v8::HandleScope scope1(isolate);
8457 v8::Handle<Context> context1 =
8458 Context::New(isolate, NULL, global_template);
8461 v8::Handle<v8::Object> global1 = context1->Global();
8462 global1->Set(v8_str("othercontext"), global0);
8463 // This set will fail the security check.
8464 v8::Handle<Script> script1 =
8465 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8467 // This read will pass the security check.
8468 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8469 CHECK_EQ(111, foo1->Int32Value());
8470 // This read will pass the security check.
8471 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8472 CHECK_EQ(999, z1->Int32Value());
8474 // Create another environment, should pass security checks.
8475 { g_security_callback_result = true; // allow security handler to pass.
8476 v8::HandleScope scope2(isolate);
8477 LocalContext context2;
8478 v8::Handle<v8::Object> global2 = context2->Global();
8479 global2->Set(v8_str("othercontext"), global0);
8480 v8::Handle<Script> script2 =
8481 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8483 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8484 CHECK_EQ(333, foo2->Int32Value());
8485 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8486 CHECK_EQ(888, z2->Int32Value());
8494 THREADED_TEST(SecurityChecks) {
8496 v8::HandleScope handle_scope(env1->GetIsolate());
8497 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8499 Local<Value> foo = v8_str("foo");
8500 Local<Value> bar = v8_str("bar");
8502 // Set to the same domain.
8503 env1->SetSecurityToken(foo);
8505 // Create a function in env1.
8506 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8507 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8508 CHECK(spy->IsFunction());
8510 // Create another function accessing global objects.
8511 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8512 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8513 CHECK(spy2->IsFunction());
8515 // Switch to env2 in the same domain and invoke spy on env2.
8517 env2->SetSecurityToken(foo);
8519 Context::Scope scope_env2(env2);
8520 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8521 CHECK(result->IsFunction());
8525 env2->SetSecurityToken(bar);
8526 Context::Scope scope_env2(env2);
8528 // Call cross_domain_call, it should throw an exception
8529 v8::TryCatch try_catch;
8530 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8531 CHECK(try_catch.HasCaught());
8536 // Regression test case for issue 1183439.
8537 THREADED_TEST(SecurityChecksForPrototypeChain) {
8538 LocalContext current;
8539 v8::HandleScope scope(current->GetIsolate());
8540 v8::Handle<Context> other = Context::New(current->GetIsolate());
8542 // Change context to be able to get to the Object function in the
8543 // other context without hitting the security checks.
8544 v8::Local<Value> other_object;
8545 { Context::Scope scope(other);
8546 other_object = other->Global()->Get(v8_str("Object"));
8547 other->Global()->Set(v8_num(42), v8_num(87));
8550 current->Global()->Set(v8_str("other"), other->Global());
8551 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8553 // Make sure the security check fails here and we get an undefined
8554 // result instead of getting the Object function. Repeat in a loop
8555 // to make sure to exercise the IC code.
8556 v8::Local<Script> access_other0 = v8_compile("other.Object");
8557 v8::Local<Script> access_other1 = v8_compile("other[42]");
8558 for (int i = 0; i < 5; i++) {
8559 CHECK(!access_other0->Run()->Equals(other_object));
8560 CHECK(access_other0->Run()->IsUndefined());
8561 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8562 CHECK(access_other1->Run()->IsUndefined());
8565 // Create an object that has 'other' in its prototype chain and make
8566 // sure we cannot access the Object function indirectly through
8567 // that. Repeat in a loop to make sure to exercise the IC code.
8568 v8_compile("function F() { };"
8569 "F.prototype = other;"
8570 "var f = new F();")->Run();
8571 v8::Local<Script> access_f0 = v8_compile("f.Object");
8572 v8::Local<Script> access_f1 = v8_compile("f[42]");
8573 for (int j = 0; j < 5; j++) {
8574 CHECK(!access_f0->Run()->Equals(other_object));
8575 CHECK(access_f0->Run()->IsUndefined());
8576 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8577 CHECK(access_f1->Run()->IsUndefined());
8580 // Now it gets hairy: Set the prototype for the other global object
8581 // to be the current global object. The prototype chain for 'f' now
8582 // goes through 'other' but ends up in the current global object.
8583 { Context::Scope scope(other);
8584 other->Global()->Set(v8_str("__proto__"), current->Global());
8586 // Set a named and an index property on the current global
8587 // object. To force the lookup to go through the other global object,
8588 // the properties must not exist in the other global object.
8589 current->Global()->Set(v8_str("foo"), v8_num(100));
8590 current->Global()->Set(v8_num(99), v8_num(101));
8591 // Try to read the properties from f and make sure that the access
8592 // gets stopped by the security checks on the other global object.
8593 Local<Script> access_f2 = v8_compile("f.foo");
8594 Local<Script> access_f3 = v8_compile("f[99]");
8595 for (int k = 0; k < 5; k++) {
8596 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8597 CHECK(access_f2->Run()->IsUndefined());
8598 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8599 CHECK(access_f3->Run()->IsUndefined());
8604 THREADED_TEST(CrossDomainDelete) {
8606 v8::HandleScope handle_scope(env1->GetIsolate());
8607 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8609 Local<Value> foo = v8_str("foo");
8610 Local<Value> bar = v8_str("bar");
8612 // Set to the same domain.
8613 env1->SetSecurityToken(foo);
8614 env2->SetSecurityToken(foo);
8616 env1->Global()->Set(v8_str("prop"), v8_num(3));
8617 env2->Global()->Set(v8_str("env1"), env1->Global());
8619 // Change env2 to a different domain and delete env1.prop.
8620 env2->SetSecurityToken(bar);
8622 Context::Scope scope_env2(env2);
8623 Local<Value> result =
8624 Script::Compile(v8_str("delete env1.prop"))->Run();
8625 CHECK(result->IsFalse());
8628 // Check that env1.prop still exists.
8629 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8630 CHECK(v->IsNumber());
8631 CHECK_EQ(3, v->Int32Value());
8635 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8637 v8::HandleScope handle_scope(env1->GetIsolate());
8638 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8640 Local<Value> foo = v8_str("foo");
8641 Local<Value> bar = v8_str("bar");
8643 // Set to the same domain.
8644 env1->SetSecurityToken(foo);
8645 env2->SetSecurityToken(foo);
8647 env1->Global()->Set(v8_str("prop"), v8_num(3));
8648 env2->Global()->Set(v8_str("env1"), env1->Global());
8650 // env1.prop is enumerable in env2.
8651 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8653 Context::Scope scope_env2(env2);
8654 Local<Value> result = Script::Compile(test)->Run();
8655 CHECK(result->IsTrue());
8658 // Change env2 to a different domain and test again.
8659 env2->SetSecurityToken(bar);
8661 Context::Scope scope_env2(env2);
8662 Local<Value> result = Script::Compile(test)->Run();
8663 CHECK(result->IsFalse());
8668 THREADED_TEST(CrossDomainForIn) {
8670 v8::HandleScope handle_scope(env1->GetIsolate());
8671 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8673 Local<Value> foo = v8_str("foo");
8674 Local<Value> bar = v8_str("bar");
8676 // Set to the same domain.
8677 env1->SetSecurityToken(foo);
8678 env2->SetSecurityToken(foo);
8680 env1->Global()->Set(v8_str("prop"), v8_num(3));
8681 env2->Global()->Set(v8_str("env1"), env1->Global());
8683 // Change env2 to a different domain and set env1's global object
8684 // as the __proto__ of an object in env2 and enumerate properties
8685 // in for-in. It shouldn't enumerate properties on env1's global
8687 env2->SetSecurityToken(bar);
8689 Context::Scope scope_env2(env2);
8690 Local<Value> result =
8691 CompileRun("(function(){var obj = {'__proto__':env1};"
8692 "for (var p in obj)"
8693 " if (p == 'prop') return false;"
8694 "return true;})()");
8695 CHECK(result->IsTrue());
8700 TEST(ContextDetachGlobal) {
8702 v8::HandleScope handle_scope(env1->GetIsolate());
8703 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8705 Local<v8::Object> global1 = env1->Global();
8707 Local<Value> foo = v8_str("foo");
8709 // Set to the same domain.
8710 env1->SetSecurityToken(foo);
8711 env2->SetSecurityToken(foo);
8716 // Create a function in env2 and add a reference to it in env1.
8717 Local<v8::Object> global2 = env2->Global();
8718 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8719 CompileRun("function getProp() {return prop;}");
8721 env1->Global()->Set(v8_str("getProp"),
8722 global2->Get(v8_str("getProp")));
8724 // Detach env2's global, and reuse the global object of env2
8726 env2->DetachGlobal();
8728 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8730 v8::Handle<v8::ObjectTemplate>(),
8732 env3->SetSecurityToken(v8_str("bar"));
8735 Local<v8::Object> global3 = env3->Global();
8736 CHECK_EQ(global2, global3);
8737 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8738 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8739 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8740 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8743 // Call getProp in env1, and it should return the value 1
8745 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8746 CHECK(get_prop->IsFunction());
8747 v8::TryCatch try_catch;
8748 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8749 CHECK(!try_catch.HasCaught());
8750 CHECK_EQ(1, r->Int32Value());
8753 // Check that env3 is not accessible from env1
8755 Local<Value> r = global3->Get(v8_str("prop2"));
8756 CHECK(r->IsUndefined());
8761 TEST(DetachGlobal) {
8763 v8::HandleScope scope(env1->GetIsolate());
8765 // Create second environment.
8766 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8768 Local<Value> foo = v8_str("foo");
8770 // Set same security token for env1 and env2.
8771 env1->SetSecurityToken(foo);
8772 env2->SetSecurityToken(foo);
8774 // Create a property on the global object in env2.
8776 v8::Context::Scope scope(env2);
8777 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8780 // Create a reference to env2 global from env1 global.
8781 env1->Global()->Set(v8_str("other"), env2->Global());
8783 // Check that we have access to other.p in env2 from env1.
8784 Local<Value> result = CompileRun("other.p");
8785 CHECK(result->IsInt32());
8786 CHECK_EQ(42, result->Int32Value());
8788 // Hold on to global from env2 and detach global from env2.
8789 Local<v8::Object> global2 = env2->Global();
8790 env2->DetachGlobal();
8792 // Check that the global has been detached. No other.p property can
8794 result = CompileRun("other.p");
8795 CHECK(result->IsUndefined());
8797 // Reuse global2 for env3.
8798 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8800 v8::Handle<v8::ObjectTemplate>(),
8802 CHECK_EQ(global2, env3->Global());
8804 // Start by using the same security token for env3 as for env1 and env2.
8805 env3->SetSecurityToken(foo);
8807 // Create a property on the global object in env3.
8809 v8::Context::Scope scope(env3);
8810 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8813 // Check that other.p is now the property in env3 and that we have access.
8814 result = CompileRun("other.p");
8815 CHECK(result->IsInt32());
8816 CHECK_EQ(24, result->Int32Value());
8818 // Change security token for env3 to something different from env1 and env2.
8819 env3->SetSecurityToken(v8_str("bar"));
8821 // Check that we do not have access to other.p in env1. |other| is now
8822 // the global object for env3 which has a different security token,
8823 // so access should be blocked.
8824 result = CompileRun("other.p");
8825 CHECK(result->IsUndefined());
8829 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8830 info.GetReturnValue().Set(
8831 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8835 TEST(DetachedAccesses) {
8837 v8::HandleScope scope(env1->GetIsolate());
8839 // Create second environment.
8840 Local<ObjectTemplate> inner_global_template =
8841 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8842 inner_global_template ->SetAccessorProperty(
8843 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8844 v8::Local<Context> env2 =
8845 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8847 Local<Value> foo = v8_str("foo");
8849 // Set same security token for env1 and env2.
8850 env1->SetSecurityToken(foo);
8851 env2->SetSecurityToken(foo);
8853 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8856 v8::Context::Scope scope(env2);
8857 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8859 "function bound_x() { return x; }"
8860 "function get_x() { return this.x; }"
8861 "function get_x_w() { return (function() {return this.x;})(); }");
8862 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8863 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8864 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8865 env1->Global()->Set(
8867 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8870 Local<Object> env2_global = env2->Global();
8871 env2_global->TurnOnAccessCheck();
8872 env2->DetachGlobal();
8874 Local<Value> result;
8875 result = CompileRun("bound_x()");
8876 CHECK_EQ(v8_str("env2_x"), result);
8877 result = CompileRun("get_x()");
8878 CHECK(result->IsUndefined());
8879 result = CompileRun("get_x_w()");
8880 CHECK(result->IsUndefined());
8881 result = CompileRun("this_x()");
8882 CHECK_EQ(v8_str("env2_x"), result);
8884 // Reattach env2's proxy
8885 env2 = Context::New(env1->GetIsolate(),
8887 v8::Handle<v8::ObjectTemplate>(),
8889 env2->SetSecurityToken(foo);
8891 v8::Context::Scope scope(env2);
8892 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8893 env2->Global()->Set(v8_str("env1"), env1->Global());
8894 result = CompileRun(
8896 "for (var i = 0; i < 4; i++ ) {"
8897 " results.push(env1.bound_x());"
8898 " results.push(env1.get_x());"
8899 " results.push(env1.get_x_w());"
8900 " results.push(env1.this_x());"
8903 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8904 CHECK_EQ(16, results->Length());
8905 for (int i = 0; i < 16; i += 4) {
8906 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8907 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8908 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8909 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8913 result = CompileRun(
8915 "for (var i = 0; i < 4; i++ ) {"
8916 " results.push(bound_x());"
8917 " results.push(get_x());"
8918 " results.push(get_x_w());"
8919 " results.push(this_x());"
8922 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8923 CHECK_EQ(16, results->Length());
8924 for (int i = 0; i < 16; i += 4) {
8925 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8926 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8927 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8928 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8931 result = CompileRun(
8933 "for (var i = 0; i < 4; i++ ) {"
8934 " results.push(this.bound_x());"
8935 " results.push(this.get_x());"
8936 " results.push(this.get_x_w());"
8937 " results.push(this.this_x());"
8940 results = Local<v8::Array>::Cast(result);
8941 CHECK_EQ(16, results->Length());
8942 for (int i = 0; i < 16; i += 4) {
8943 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8944 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8945 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8946 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8951 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8952 static bool NamedAccessBlocker(Local<v8::Object> global,
8954 v8::AccessType type,
8955 Local<Value> data) {
8956 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8957 allowed_access_type[type];
8961 static bool IndexedAccessBlocker(Local<v8::Object> global,
8963 v8::AccessType type,
8964 Local<Value> data) {
8965 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8966 allowed_access_type[type];
8970 static int g_echo_value_1 = -1;
8971 static int g_echo_value_2 = -1;
8974 static void EchoGetter(
8976 const v8::PropertyCallbackInfo<v8::Value>& info) {
8977 info.GetReturnValue().Set(v8_num(g_echo_value_1));
8981 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8982 info.GetReturnValue().Set(v8_num(g_echo_value_2));
8986 static void EchoSetter(Local<String> name,
8988 const v8::PropertyCallbackInfo<void>&) {
8989 if (value->IsNumber())
8990 g_echo_value_1 = value->Int32Value();
8994 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8995 v8::Handle<v8::Value> value = info[0];
8996 if (value->IsNumber())
8997 g_echo_value_2 = value->Int32Value();
9001 static void UnreachableGetter(
9003 const v8::PropertyCallbackInfo<v8::Value>& info) {
9004 CHECK(false); // This function should not be called..
9008 static void UnreachableSetter(Local<String>,
9010 const v8::PropertyCallbackInfo<void>&) {
9011 CHECK(false); // This function should nto be called.
9015 static void UnreachableFunction(
9016 const v8::FunctionCallbackInfo<v8::Value>& info) {
9017 CHECK(false); // This function should not be called..
9021 TEST(AccessControl) {
9022 v8::Isolate* isolate = CcTest::isolate();
9023 v8::HandleScope handle_scope(isolate);
9024 v8::Handle<v8::ObjectTemplate> global_template =
9025 v8::ObjectTemplate::New(isolate);
9027 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9028 IndexedAccessBlocker);
9030 // Add an accessor accessible by cross-domain JS code.
9031 global_template->SetAccessor(
9032 v8_str("accessible_prop"),
9033 EchoGetter, EchoSetter,
9034 v8::Handle<Value>(),
9035 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9038 global_template->SetAccessorProperty(
9039 v8_str("accessible_js_prop"),
9040 v8::FunctionTemplate::New(isolate, EchoGetter),
9041 v8::FunctionTemplate::New(isolate, EchoSetter),
9043 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9045 // Add an accessor that is not accessible by cross-domain JS code.
9046 global_template->SetAccessor(v8_str("blocked_prop"),
9047 UnreachableGetter, UnreachableSetter,
9048 v8::Handle<Value>(),
9051 global_template->SetAccessorProperty(
9052 v8_str("blocked_js_prop"),
9053 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9054 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9058 // Create an environment
9059 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9062 v8::Handle<v8::Object> global0 = context0->Global();
9064 // Define a property with JS getter and setter.
9066 "function getter() { return 'getter'; };\n"
9067 "function setter() { return 'setter'; }\n"
9068 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9070 Local<Value> getter = global0->Get(v8_str("getter"));
9071 Local<Value> setter = global0->Get(v8_str("setter"));
9073 // And define normal element.
9074 global0->Set(239, v8_str("239"));
9076 // Define an element with JS getter and setter.
9078 "function el_getter() { return 'el_getter'; };\n"
9079 "function el_setter() { return 'el_setter'; };\n"
9080 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9082 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9083 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9085 v8::HandleScope scope1(isolate);
9087 v8::Local<Context> context1 = Context::New(isolate);
9090 v8::Handle<v8::Object> global1 = context1->Global();
9091 global1->Set(v8_str("other"), global0);
9093 // Access blocked property.
9094 CompileRun("other.blocked_prop = 1");
9096 ExpectUndefined("other.blocked_prop");
9098 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9099 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9101 // Enable ACCESS_HAS
9102 allowed_access_type[v8::ACCESS_HAS] = true;
9103 ExpectUndefined("other.blocked_prop");
9104 // ... and now we can get the descriptor...
9106 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9107 // ... and enumerate the property.
9108 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9109 allowed_access_type[v8::ACCESS_HAS] = false;
9111 // Access blocked element.
9112 CompileRun("other[239] = 1");
9114 ExpectUndefined("other[239]");
9115 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9116 ExpectFalse("propertyIsEnumerable.call(other, '239')");
9118 // Enable ACCESS_HAS
9119 allowed_access_type[v8::ACCESS_HAS] = true;
9120 ExpectUndefined("other[239]");
9121 // ... and now we can get the descriptor...
9122 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9123 // ... and enumerate the property.
9124 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9125 allowed_access_type[v8::ACCESS_HAS] = false;
9127 // Access a property with JS accessor.
9128 CompileRun("other.js_accessor_p = 2");
9130 ExpectUndefined("other.js_accessor_p");
9132 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9134 // Enable ACCESS_HAS.
9135 allowed_access_type[v8::ACCESS_HAS] = true;
9136 ExpectUndefined("other.js_accessor_p");
9138 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9140 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9142 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9143 allowed_access_type[v8::ACCESS_HAS] = false;
9145 // Enable both ACCESS_HAS and ACCESS_GET.
9146 allowed_access_type[v8::ACCESS_HAS] = true;
9147 allowed_access_type[v8::ACCESS_GET] = true;
9149 ExpectString("other.js_accessor_p", "getter");
9151 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9153 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9155 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9157 allowed_access_type[v8::ACCESS_GET] = false;
9158 allowed_access_type[v8::ACCESS_HAS] = false;
9160 // Enable both ACCESS_HAS and ACCESS_SET.
9161 allowed_access_type[v8::ACCESS_HAS] = true;
9162 allowed_access_type[v8::ACCESS_SET] = true;
9164 ExpectUndefined("other.js_accessor_p");
9166 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9168 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9170 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9172 allowed_access_type[v8::ACCESS_SET] = false;
9173 allowed_access_type[v8::ACCESS_HAS] = false;
9175 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9176 allowed_access_type[v8::ACCESS_HAS] = true;
9177 allowed_access_type[v8::ACCESS_GET] = true;
9178 allowed_access_type[v8::ACCESS_SET] = true;
9180 ExpectString("other.js_accessor_p", "getter");
9182 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9184 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9186 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9188 allowed_access_type[v8::ACCESS_SET] = false;
9189 allowed_access_type[v8::ACCESS_GET] = false;
9190 allowed_access_type[v8::ACCESS_HAS] = false;
9192 // Access an element with JS accessor.
9193 CompileRun("other[42] = 2");
9195 ExpectUndefined("other[42]");
9196 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9198 // Enable ACCESS_HAS.
9199 allowed_access_type[v8::ACCESS_HAS] = true;
9200 ExpectUndefined("other[42]");
9201 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9202 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9203 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9204 allowed_access_type[v8::ACCESS_HAS] = false;
9206 // Enable both ACCESS_HAS and ACCESS_GET.
9207 allowed_access_type[v8::ACCESS_HAS] = true;
9208 allowed_access_type[v8::ACCESS_GET] = true;
9210 ExpectString("other[42]", "el_getter");
9211 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9212 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9213 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9215 allowed_access_type[v8::ACCESS_GET] = false;
9216 allowed_access_type[v8::ACCESS_HAS] = false;
9218 // Enable both ACCESS_HAS and ACCESS_SET.
9219 allowed_access_type[v8::ACCESS_HAS] = true;
9220 allowed_access_type[v8::ACCESS_SET] = true;
9222 ExpectUndefined("other[42]");
9223 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9224 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9225 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9227 allowed_access_type[v8::ACCESS_SET] = false;
9228 allowed_access_type[v8::ACCESS_HAS] = false;
9230 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9231 allowed_access_type[v8::ACCESS_HAS] = true;
9232 allowed_access_type[v8::ACCESS_GET] = true;
9233 allowed_access_type[v8::ACCESS_SET] = true;
9235 ExpectString("other[42]", "el_getter");
9236 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9237 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9238 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9240 allowed_access_type[v8::ACCESS_SET] = false;
9241 allowed_access_type[v8::ACCESS_GET] = false;
9242 allowed_access_type[v8::ACCESS_HAS] = false;
9244 v8::Handle<Value> value;
9246 // Access accessible property
9247 value = CompileRun("other.accessible_prop = 3");
9248 CHECK(value->IsNumber());
9249 CHECK_EQ(3, value->Int32Value());
9250 CHECK_EQ(3, g_echo_value_1);
9252 // Access accessible js property
9253 value = CompileRun("other.accessible_js_prop = 3");
9254 CHECK(value->IsNumber());
9255 CHECK_EQ(3, value->Int32Value());
9256 CHECK_EQ(3, g_echo_value_2);
9258 value = CompileRun("other.accessible_prop");
9259 CHECK(value->IsNumber());
9260 CHECK_EQ(3, value->Int32Value());
9262 value = CompileRun("other.accessible_js_prop");
9263 CHECK(value->IsNumber());
9264 CHECK_EQ(3, value->Int32Value());
9267 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9268 CHECK(value->IsNumber());
9269 CHECK_EQ(3, value->Int32Value());
9272 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9273 CHECK(value->IsNumber());
9274 CHECK_EQ(3, value->Int32Value());
9276 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9277 CHECK(value->IsTrue());
9279 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9280 CHECK(value->IsTrue());
9282 // Enumeration doesn't enumerate accessors from inaccessible objects in
9283 // the prototype chain even if the accessors are in themselves accessible.
9285 CompileRun("(function(){var obj = {'__proto__':other};"
9286 "for (var p in obj)"
9287 " if (p == 'accessible_prop' ||"
9288 " p == 'accessible_js_prop' ||"
9289 " p == 'blocked_js_prop' ||"
9290 " p == 'blocked_js_prop') {"
9293 "return true;})()");
9294 CHECK(value->IsTrue());
9301 TEST(AccessControlES5) {
9302 v8::Isolate* isolate = CcTest::isolate();
9303 v8::HandleScope handle_scope(isolate);
9304 v8::Handle<v8::ObjectTemplate> global_template =
9305 v8::ObjectTemplate::New(isolate);
9307 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9308 IndexedAccessBlocker);
9310 // Add accessible accessor.
9311 global_template->SetAccessor(
9312 v8_str("accessible_prop"),
9313 EchoGetter, EchoSetter,
9314 v8::Handle<Value>(),
9315 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9318 // Add an accessor that is not accessible by cross-domain JS code.
9319 global_template->SetAccessor(v8_str("blocked_prop"),
9320 UnreachableGetter, UnreachableSetter,
9321 v8::Handle<Value>(),
9324 // Create an environment
9325 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9328 v8::Handle<v8::Object> global0 = context0->Global();
9330 v8::Local<Context> context1 = Context::New(isolate);
9332 v8::Handle<v8::Object> global1 = context1->Global();
9333 global1->Set(v8_str("other"), global0);
9335 // Regression test for issue 1154.
9336 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9338 ExpectUndefined("other.blocked_prop");
9340 // Regression test for issue 1027.
9341 CompileRun("Object.defineProperty(\n"
9342 " other, 'blocked_prop', {configurable: false})");
9343 ExpectUndefined("other.blocked_prop");
9345 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9347 // Regression test for issue 1171.
9348 ExpectTrue("Object.isExtensible(other)");
9349 CompileRun("Object.preventExtensions(other)");
9350 ExpectTrue("Object.isExtensible(other)");
9352 // Object.seal and Object.freeze.
9353 CompileRun("Object.freeze(other)");
9354 ExpectTrue("Object.isExtensible(other)");
9356 CompileRun("Object.seal(other)");
9357 ExpectTrue("Object.isExtensible(other)");
9359 // Regression test for issue 1250.
9360 // Make sure that we can set the accessible accessors value using normal
9362 CompileRun("other.accessible_prop = 42");
9363 CHECK_EQ(42, g_echo_value_1);
9365 v8::Handle<Value> value;
9366 // We follow Safari in ignoring assignments to host object accessors.
9367 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9368 value = CompileRun("other.accessible_prop == 42");
9369 CHECK(value->IsTrue());
9373 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9375 v8::AccessType type,
9376 Local<Value> data) {
9381 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9383 v8::AccessType type,
9384 Local<Value> data) {
9389 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9390 v8::Isolate* isolate = CcTest::isolate();
9391 v8::HandleScope handle_scope(isolate);
9392 v8::Handle<v8::ObjectTemplate> obj_template =
9393 v8::ObjectTemplate::New(isolate);
9395 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9396 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9397 GetOwnPropertyNamesIndexedBlocker);
9399 // Create an environment
9400 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9403 v8::Handle<v8::Object> global0 = context0->Global();
9405 v8::HandleScope scope1(CcTest::isolate());
9407 v8::Local<Context> context1 = Context::New(isolate);
9410 v8::Handle<v8::Object> global1 = context1->Global();
9411 global1->Set(v8_str("other"), global0);
9412 global1->Set(v8_str("object"), obj_template->NewInstance());
9414 v8::Handle<Value> value;
9416 // Attempt to get the property names of the other global object and
9417 // of an object that requires access checks. Accessing the other
9418 // global object should be blocked by access checks on the global
9419 // proxy object. Accessing the object that requires access checks
9420 // is blocked by the access checks on the object itself.
9421 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9422 CHECK(value->IsTrue());
9424 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9425 CHECK(value->IsTrue());
9432 static void IndexedPropertyEnumerator(
9433 const v8::PropertyCallbackInfo<v8::Array>& info) {
9434 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9435 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9436 result->Set(1, v8::Object::New(info.GetIsolate()));
9437 info.GetReturnValue().Set(result);
9441 static void NamedPropertyEnumerator(
9442 const v8::PropertyCallbackInfo<v8::Array>& info) {
9443 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9444 result->Set(0, v8_str("x"));
9445 result->Set(1, v8::Object::New(info.GetIsolate()));
9446 info.GetReturnValue().Set(result);
9450 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9451 v8::Isolate* isolate = CcTest::isolate();
9452 v8::HandleScope handle_scope(isolate);
9453 v8::Handle<v8::ObjectTemplate> obj_template =
9454 v8::ObjectTemplate::New(isolate);
9456 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9457 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9458 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9459 IndexedPropertyEnumerator);
9460 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9461 NamedPropertyEnumerator);
9463 LocalContext context;
9464 v8::Handle<v8::Object> global = context->Global();
9465 global->Set(v8_str("object"), obj_template->NewInstance());
9467 v8::Handle<v8::Value> result =
9468 CompileRun("Object.getOwnPropertyNames(object)");
9469 CHECK(result->IsArray());
9470 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9471 CHECK_EQ(3, result_array->Length());
9472 CHECK(result_array->Get(0)->IsString());
9473 CHECK(result_array->Get(1)->IsString());
9474 CHECK(result_array->Get(2)->IsString());
9475 CHECK_EQ(v8_str("7"), result_array->Get(0));
9476 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9477 CHECK_EQ(v8_str("x"), result_array->Get(2));
9481 static void ConstTenGetter(Local<String> name,
9482 const v8::PropertyCallbackInfo<v8::Value>& info) {
9483 info.GetReturnValue().Set(v8_num(10));
9487 THREADED_TEST(CrossDomainAccessors) {
9488 v8::Isolate* isolate = CcTest::isolate();
9489 v8::HandleScope handle_scope(isolate);
9491 v8::Handle<v8::FunctionTemplate> func_template =
9492 v8::FunctionTemplate::New(isolate);
9494 v8::Handle<v8::ObjectTemplate> global_template =
9495 func_template->InstanceTemplate();
9497 v8::Handle<v8::ObjectTemplate> proto_template =
9498 func_template->PrototypeTemplate();
9500 // Add an accessor to proto that's accessible by cross-domain JS code.
9501 proto_template->SetAccessor(v8_str("accessible"),
9503 v8::Handle<Value>(),
9506 // Add an accessor that is not accessible by cross-domain JS code.
9507 global_template->SetAccessor(v8_str("unreachable"),
9508 UnreachableGetter, 0,
9509 v8::Handle<Value>(),
9512 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9515 Local<v8::Object> global = context0->Global();
9516 // Add a normal property that shadows 'accessible'
9517 global->Set(v8_str("accessible"), v8_num(11));
9519 // Enter a new context.
9520 v8::HandleScope scope1(CcTest::isolate());
9521 v8::Local<Context> context1 = Context::New(isolate);
9524 v8::Handle<v8::Object> global1 = context1->Global();
9525 global1->Set(v8_str("other"), global);
9527 // Should return 10, instead of 11
9528 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9529 CHECK(value->IsNumber());
9530 CHECK_EQ(10, value->Int32Value());
9532 value = v8_compile("other.unreachable")->Run();
9533 CHECK(value->IsUndefined());
9540 static int named_access_count = 0;
9541 static int indexed_access_count = 0;
9543 static bool NamedAccessCounter(Local<v8::Object> global,
9545 v8::AccessType type,
9546 Local<Value> data) {
9547 named_access_count++;
9552 static bool IndexedAccessCounter(Local<v8::Object> global,
9554 v8::AccessType type,
9555 Local<Value> data) {
9556 indexed_access_count++;
9561 // This one is too easily disturbed by other tests.
9562 TEST(AccessControlIC) {
9563 named_access_count = 0;
9564 indexed_access_count = 0;
9566 v8::Isolate* isolate = CcTest::isolate();
9567 v8::HandleScope handle_scope(isolate);
9569 // Create an environment.
9570 v8::Local<Context> context0 = Context::New(isolate);
9573 // Create an object that requires access-check functions to be
9574 // called for cross-domain access.
9575 v8::Handle<v8::ObjectTemplate> object_template =
9576 v8::ObjectTemplate::New(isolate);
9577 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9578 IndexedAccessCounter);
9579 Local<v8::Object> object = object_template->NewInstance();
9581 v8::HandleScope scope1(isolate);
9583 // Create another environment.
9584 v8::Local<Context> context1 = Context::New(isolate);
9587 // Make easy access to the object from the other environment.
9588 v8::Handle<v8::Object> global1 = context1->Global();
9589 global1->Set(v8_str("obj"), object);
9591 v8::Handle<Value> value;
9593 // Check that the named access-control function is called every time.
9594 CompileRun("function testProp(obj) {"
9595 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9596 " for (var j = 0; j < 10; j++) obj.prop;"
9599 value = CompileRun("testProp(obj)");
9600 CHECK(value->IsNumber());
9601 CHECK_EQ(1, value->Int32Value());
9602 CHECK_EQ(21, named_access_count);
9604 // Check that the named access-control function is called every time.
9605 CompileRun("var p = 'prop';"
9606 "function testKeyed(obj) {"
9607 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9608 " for (var j = 0; j < 10; j++) obj[p];"
9611 // Use obj which requires access checks. No inline caching is used
9613 value = CompileRun("testKeyed(obj)");
9614 CHECK(value->IsNumber());
9615 CHECK_EQ(1, value->Int32Value());
9616 CHECK_EQ(42, named_access_count);
9617 // Force the inline caches into generic state and try again.
9618 CompileRun("testKeyed({ a: 0 })");
9619 CompileRun("testKeyed({ b: 0 })");
9620 value = CompileRun("testKeyed(obj)");
9621 CHECK(value->IsNumber());
9622 CHECK_EQ(1, value->Int32Value());
9623 CHECK_EQ(63, named_access_count);
9625 // Check that the indexed access-control function is called every time.
9626 CompileRun("function testIndexed(obj) {"
9627 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9628 " for (var j = 0; j < 10; j++) obj[0];"
9631 value = CompileRun("testIndexed(obj)");
9632 CHECK(value->IsNumber());
9633 CHECK_EQ(1, value->Int32Value());
9634 CHECK_EQ(21, indexed_access_count);
9635 // Force the inline caches into generic state.
9636 CompileRun("testIndexed(new Array(1))");
9637 // Test that the indexed access check is called.
9638 value = CompileRun("testIndexed(obj)");
9639 CHECK(value->IsNumber());
9640 CHECK_EQ(1, value->Int32Value());
9641 CHECK_EQ(42, indexed_access_count);
9643 // Check that the named access check is called when invoking
9644 // functions on an object that requires access checks.
9645 CompileRun("obj.f = function() {}");
9646 CompileRun("function testCallNormal(obj) {"
9647 " for (var i = 0; i < 10; i++) obj.f();"
9649 CompileRun("testCallNormal(obj)");
9650 CHECK_EQ(74, named_access_count);
9652 // Force obj into slow case.
9653 value = CompileRun("delete obj.prop");
9654 CHECK(value->BooleanValue());
9655 // Force inline caches into dictionary probing mode.
9656 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9657 // Test that the named access check is called.
9658 value = CompileRun("testProp(obj);");
9659 CHECK(value->IsNumber());
9660 CHECK_EQ(1, value->Int32Value());
9661 CHECK_EQ(96, named_access_count);
9663 // Force the call inline cache into dictionary probing mode.
9664 CompileRun("o.f = function() {}; testCallNormal(o)");
9665 // Test that the named access check is still called for each
9666 // invocation of the function.
9667 value = CompileRun("testCallNormal(obj)");
9668 CHECK_EQ(106, named_access_count);
9675 static bool NamedAccessFlatten(Local<v8::Object> global,
9677 v8::AccessType type,
9678 Local<Value> data) {
9682 CHECK(name->IsString());
9684 memset(buf, 0x1, sizeof(buf));
9685 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9690 memset(buf, 0x1, sizeof(buf));
9691 len = name.As<String>()->Write(buf2);
9698 static bool IndexedAccessFlatten(Local<v8::Object> global,
9700 v8::AccessType type,
9701 Local<Value> data) {
9706 // Regression test. In access checks, operations that may cause
9707 // garbage collection are not allowed. It used to be the case that
9708 // using the Write operation on a string could cause a garbage
9709 // collection due to flattening of the string. This is no longer the
9711 THREADED_TEST(AccessControlFlatten) {
9712 named_access_count = 0;
9713 indexed_access_count = 0;
9715 v8::Isolate* isolate = CcTest::isolate();
9716 v8::HandleScope handle_scope(isolate);
9718 // Create an environment.
9719 v8::Local<Context> context0 = Context::New(isolate);
9722 // Create an object that requires access-check functions to be
9723 // called for cross-domain access.
9724 v8::Handle<v8::ObjectTemplate> object_template =
9725 v8::ObjectTemplate::New(isolate);
9726 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9727 IndexedAccessFlatten);
9728 Local<v8::Object> object = object_template->NewInstance();
9730 v8::HandleScope scope1(isolate);
9732 // Create another environment.
9733 v8::Local<Context> context1 = Context::New(isolate);
9736 // Make easy access to the object from the other environment.
9737 v8::Handle<v8::Object> global1 = context1->Global();
9738 global1->Set(v8_str("obj"), object);
9740 v8::Handle<Value> value;
9742 value = v8_compile("var p = 'as' + 'df';")->Run();
9743 value = v8_compile("obj[p];")->Run();
9750 static void AccessControlNamedGetter(
9752 const v8::PropertyCallbackInfo<v8::Value>& info) {
9753 info.GetReturnValue().Set(42);
9757 static void AccessControlNamedSetter(
9760 const v8::PropertyCallbackInfo<v8::Value>& info) {
9761 info.GetReturnValue().Set(value);
9765 static void AccessControlIndexedGetter(
9767 const v8::PropertyCallbackInfo<v8::Value>& info) {
9768 info.GetReturnValue().Set(v8_num(42));
9772 static void AccessControlIndexedSetter(
9775 const v8::PropertyCallbackInfo<v8::Value>& info) {
9776 info.GetReturnValue().Set(value);
9780 THREADED_TEST(AccessControlInterceptorIC) {
9781 named_access_count = 0;
9782 indexed_access_count = 0;
9784 v8::Isolate* isolate = CcTest::isolate();
9785 v8::HandleScope handle_scope(isolate);
9787 // Create an environment.
9788 v8::Local<Context> context0 = Context::New(isolate);
9791 // Create an object that requires access-check functions to be
9792 // called for cross-domain access. The object also has interceptors
9794 v8::Handle<v8::ObjectTemplate> object_template =
9795 v8::ObjectTemplate::New(isolate);
9796 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9797 IndexedAccessCounter);
9798 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9799 AccessControlNamedSetter);
9800 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9801 AccessControlIndexedSetter);
9802 Local<v8::Object> object = object_template->NewInstance();
9804 v8::HandleScope scope1(isolate);
9806 // Create another environment.
9807 v8::Local<Context> context1 = Context::New(isolate);
9810 // Make easy access to the object from the other environment.
9811 v8::Handle<v8::Object> global1 = context1->Global();
9812 global1->Set(v8_str("obj"), object);
9814 v8::Handle<Value> value;
9816 // Check that the named access-control function is called every time
9817 // eventhough there is an interceptor on the object.
9818 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9819 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9821 CHECK(value->IsNumber());
9822 CHECK_EQ(42, value->Int32Value());
9823 CHECK_EQ(21, named_access_count);
9825 value = v8_compile("var p = 'x';")->Run();
9826 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9827 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9829 CHECK(value->IsNumber());
9830 CHECK_EQ(42, value->Int32Value());
9831 CHECK_EQ(42, named_access_count);
9833 // Check that the indexed access-control function is called every
9834 // time eventhough there is an interceptor on the object.
9835 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9836 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9838 CHECK(value->IsNumber());
9839 CHECK_EQ(42, value->Int32Value());
9840 CHECK_EQ(21, indexed_access_count);
9847 THREADED_TEST(Version) {
9848 v8::V8::GetVersion();
9852 static void InstanceFunctionCallback(
9853 const v8::FunctionCallbackInfo<v8::Value>& args) {
9854 ApiTestFuzzer::Fuzz();
9855 args.GetReturnValue().Set(v8_num(12));
9859 THREADED_TEST(InstanceProperties) {
9860 LocalContext context;
9861 v8::Isolate* isolate = context->GetIsolate();
9862 v8::HandleScope handle_scope(isolate);
9864 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9865 Local<ObjectTemplate> instance = t->InstanceTemplate();
9867 instance->Set(v8_str("x"), v8_num(42));
9868 instance->Set(v8_str("f"),
9869 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9871 Local<Value> o = t->GetFunction()->NewInstance();
9873 context->Global()->Set(v8_str("i"), o);
9874 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9875 CHECK_EQ(42, value->Int32Value());
9877 value = Script::Compile(v8_str("i.f()"))->Run();
9878 CHECK_EQ(12, value->Int32Value());
9882 static void GlobalObjectInstancePropertiesGet(
9884 const v8::PropertyCallbackInfo<v8::Value>&) {
9885 ApiTestFuzzer::Fuzz();
9889 THREADED_TEST(GlobalObjectInstanceProperties) {
9890 v8::Isolate* isolate = CcTest::isolate();
9891 v8::HandleScope handle_scope(isolate);
9893 Local<Value> global_object;
9895 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9896 t->InstanceTemplate()->SetNamedPropertyHandler(
9897 GlobalObjectInstancePropertiesGet);
9898 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9899 instance_template->Set(v8_str("x"), v8_num(42));
9900 instance_template->Set(v8_str("f"),
9901 v8::FunctionTemplate::New(isolate,
9902 InstanceFunctionCallback));
9904 // The script to check how Crankshaft compiles missing global function
9905 // invocations. function g is not defined and should throw on call.
9906 const char* script =
9907 "function wrapper(call) {"
9908 " var x = 0, y = 1;"
9909 " for (var i = 0; i < 1000; i++) {"
9915 "for (var i = 0; i < 17; i++) wrapper(false);"
9917 "try { wrapper(true); } catch (e) { thrown = 1; };"
9921 LocalContext env(NULL, instance_template);
9922 // Hold on to the global object so it can be used again in another
9923 // environment initialization.
9924 global_object = env->Global();
9926 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9927 CHECK_EQ(42, value->Int32Value());
9928 value = Script::Compile(v8_str("f()"))->Run();
9929 CHECK_EQ(12, value->Int32Value());
9930 value = Script::Compile(v8_str(script))->Run();
9931 CHECK_EQ(1, value->Int32Value());
9935 // Create new environment reusing the global object.
9936 LocalContext env(NULL, instance_template, global_object);
9937 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9938 CHECK_EQ(42, value->Int32Value());
9939 value = Script::Compile(v8_str("f()"))->Run();
9940 CHECK_EQ(12, value->Int32Value());
9941 value = Script::Compile(v8_str(script))->Run();
9942 CHECK_EQ(1, value->Int32Value());
9947 THREADED_TEST(CallKnownGlobalReceiver) {
9948 v8::Isolate* isolate = CcTest::isolate();
9949 v8::HandleScope handle_scope(isolate);
9951 Local<Value> global_object;
9953 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9954 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9956 // The script to check that we leave global object not
9957 // global object proxy on stack when we deoptimize from inside
9958 // arguments evaluation.
9959 // To provoke error we need to both force deoptimization
9960 // from arguments evaluation and to force CallIC to take
9961 // CallIC_Miss code path that can't cope with global proxy.
9962 const char* script =
9963 "function bar(x, y) { try { } finally { } }"
9964 "function baz(x) { try { } finally { } }"
9965 "function bom(x) { try { } finally { } }"
9966 "function foo(x) { bar([x], bom(2)); }"
9967 "for (var i = 0; i < 10000; i++) foo(1);"
9972 LocalContext env(NULL, instance_template);
9973 // Hold on to the global object so it can be used again in another
9974 // environment initialization.
9975 global_object = env->Global();
9976 foo = Script::Compile(v8_str(script))->Run();
9980 // Create new environment reusing the global object.
9981 LocalContext env(NULL, instance_template, global_object);
9982 env->Global()->Set(v8_str("foo"), foo);
9983 Script::Compile(v8_str("foo()"))->Run();
9988 static void ShadowFunctionCallback(
9989 const v8::FunctionCallbackInfo<v8::Value>& args) {
9990 ApiTestFuzzer::Fuzz();
9991 args.GetReturnValue().Set(v8_num(42));
9995 static int shadow_y;
9996 static int shadow_y_setter_call_count;
9997 static int shadow_y_getter_call_count;
10000 static void ShadowYSetter(Local<String>,
10002 const v8::PropertyCallbackInfo<void>&) {
10003 shadow_y_setter_call_count++;
10008 static void ShadowYGetter(Local<String> name,
10009 const v8::PropertyCallbackInfo<v8::Value>& info) {
10010 ApiTestFuzzer::Fuzz();
10011 shadow_y_getter_call_count++;
10012 info.GetReturnValue().Set(v8_num(shadow_y));
10016 static void ShadowIndexedGet(uint32_t index,
10017 const v8::PropertyCallbackInfo<v8::Value>&) {
10021 static void ShadowNamedGet(Local<String> key,
10022 const v8::PropertyCallbackInfo<v8::Value>&) {
10026 THREADED_TEST(ShadowObject) {
10027 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10028 v8::Isolate* isolate = CcTest::isolate();
10029 v8::HandleScope handle_scope(isolate);
10031 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10032 LocalContext context(NULL, global_template);
10034 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10035 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10036 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10037 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10038 Local<ObjectTemplate> instance = t->InstanceTemplate();
10040 proto->Set(v8_str("f"),
10041 v8::FunctionTemplate::New(isolate,
10042 ShadowFunctionCallback,
10044 proto->Set(v8_str("x"), v8_num(12));
10046 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10048 Local<Value> o = t->GetFunction()->NewInstance();
10049 context->Global()->Set(v8_str("__proto__"), o);
10051 Local<Value> value =
10052 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
10053 CHECK(value->IsBoolean());
10054 CHECK(!value->BooleanValue());
10056 value = Script::Compile(v8_str("x"))->Run();
10057 CHECK_EQ(12, value->Int32Value());
10059 value = Script::Compile(v8_str("f()"))->Run();
10060 CHECK_EQ(42, value->Int32Value());
10062 Script::Compile(v8_str("y = 43"))->Run();
10063 CHECK_EQ(1, shadow_y_setter_call_count);
10064 value = Script::Compile(v8_str("y"))->Run();
10065 CHECK_EQ(1, shadow_y_getter_call_count);
10066 CHECK_EQ(42, value->Int32Value());
10070 THREADED_TEST(HiddenPrototype) {
10071 LocalContext context;
10072 v8::Isolate* isolate = context->GetIsolate();
10073 v8::HandleScope handle_scope(isolate);
10075 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10076 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10077 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10078 t1->SetHiddenPrototype(true);
10079 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10080 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10081 t2->SetHiddenPrototype(true);
10082 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10083 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10084 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10086 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10087 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10088 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10089 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10091 // Setting the prototype on an object skips hidden prototypes.
10092 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10093 o0->Set(v8_str("__proto__"), o1);
10094 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10095 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10096 o0->Set(v8_str("__proto__"), o2);
10097 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10098 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10099 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10100 o0->Set(v8_str("__proto__"), o3);
10101 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10102 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10103 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10104 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10106 // Getting the prototype of o0 should get the first visible one
10107 // which is o3. Therefore, z should not be defined on the prototype
10109 Local<Value> proto = o0->Get(v8_str("__proto__"));
10110 CHECK(proto->IsObject());
10111 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10115 THREADED_TEST(HiddenPrototypeSet) {
10116 LocalContext context;
10117 v8::Isolate* isolate = context->GetIsolate();
10118 v8::HandleScope handle_scope(isolate);
10120 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10121 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10122 ht->SetHiddenPrototype(true);
10123 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10124 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10126 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10127 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10128 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10129 o->Set(v8_str("__proto__"), h);
10130 h->Set(v8_str("__proto__"), p);
10132 // Setting a property that exists on the hidden prototype goes there.
10133 o->Set(v8_str("x"), v8_num(7));
10134 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10135 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10136 CHECK(p->Get(v8_str("x"))->IsUndefined());
10138 // Setting a new property should not be forwarded to the hidden prototype.
10139 o->Set(v8_str("y"), v8_num(6));
10140 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10141 CHECK(h->Get(v8_str("y"))->IsUndefined());
10142 CHECK(p->Get(v8_str("y"))->IsUndefined());
10144 // Setting a property that only exists on a prototype of the hidden prototype
10145 // is treated normally again.
10146 p->Set(v8_str("z"), v8_num(8));
10147 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10148 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10149 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10150 o->Set(v8_str("z"), v8_num(9));
10151 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10152 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10153 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10157 // Regression test for issue 2457.
10158 THREADED_TEST(HiddenPrototypeIdentityHash) {
10159 LocalContext context;
10160 v8::HandleScope handle_scope(context->GetIsolate());
10162 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10163 t->SetHiddenPrototype(true);
10164 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10165 Handle<Object> p = t->GetFunction()->NewInstance();
10166 Handle<Object> o = Object::New(context->GetIsolate());
10167 o->SetPrototype(p);
10169 int hash = o->GetIdentityHash();
10171 o->Set(v8_str("foo"), v8_num(42));
10172 ASSERT_EQ(hash, o->GetIdentityHash());
10176 THREADED_TEST(SetPrototype) {
10177 LocalContext context;
10178 v8::Isolate* isolate = context->GetIsolate();
10179 v8::HandleScope handle_scope(isolate);
10181 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10182 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10183 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10184 t1->SetHiddenPrototype(true);
10185 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10186 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10187 t2->SetHiddenPrototype(true);
10188 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10189 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10190 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10192 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10193 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10194 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10195 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10197 // Setting the prototype on an object does not skip hidden prototypes.
10198 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10199 CHECK(o0->SetPrototype(o1));
10200 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10201 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10202 CHECK(o1->SetPrototype(o2));
10203 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10204 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10205 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10206 CHECK(o2->SetPrototype(o3));
10207 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10208 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10209 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10210 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10212 // Getting the prototype of o0 should get the first visible one
10213 // which is o3. Therefore, z should not be defined on the prototype
10215 Local<Value> proto = o0->Get(v8_str("__proto__"));
10216 CHECK(proto->IsObject());
10217 CHECK_EQ(proto.As<v8::Object>(), o3);
10219 // However, Object::GetPrototype ignores hidden prototype.
10220 Local<Value> proto0 = o0->GetPrototype();
10221 CHECK(proto0->IsObject());
10222 CHECK_EQ(proto0.As<v8::Object>(), o1);
10224 Local<Value> proto1 = o1->GetPrototype();
10225 CHECK(proto1->IsObject());
10226 CHECK_EQ(proto1.As<v8::Object>(), o2);
10228 Local<Value> proto2 = o2->GetPrototype();
10229 CHECK(proto2->IsObject());
10230 CHECK_EQ(proto2.As<v8::Object>(), o3);
10234 // Getting property names of an object with a prototype chain that
10235 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10236 // crash the runtime.
10237 THREADED_TEST(Regress91517) {
10238 i::FLAG_allow_natives_syntax = true;
10239 LocalContext context;
10240 v8::Isolate* isolate = context->GetIsolate();
10241 v8::HandleScope handle_scope(isolate);
10243 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10244 t1->SetHiddenPrototype(true);
10245 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10246 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10247 t2->SetHiddenPrototype(true);
10248 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10249 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10250 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10251 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10252 t3->SetHiddenPrototype(true);
10253 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10254 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10255 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10257 // Force dictionary-based properties.
10258 i::ScopedVector<char> name_buf(1024);
10259 for (int i = 1; i <= 1000; i++) {
10260 i::OS::SNPrintF(name_buf, "sdf%d", i);
10261 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10264 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10265 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10266 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10267 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10269 // Create prototype chain of hidden prototypes.
10270 CHECK(o4->SetPrototype(o3));
10271 CHECK(o3->SetPrototype(o2));
10272 CHECK(o2->SetPrototype(o1));
10274 // Call the runtime version of GetLocalPropertyNames() on the natively
10275 // created object through JavaScript.
10276 context->Global()->Set(v8_str("obj"), o4);
10277 // PROPERTY_ATTRIBUTES_NONE = 0
10278 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10280 ExpectInt32("names.length", 1006);
10281 ExpectTrue("names.indexOf(\"baz\") >= 0");
10282 ExpectTrue("names.indexOf(\"boo\") >= 0");
10283 ExpectTrue("names.indexOf(\"foo\") >= 0");
10284 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10285 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10286 ExpectFalse("names[1005] == undefined");
10290 // Getting property names of an object with a hidden and inherited
10291 // prototype should not duplicate the accessor properties inherited.
10292 THREADED_TEST(Regress269562) {
10293 i::FLAG_allow_natives_syntax = true;
10294 LocalContext context;
10295 v8::HandleScope handle_scope(context->GetIsolate());
10297 Local<v8::FunctionTemplate> t1 =
10298 v8::FunctionTemplate::New(context->GetIsolate());
10299 t1->SetHiddenPrototype(true);
10301 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10302 i1->SetAccessor(v8_str("foo"),
10303 SimpleAccessorGetter, SimpleAccessorSetter);
10304 i1->SetAccessor(v8_str("bar"),
10305 SimpleAccessorGetter, SimpleAccessorSetter);
10306 i1->SetAccessor(v8_str("baz"),
10307 SimpleAccessorGetter, SimpleAccessorSetter);
10308 i1->Set(v8_str("n1"), v8_num(1));
10309 i1->Set(v8_str("n2"), v8_num(2));
10311 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10312 Local<v8::FunctionTemplate> t2 =
10313 v8::FunctionTemplate::New(context->GetIsolate());
10314 t2->SetHiddenPrototype(true);
10316 // Inherit from t1 and mark prototype as hidden.
10318 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10320 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10321 CHECK(o2->SetPrototype(o1));
10323 v8::Local<v8::Symbol> sym = v8::Symbol::New(context->GetIsolate(), "s1");
10324 o1->Set(sym, v8_num(3));
10325 o1->SetHiddenValue(v8_str("h1"),
10326 v8::Integer::New(context->GetIsolate(), 2013));
10328 // Call the runtime version of GetLocalPropertyNames() on
10329 // the natively created object through JavaScript.
10330 context->Global()->Set(v8_str("obj"), o2);
10331 context->Global()->Set(v8_str("sym"), sym);
10332 // PROPERTY_ATTRIBUTES_NONE = 0
10333 CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10335 ExpectInt32("names.length", 7);
10336 ExpectTrue("names.indexOf(\"foo\") >= 0");
10337 ExpectTrue("names.indexOf(\"bar\") >= 0");
10338 ExpectTrue("names.indexOf(\"baz\") >= 0");
10339 ExpectTrue("names.indexOf(\"n1\") >= 0");
10340 ExpectTrue("names.indexOf(\"n2\") >= 0");
10341 ExpectTrue("names.indexOf(sym) >= 0");
10342 ExpectTrue("names.indexOf(\"mine\") >= 0");
10346 THREADED_TEST(FunctionReadOnlyPrototype) {
10347 LocalContext context;
10348 v8::Isolate* isolate = context->GetIsolate();
10349 v8::HandleScope handle_scope(isolate);
10351 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10352 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10353 t1->ReadOnlyPrototype();
10354 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10355 // Configured value of ReadOnly flag.
10358 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10359 " return (descriptor['writable'] == false);"
10360 "})()")->BooleanValue());
10361 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10363 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10365 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10366 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10367 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10368 // Default value of ReadOnly flag.
10371 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10372 " return (descriptor['writable'] == true);"
10373 "})()")->BooleanValue());
10374 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10378 THREADED_TEST(SetPrototypeThrows) {
10379 LocalContext context;
10380 v8::Isolate* isolate = context->GetIsolate();
10381 v8::HandleScope handle_scope(isolate);
10383 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10385 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10386 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10388 CHECK(o0->SetPrototype(o1));
10389 // If setting the prototype leads to the cycle, SetPrototype should
10390 // return false and keep VM in sane state.
10391 v8::TryCatch try_catch;
10392 CHECK(!o1->SetPrototype(o0));
10393 CHECK(!try_catch.HasCaught());
10394 ASSERT(!CcTest::i_isolate()->has_pending_exception());
10396 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10400 THREADED_TEST(FunctionRemovePrototype) {
10401 LocalContext context;
10402 v8::Isolate* isolate = context->GetIsolate();
10403 v8::HandleScope handle_scope(isolate);
10405 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10406 t1->RemovePrototype();
10407 Local<v8::Function> fun = t1->GetFunction();
10408 context->Global()->Set(v8_str("fun"), fun);
10409 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10411 v8::TryCatch try_catch;
10412 CompileRun("new fun()");
10413 CHECK(try_catch.HasCaught());
10416 fun->NewInstance();
10417 CHECK(try_catch.HasCaught());
10421 THREADED_TEST(GetterSetterExceptions) {
10422 LocalContext context;
10423 v8::Isolate* isolate = context->GetIsolate();
10424 v8::HandleScope handle_scope(isolate);
10426 "function Foo() { };"
10427 "function Throw() { throw 5; };"
10429 "x.__defineSetter__('set', Throw);"
10430 "x.__defineGetter__('get', Throw);");
10431 Local<v8::Object> x =
10432 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10433 v8::TryCatch try_catch;
10434 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10435 x->Get(v8_str("get"));
10436 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10437 x->Get(v8_str("get"));
10438 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10439 x->Get(v8_str("get"));
10440 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10441 x->Get(v8_str("get"));
10445 THREADED_TEST(Constructor) {
10446 LocalContext context;
10447 v8::Isolate* isolate = context->GetIsolate();
10448 v8::HandleScope handle_scope(isolate);
10449 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10450 templ->SetClassName(v8_str("Fun"));
10451 Local<Function> cons = templ->GetFunction();
10452 context->Global()->Set(v8_str("Fun"), cons);
10453 Local<v8::Object> inst = cons->NewInstance();
10454 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10455 CHECK(obj->IsJSObject());
10456 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10457 CHECK(value->BooleanValue());
10461 static void ConstructorCallback(
10462 const v8::FunctionCallbackInfo<v8::Value>& args) {
10463 ApiTestFuzzer::Fuzz();
10464 Local<Object> This;
10466 if (args.IsConstructCall()) {
10467 Local<Object> Holder = args.Holder();
10468 This = Object::New(args.GetIsolate());
10469 Local<Value> proto = Holder->GetPrototype();
10470 if (proto->IsObject()) {
10471 This->SetPrototype(proto);
10474 This = args.This();
10477 This->Set(v8_str("a"), args[0]);
10478 args.GetReturnValue().Set(This);
10482 static void FakeConstructorCallback(
10483 const v8::FunctionCallbackInfo<v8::Value>& args) {
10484 ApiTestFuzzer::Fuzz();
10485 args.GetReturnValue().Set(args[0]);
10489 THREADED_TEST(ConstructorForObject) {
10490 LocalContext context;
10491 v8::Isolate* isolate = context->GetIsolate();
10492 v8::HandleScope handle_scope(isolate);
10494 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10495 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10496 Local<Object> instance = instance_template->NewInstance();
10497 context->Global()->Set(v8_str("obj"), instance);
10498 v8::TryCatch try_catch;
10499 Local<Value> value;
10500 CHECK(!try_catch.HasCaught());
10502 // Call the Object's constructor with a 32-bit signed integer.
10503 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10504 CHECK(!try_catch.HasCaught());
10505 CHECK(value->IsInt32());
10506 CHECK_EQ(28, value->Int32Value());
10508 Local<Value> args1[] = { v8_num(28) };
10509 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10510 CHECK(value_obj1->IsObject());
10511 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10512 value = object1->Get(v8_str("a"));
10513 CHECK(value->IsInt32());
10514 CHECK(!try_catch.HasCaught());
10515 CHECK_EQ(28, value->Int32Value());
10517 // Call the Object's constructor with a String.
10518 value = CompileRun(
10519 "(function() { var o = new obj('tipli'); return o.a; })()");
10520 CHECK(!try_catch.HasCaught());
10521 CHECK(value->IsString());
10522 String::Utf8Value string_value1(value->ToString());
10523 CHECK_EQ("tipli", *string_value1);
10525 Local<Value> args2[] = { v8_str("tipli") };
10526 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10527 CHECK(value_obj2->IsObject());
10528 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10529 value = object2->Get(v8_str("a"));
10530 CHECK(!try_catch.HasCaught());
10531 CHECK(value->IsString());
10532 String::Utf8Value string_value2(value->ToString());
10533 CHECK_EQ("tipli", *string_value2);
10535 // Call the Object's constructor with a Boolean.
10536 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10537 CHECK(!try_catch.HasCaught());
10538 CHECK(value->IsBoolean());
10539 CHECK_EQ(true, value->BooleanValue());
10541 Handle<Value> args3[] = { v8::True(isolate) };
10542 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10543 CHECK(value_obj3->IsObject());
10544 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10545 value = object3->Get(v8_str("a"));
10546 CHECK(!try_catch.HasCaught());
10547 CHECK(value->IsBoolean());
10548 CHECK_EQ(true, value->BooleanValue());
10550 // Call the Object's constructor with undefined.
10551 Handle<Value> args4[] = { v8::Undefined(isolate) };
10552 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10553 CHECK(value_obj4->IsObject());
10554 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10555 value = object4->Get(v8_str("a"));
10556 CHECK(!try_catch.HasCaught());
10557 CHECK(value->IsUndefined());
10559 // Call the Object's constructor with null.
10560 Handle<Value> args5[] = { v8::Null(isolate) };
10561 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10562 CHECK(value_obj5->IsObject());
10563 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10564 value = object5->Get(v8_str("a"));
10565 CHECK(!try_catch.HasCaught());
10566 CHECK(value->IsNull());
10569 // Check exception handling when there is no constructor set for the Object.
10570 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10571 Local<Object> instance = instance_template->NewInstance();
10572 context->Global()->Set(v8_str("obj2"), instance);
10573 v8::TryCatch try_catch;
10574 Local<Value> value;
10575 CHECK(!try_catch.HasCaught());
10577 value = CompileRun("new obj2(28)");
10578 CHECK(try_catch.HasCaught());
10579 String::Utf8Value exception_value1(try_catch.Exception());
10580 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10583 Local<Value> args[] = { v8_num(29) };
10584 value = instance->CallAsConstructor(1, args);
10585 CHECK(try_catch.HasCaught());
10586 String::Utf8Value exception_value2(try_catch.Exception());
10587 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10591 // Check the case when constructor throws exception.
10592 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10593 instance_template->SetCallAsFunctionHandler(ThrowValue);
10594 Local<Object> instance = instance_template->NewInstance();
10595 context->Global()->Set(v8_str("obj3"), instance);
10596 v8::TryCatch try_catch;
10597 Local<Value> value;
10598 CHECK(!try_catch.HasCaught());
10600 value = CompileRun("new obj3(22)");
10601 CHECK(try_catch.HasCaught());
10602 String::Utf8Value exception_value1(try_catch.Exception());
10603 CHECK_EQ("22", *exception_value1);
10606 Local<Value> args[] = { v8_num(23) };
10607 value = instance->CallAsConstructor(1, args);
10608 CHECK(try_catch.HasCaught());
10609 String::Utf8Value exception_value2(try_catch.Exception());
10610 CHECK_EQ("23", *exception_value2);
10614 // Check whether constructor returns with an object or non-object.
10615 { Local<FunctionTemplate> function_template =
10616 FunctionTemplate::New(isolate, FakeConstructorCallback);
10617 Local<Function> function = function_template->GetFunction();
10618 Local<Object> instance1 = function;
10619 context->Global()->Set(v8_str("obj4"), instance1);
10620 v8::TryCatch try_catch;
10621 Local<Value> value;
10622 CHECK(!try_catch.HasCaught());
10624 CHECK(instance1->IsObject());
10625 CHECK(instance1->IsFunction());
10627 value = CompileRun("new obj4(28)");
10628 CHECK(!try_catch.HasCaught());
10629 CHECK(value->IsObject());
10631 Local<Value> args1[] = { v8_num(28) };
10632 value = instance1->CallAsConstructor(1, args1);
10633 CHECK(!try_catch.HasCaught());
10634 CHECK(value->IsObject());
10636 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10637 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10638 Local<Object> instance2 = instance_template->NewInstance();
10639 context->Global()->Set(v8_str("obj5"), instance2);
10640 CHECK(!try_catch.HasCaught());
10642 CHECK(instance2->IsObject());
10643 CHECK(!instance2->IsFunction());
10645 value = CompileRun("new obj5(28)");
10646 CHECK(!try_catch.HasCaught());
10647 CHECK(!value->IsObject());
10649 Local<Value> args2[] = { v8_num(28) };
10650 value = instance2->CallAsConstructor(1, args2);
10651 CHECK(!try_catch.HasCaught());
10652 CHECK(!value->IsObject());
10657 THREADED_TEST(FunctionDescriptorException) {
10658 LocalContext context;
10659 v8::Isolate* isolate = context->GetIsolate();
10660 v8::HandleScope handle_scope(isolate);
10661 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10662 templ->SetClassName(v8_str("Fun"));
10663 Local<Function> cons = templ->GetFunction();
10664 context->Global()->Set(v8_str("Fun"), cons);
10665 Local<Value> value = CompileRun(
10666 "function test() {"
10668 " (new Fun()).blah()"
10670 " var str = String(e);"
10671 " if (str.indexOf('TypeError') == -1) return 1;"
10672 " if (str.indexOf('[object Fun]') != -1) return 2;"
10673 " if (str.indexOf('#<Fun>') == -1) return 3;"
10679 CHECK_EQ(0, value->Int32Value());
10683 THREADED_TEST(EvalAliasedDynamic) {
10684 LocalContext current;
10685 v8::HandleScope scope(current->GetIsolate());
10687 // Tests where aliased eval can only be resolved dynamically.
10688 Local<Script> script =
10689 Script::Compile(v8_str("function f(x) { "
10691 " with (x) { return eval('foo'); }"
10694 "result1 = f(new Object());"
10695 "result2 = f(this);"
10696 "var x = new Object();"
10697 "x.eval = function(x) { return 1; };"
10698 "result3 = f(x);"));
10700 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10701 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10702 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10704 v8::TryCatch try_catch;
10706 Script::Compile(v8_str("function f(x) { "
10708 " with (x) { return eval('bar'); }"
10710 "result4 = f(this)"));
10712 CHECK(!try_catch.HasCaught());
10713 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10719 THREADED_TEST(CrossEval) {
10720 v8::HandleScope scope(CcTest::isolate());
10721 LocalContext other;
10722 LocalContext current;
10724 Local<String> token = v8_str("<security token>");
10725 other->SetSecurityToken(token);
10726 current->SetSecurityToken(token);
10728 // Set up reference from current to other.
10729 current->Global()->Set(v8_str("other"), other->Global());
10731 // Check that new variables are introduced in other context.
10732 Local<Script> script =
10733 Script::Compile(v8_str("other.eval('var foo = 1234')"));
10735 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10736 CHECK_EQ(1234, foo->Int32Value());
10737 CHECK(!current->Global()->Has(v8_str("foo")));
10739 // Check that writing to non-existing properties introduces them in
10740 // the other context.
10742 Script::Compile(v8_str("other.eval('na = 1234')"));
10744 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10745 CHECK(!current->Global()->Has(v8_str("na")));
10747 // Check that global variables in current context are not visible in other
10749 v8::TryCatch try_catch;
10751 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10752 Local<Value> result = script->Run();
10753 CHECK(try_catch.HasCaught());
10756 // Check that local variables in current context are not visible in other
10759 Script::Compile(v8_str("(function() { "
10761 " return other.eval('baz');"
10763 result = script->Run();
10764 CHECK(try_catch.HasCaught());
10767 // Check that global variables in the other environment are visible
10768 // when evaluting code.
10769 other->Global()->Set(v8_str("bis"), v8_num(1234));
10770 script = Script::Compile(v8_str("other.eval('bis')"));
10771 CHECK_EQ(1234, script->Run()->Int32Value());
10772 CHECK(!try_catch.HasCaught());
10774 // Check that the 'this' pointer points to the global object evaluating
10776 other->Global()->Set(v8_str("t"), other->Global());
10777 script = Script::Compile(v8_str("other.eval('this == t')"));
10778 result = script->Run();
10779 CHECK(result->IsTrue());
10780 CHECK(!try_catch.HasCaught());
10782 // Check that variables introduced in with-statement are not visible in
10785 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10786 result = script->Run();
10787 CHECK(try_catch.HasCaught());
10790 // Check that you cannot use 'eval.call' with another object than the
10791 // current global object.
10793 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10794 result = script->Run();
10795 CHECK(try_catch.HasCaught());
10799 // Test that calling eval in a context which has been detached from
10800 // its global throws an exception. This behavior is consistent with
10801 // other JavaScript implementations.
10802 THREADED_TEST(EvalInDetachedGlobal) {
10803 v8::Isolate* isolate = CcTest::isolate();
10804 v8::HandleScope scope(isolate);
10806 v8::Local<Context> context0 = Context::New(isolate);
10807 v8::Local<Context> context1 = Context::New(isolate);
10809 // Set up function in context0 that uses eval from context0.
10811 v8::Handle<v8::Value> fun =
10812 CompileRun("var x = 42;"
10815 " return function(s) { return e(s); }"
10819 // Put the function into context1 and call it before and after
10820 // detaching the global. Before detaching, the call succeeds and
10821 // after detaching and exception is thrown.
10823 context1->Global()->Set(v8_str("fun"), fun);
10824 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10825 CHECK_EQ(42, x_value->Int32Value());
10826 context0->DetachGlobal();
10827 v8::TryCatch catcher;
10828 x_value = CompileRun("fun('x')");
10829 CHECK(x_value.IsEmpty());
10830 CHECK(catcher.HasCaught());
10835 THREADED_TEST(CrossLazyLoad) {
10836 v8::HandleScope scope(CcTest::isolate());
10837 LocalContext other;
10838 LocalContext current;
10840 Local<String> token = v8_str("<security token>");
10841 other->SetSecurityToken(token);
10842 current->SetSecurityToken(token);
10844 // Set up reference from current to other.
10845 current->Global()->Set(v8_str("other"), other->Global());
10847 // Trigger lazy loading in other context.
10848 Local<Script> script =
10849 Script::Compile(v8_str("other.eval('new Date(42)')"));
10850 Local<Value> value = script->Run();
10851 CHECK_EQ(42.0, value->NumberValue());
10855 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10856 ApiTestFuzzer::Fuzz();
10857 if (args.IsConstructCall()) {
10858 if (args[0]->IsInt32()) {
10859 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10864 args.GetReturnValue().Set(args[0]);
10868 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10869 args.GetReturnValue().Set(args.This());
10873 // Test that a call handler can be set for objects which will allow
10874 // non-function objects created through the API to be called as
10876 THREADED_TEST(CallAsFunction) {
10877 LocalContext context;
10878 v8::Isolate* isolate = context->GetIsolate();
10879 v8::HandleScope scope(isolate);
10881 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10882 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10883 instance_template->SetCallAsFunctionHandler(call_as_function);
10884 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10885 context->Global()->Set(v8_str("obj"), instance);
10886 v8::TryCatch try_catch;
10887 Local<Value> value;
10888 CHECK(!try_catch.HasCaught());
10890 value = CompileRun("obj(42)");
10891 CHECK(!try_catch.HasCaught());
10892 CHECK_EQ(42, value->Int32Value());
10894 value = CompileRun("(function(o){return o(49)})(obj)");
10895 CHECK(!try_catch.HasCaught());
10896 CHECK_EQ(49, value->Int32Value());
10898 // test special case of call as function
10899 value = CompileRun("[obj]['0'](45)");
10900 CHECK(!try_catch.HasCaught());
10901 CHECK_EQ(45, value->Int32Value());
10903 value = CompileRun("obj.call = Function.prototype.call;"
10904 "obj.call(null, 87)");
10905 CHECK(!try_catch.HasCaught());
10906 CHECK_EQ(87, value->Int32Value());
10908 // Regression tests for bug #1116356: Calling call through call/apply
10909 // must work for non-function receivers.
10910 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10911 value = CompileRun(apply_99);
10912 CHECK(!try_catch.HasCaught());
10913 CHECK_EQ(99, value->Int32Value());
10915 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10916 value = CompileRun(call_17);
10917 CHECK(!try_catch.HasCaught());
10918 CHECK_EQ(17, value->Int32Value());
10920 // Check that the call-as-function handler can be called through
10922 value = CompileRun("new obj(43)");
10923 CHECK(!try_catch.HasCaught());
10924 CHECK_EQ(-43, value->Int32Value());
10926 // Check that the call-as-function handler can be called through
10928 v8::Handle<Value> args[] = { v8_num(28) };
10929 value = instance->CallAsFunction(instance, 1, args);
10930 CHECK(!try_catch.HasCaught());
10931 CHECK_EQ(28, value->Int32Value());
10934 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10935 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10936 USE(instance_template);
10937 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10938 context->Global()->Set(v8_str("obj2"), instance);
10939 v8::TryCatch try_catch;
10940 Local<Value> value;
10941 CHECK(!try_catch.HasCaught());
10943 // Call an object without call-as-function handler through the JS
10944 value = CompileRun("obj2(28)");
10945 CHECK(value.IsEmpty());
10946 CHECK(try_catch.HasCaught());
10947 String::Utf8Value exception_value1(try_catch.Exception());
10948 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
10949 *exception_value1);
10952 // Call an object without call-as-function handler through the API
10953 value = CompileRun("obj2(28)");
10954 v8::Handle<Value> args[] = { v8_num(28) };
10955 value = instance->CallAsFunction(instance, 1, args);
10956 CHECK(value.IsEmpty());
10957 CHECK(try_catch.HasCaught());
10958 String::Utf8Value exception_value2(try_catch.Exception());
10959 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10963 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10964 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10965 instance_template->SetCallAsFunctionHandler(ThrowValue);
10966 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10967 context->Global()->Set(v8_str("obj3"), instance);
10968 v8::TryCatch try_catch;
10969 Local<Value> value;
10970 CHECK(!try_catch.HasCaught());
10972 // Catch the exception which is thrown by call-as-function handler
10973 value = CompileRun("obj3(22)");
10974 CHECK(try_catch.HasCaught());
10975 String::Utf8Value exception_value1(try_catch.Exception());
10976 CHECK_EQ("22", *exception_value1);
10979 v8::Handle<Value> args[] = { v8_num(23) };
10980 value = instance->CallAsFunction(instance, 1, args);
10981 CHECK(try_catch.HasCaught());
10982 String::Utf8Value exception_value2(try_catch.Exception());
10983 CHECK_EQ("23", *exception_value2);
10987 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10988 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10989 instance_template->SetCallAsFunctionHandler(ReturnThis);
10990 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10992 Local<v8::Value> a1 =
10993 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10994 CHECK(a1->StrictEquals(instance));
10995 Local<v8::Value> a2 =
10996 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10997 CHECK(a2->StrictEquals(instance));
10998 Local<v8::Value> a3 =
10999 instance->CallAsFunction(v8_num(42), 0, NULL);
11000 CHECK(a3->StrictEquals(instance));
11001 Local<v8::Value> a4 =
11002 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11003 CHECK(a4->StrictEquals(instance));
11004 Local<v8::Value> a5 =
11005 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11006 CHECK(a5->StrictEquals(instance));
11010 "function ReturnThisSloppy() {"
11013 "function ReturnThisStrict() {"
11017 Local<Function> ReturnThisSloppy =
11018 Local<Function>::Cast(
11019 context->Global()->Get(v8_str("ReturnThisSloppy")));
11020 Local<Function> ReturnThisStrict =
11021 Local<Function>::Cast(
11022 context->Global()->Get(v8_str("ReturnThisStrict")));
11024 Local<v8::Value> a1 =
11025 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11026 CHECK(a1->StrictEquals(context->Global()));
11027 Local<v8::Value> a2 =
11028 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11029 CHECK(a2->StrictEquals(context->Global()));
11030 Local<v8::Value> a3 =
11031 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11032 CHECK(a3->IsNumberObject());
11033 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11034 Local<v8::Value> a4 =
11035 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11036 CHECK(a4->IsStringObject());
11037 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11038 Local<v8::Value> a5 =
11039 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11040 CHECK(a5->IsBooleanObject());
11041 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11043 Local<v8::Value> a6 =
11044 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11045 CHECK(a6->IsUndefined());
11046 Local<v8::Value> a7 =
11047 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11048 CHECK(a7->IsNull());
11049 Local<v8::Value> a8 =
11050 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11051 CHECK(a8->StrictEquals(v8_num(42)));
11052 Local<v8::Value> a9 =
11053 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11054 CHECK(a9->StrictEquals(v8_str("hello")));
11055 Local<v8::Value> a10 =
11056 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11057 CHECK(a10->StrictEquals(v8::True(isolate)));
11062 // Check whether a non-function object is callable.
11063 THREADED_TEST(CallableObject) {
11064 LocalContext context;
11065 v8::Isolate* isolate = context->GetIsolate();
11066 v8::HandleScope scope(isolate);
11068 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11069 instance_template->SetCallAsFunctionHandler(call_as_function);
11070 Local<Object> instance = instance_template->NewInstance();
11071 v8::TryCatch try_catch;
11073 CHECK(instance->IsCallable());
11074 CHECK(!try_catch.HasCaught());
11077 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11078 Local<Object> instance = instance_template->NewInstance();
11079 v8::TryCatch try_catch;
11081 CHECK(!instance->IsCallable());
11082 CHECK(!try_catch.HasCaught());
11085 { Local<FunctionTemplate> function_template =
11086 FunctionTemplate::New(isolate, call_as_function);
11087 Local<Function> function = function_template->GetFunction();
11088 Local<Object> instance = function;
11089 v8::TryCatch try_catch;
11091 CHECK(instance->IsCallable());
11092 CHECK(!try_catch.HasCaught());
11095 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11096 Local<Function> function = function_template->GetFunction();
11097 Local<Object> instance = function;
11098 v8::TryCatch try_catch;
11100 CHECK(instance->IsCallable());
11101 CHECK(!try_catch.HasCaught());
11106 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11107 v8::HandleScope scope(isolate);
11108 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11109 for (int i = 0; i < iterations; i++) {
11110 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11112 return Recurse(isolate, depth - 1, iterations);
11116 THREADED_TEST(HandleIteration) {
11117 static const int kIterations = 500;
11118 static const int kNesting = 200;
11119 LocalContext context;
11120 v8::Isolate* isolate = context->GetIsolate();
11121 v8::HandleScope scope0(isolate);
11122 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11124 v8::HandleScope scope1(isolate);
11125 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11126 for (int i = 0; i < kIterations; i++) {
11127 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11128 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11131 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11133 v8::HandleScope scope2(CcTest::isolate());
11134 for (int j = 0; j < kIterations; j++) {
11135 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11136 CHECK_EQ(j + 1 + kIterations,
11137 v8::HandleScope::NumberOfHandles(isolate));
11140 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11142 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11143 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11147 static void InterceptorHasOwnPropertyGetter(
11148 Local<String> name,
11149 const v8::PropertyCallbackInfo<v8::Value>& info) {
11150 ApiTestFuzzer::Fuzz();
11154 THREADED_TEST(InterceptorHasOwnProperty) {
11155 LocalContext context;
11156 v8::Isolate* isolate = context->GetIsolate();
11157 v8::HandleScope scope(isolate);
11158 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11159 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11160 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11161 Local<Function> function = fun_templ->GetFunction();
11162 context->Global()->Set(v8_str("constructor"), function);
11163 v8::Handle<Value> value = CompileRun(
11164 "var o = new constructor();"
11165 "o.hasOwnProperty('ostehaps');");
11166 CHECK_EQ(false, value->BooleanValue());
11167 value = CompileRun(
11169 "o.hasOwnProperty('ostehaps');");
11170 CHECK_EQ(true, value->BooleanValue());
11171 value = CompileRun(
11172 "var p = new constructor();"
11173 "p.hasOwnProperty('ostehaps');");
11174 CHECK_EQ(false, value->BooleanValue());
11178 static void InterceptorHasOwnPropertyGetterGC(
11179 Local<String> name,
11180 const v8::PropertyCallbackInfo<v8::Value>& info) {
11181 ApiTestFuzzer::Fuzz();
11182 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11186 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11187 LocalContext context;
11188 v8::Isolate* isolate = context->GetIsolate();
11189 v8::HandleScope scope(isolate);
11190 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11191 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11192 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11193 Local<Function> function = fun_templ->GetFunction();
11194 context->Global()->Set(v8_str("constructor"), function);
11195 // Let's first make some stuff so we can be sure to get a good GC.
11197 "function makestr(size) {"
11199 " case 1: return 'f';"
11200 " case 2: return 'fo';"
11201 " case 3: return 'foo';"
11203 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11205 "var x = makestr(12345);"
11206 "x = makestr(31415);"
11207 "x = makestr(23456);");
11208 v8::Handle<Value> value = CompileRun(
11209 "var o = new constructor();"
11210 "o.__proto__ = new String(x);"
11211 "o.hasOwnProperty('ostehaps');");
11212 CHECK_EQ(false, value->BooleanValue());
11216 typedef void (*NamedPropertyGetter)(
11217 Local<String> property,
11218 const v8::PropertyCallbackInfo<v8::Value>& info);
11221 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11222 const char* source,
11224 v8::Isolate* isolate = CcTest::isolate();
11225 v8::HandleScope scope(isolate);
11226 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11227 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11228 LocalContext context;
11229 context->Global()->Set(v8_str("o"), templ->NewInstance());
11230 v8::Handle<Value> value = CompileRun(source);
11231 CHECK_EQ(expected, value->Int32Value());
11235 static void InterceptorLoadICGetter(
11236 Local<String> name,
11237 const v8::PropertyCallbackInfo<v8::Value>& info) {
11238 ApiTestFuzzer::Fuzz();
11239 v8::Isolate* isolate = CcTest::isolate();
11240 CHECK_EQ(isolate, info.GetIsolate());
11241 CHECK_EQ(v8_str("data"), info.Data());
11242 CHECK_EQ(v8_str("x"), name);
11243 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11247 // This test should hit the load IC for the interceptor case.
11248 THREADED_TEST(InterceptorLoadIC) {
11249 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11251 "for (var i = 0; i < 1000; i++) {"
11258 // Below go several tests which verify that JITing for various
11259 // configurations of interceptor and explicit fields works fine
11260 // (those cases are special cased to get better performance).
11262 static void InterceptorLoadXICGetter(
11263 Local<String> name,
11264 const v8::PropertyCallbackInfo<v8::Value>& info) {
11265 ApiTestFuzzer::Fuzz();
11266 info.GetReturnValue().Set(
11267 v8_str("x")->Equals(name) ?
11268 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11269 v8::Handle<v8::Value>());
11273 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11274 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11277 "for (var i = 0; i < 1000; i++) {"
11284 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11285 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11287 "o.__proto__ = { 'y': 239 };"
11288 "for (var i = 0; i < 1000; i++) {"
11289 " result = o.y + o.x;"
11295 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11296 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11298 "o.__proto__.y = 239;"
11299 "for (var i = 0; i < 1000; i++) {"
11300 " result = o.y + o.x;"
11306 THREADED_TEST(InterceptorLoadICUndefined) {
11307 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11309 "for (var i = 0; i < 1000; i++) {"
11310 " result = (o.y == undefined) ? 239 : 42;"
11316 THREADED_TEST(InterceptorLoadICWithOverride) {
11317 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11318 "fst = new Object(); fst.__proto__ = o;"
11319 "snd = new Object(); snd.__proto__ = fst;"
11321 "for (var i = 0; i < 1000; i++) {"
11322 " result1 = snd.x;"
11326 "for (var i = 0; i < 1000; i++) {"
11329 "result + result1",
11334 // Test the case when we stored field into
11335 // a stub, but interceptor produced value on its own.
11336 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11337 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11338 "proto = new Object();"
11339 "o.__proto__ = proto;"
11341 "for (var i = 0; i < 1000; i++) {"
11343 // Now it should be ICed and keep a reference to x defined on proto
11346 "for (var i = 0; i < 1000; i++) {"
11354 // Test the case when we stored field into
11355 // a stub, but it got invalidated later on.
11356 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11357 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11358 "proto1 = new Object();"
11359 "proto2 = new Object();"
11360 "o.__proto__ = proto1;"
11361 "proto1.__proto__ = proto2;"
11363 "for (var i = 0; i < 1000; i++) {"
11365 // Now it should be ICed and keep a reference to y defined on proto2
11369 "for (var i = 0; i < 1000; i++) {"
11377 static int interceptor_load_not_handled_calls = 0;
11378 static void InterceptorLoadNotHandled(
11379 Local<String> name,
11380 const v8::PropertyCallbackInfo<v8::Value>& info) {
11381 ++interceptor_load_not_handled_calls;
11385 // Test how post-interceptor lookups are done in the non-cacheable
11386 // case: the interceptor should not be invoked during this lookup.
11387 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11388 interceptor_load_not_handled_calls = 0;
11389 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11390 "receiver = new Object();"
11391 "receiver.__proto__ = o;"
11392 "proto = new Object();"
11393 "/* Make proto a slow-case object. */"
11394 "for (var i = 0; i < 1000; i++) {"
11395 " proto[\"xxxxxxxx\" + i] = [];"
11398 "o.__proto__ = proto;"
11400 "for (var i = 0; i < 1000; i++) {"
11401 " result += receiver.x;"
11405 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11409 // Test the case when we stored field into
11410 // a stub, but it got invalidated later on due to override on
11411 // global object which is between interceptor and fields' holders.
11412 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11413 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11414 "o.__proto__ = this;" // set a global to be a proto of o.
11415 "this.__proto__.y = 239;"
11416 "for (var i = 0; i < 10; i++) {"
11417 " if (o.y != 239) throw 'oops: ' + o.y;"
11418 // Now it should be ICed and keep a reference to y defined on field_holder.
11420 "this.y = 42;" // Assign on a global.
11422 "for (var i = 0; i < 10; i++) {"
11430 static void SetOnThis(Local<String> name,
11431 Local<Value> value,
11432 const v8::PropertyCallbackInfo<void>& info) {
11433 info.This()->ForceSet(name, value);
11437 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11438 v8::Isolate* isolate = CcTest::isolate();
11439 v8::HandleScope scope(isolate);
11440 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11441 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11442 templ->SetAccessor(v8_str("y"), Return239Callback);
11443 LocalContext context;
11444 context->Global()->Set(v8_str("o"), templ->NewInstance());
11446 // Check the case when receiver and interceptor's holder
11447 // are the same objects.
11448 v8::Handle<Value> value = CompileRun(
11450 "for (var i = 0; i < 7; i++) {"
11453 CHECK_EQ(239, value->Int32Value());
11455 // Check the case when interceptor's holder is in proto chain
11457 value = CompileRun(
11458 "r = { __proto__: o };"
11460 "for (var i = 0; i < 7; i++) {"
11463 CHECK_EQ(239, value->Int32Value());
11467 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11468 v8::Isolate* isolate = CcTest::isolate();
11469 v8::HandleScope scope(isolate);
11470 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11471 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11472 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11473 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11475 LocalContext context;
11476 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11477 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11479 // Check the case when receiver and interceptor's holder
11480 // are the same objects.
11481 v8::Handle<Value> value = CompileRun(
11484 "for (var i = 0; i < 7; i++) {"
11485 " result = o.x + o.y;"
11487 CHECK_EQ(239 + 42, value->Int32Value());
11489 // Check the case when interceptor's holder is in proto chain
11491 value = CompileRun(
11492 "r = { __proto__: o };"
11494 "for (var i = 0; i < 7; i++) {"
11495 " result = r.x + r.y;"
11497 CHECK_EQ(239 + 42, value->Int32Value());
11501 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11502 v8::Isolate* isolate = CcTest::isolate();
11503 v8::HandleScope scope(isolate);
11504 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11505 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11506 templ->SetAccessor(v8_str("y"), Return239Callback);
11508 LocalContext context;
11509 context->Global()->Set(v8_str("o"), templ->NewInstance());
11511 v8::Handle<Value> value = CompileRun(
11512 "fst = new Object(); fst.__proto__ = o;"
11513 "snd = new Object(); snd.__proto__ = fst;"
11515 "for (var i = 0; i < 7; i++) {"
11516 " result1 = snd.x;"
11520 "for (var i = 0; i < 7; i++) {"
11523 "result + result1");
11524 CHECK_EQ(239 + 42, value->Int32Value());
11528 // Test the case when we stored callback into
11529 // a stub, but interceptor produced value on its own.
11530 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11531 v8::Isolate* isolate = CcTest::isolate();
11532 v8::HandleScope scope(isolate);
11533 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11534 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11535 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11536 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11538 LocalContext context;
11539 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11540 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11542 v8::Handle<Value> value = CompileRun(
11544 "for (var i = 0; i < 7; i++) {"
11546 // Now it should be ICed and keep a reference to x defined on p
11549 "for (var i = 0; i < 7; i++) {"
11553 CHECK_EQ(42 * 7, value->Int32Value());
11557 // Test the case when we stored callback into
11558 // a stub, but it got invalidated later on.
11559 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11560 v8::Isolate* isolate = CcTest::isolate();
11561 v8::HandleScope scope(isolate);
11562 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11563 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11564 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11565 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11567 LocalContext context;
11568 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11569 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11571 v8::Handle<Value> value = CompileRun(
11572 "inbetween = new Object();"
11573 "o.__proto__ = inbetween;"
11574 "inbetween.__proto__ = p;"
11575 "for (var i = 0; i < 10; i++) {"
11577 // Now it should be ICed and keep a reference to y defined on p
11579 "inbetween.y = 42;"
11581 "for (var i = 0; i < 10; i++) {"
11585 CHECK_EQ(42 * 10, value->Int32Value());
11589 // Test the case when we stored callback into
11590 // a stub, but it got invalidated later on due to override on
11591 // global object which is between interceptor and callbacks' holders.
11592 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11593 v8::Isolate* isolate = CcTest::isolate();
11594 v8::HandleScope scope(isolate);
11595 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11596 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11597 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11598 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11600 LocalContext context;
11601 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11602 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11604 v8::Handle<Value> value = CompileRun(
11605 "o.__proto__ = this;"
11606 "this.__proto__ = p;"
11607 "for (var i = 0; i < 10; i++) {"
11608 " if (o.y != 239) throw 'oops: ' + o.y;"
11609 // Now it should be ICed and keep a reference to y defined on p
11613 "for (var i = 0; i < 10; i++) {"
11617 CHECK_EQ(42 * 10, value->Int32Value());
11621 static void InterceptorLoadICGetter0(
11622 Local<String> name,
11623 const v8::PropertyCallbackInfo<v8::Value>& info) {
11624 ApiTestFuzzer::Fuzz();
11625 CHECK(v8_str("x")->Equals(name));
11626 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11630 THREADED_TEST(InterceptorReturningZero) {
11631 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11632 "o.x == undefined ? 1 : 0",
11637 static void InterceptorStoreICSetter(
11639 Local<Value> value,
11640 const v8::PropertyCallbackInfo<v8::Value>& info) {
11641 CHECK(v8_str("x")->Equals(key));
11642 CHECK_EQ(42, value->Int32Value());
11643 info.GetReturnValue().Set(value);
11647 // This test should hit the store IC for the interceptor case.
11648 THREADED_TEST(InterceptorStoreIC) {
11649 v8::Isolate* isolate = CcTest::isolate();
11650 v8::HandleScope scope(isolate);
11651 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11652 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11653 InterceptorStoreICSetter,
11654 0, 0, 0, v8_str("data"));
11655 LocalContext context;
11656 context->Global()->Set(v8_str("o"), templ->NewInstance());
11658 "for (var i = 0; i < 1000; i++) {"
11664 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11665 v8::Isolate* isolate = CcTest::isolate();
11666 v8::HandleScope scope(isolate);
11667 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11668 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11669 LocalContext context;
11670 context->Global()->Set(v8_str("o"), templ->NewInstance());
11671 v8::Handle<Value> value = CompileRun(
11672 "for (var i = 0; i < 1000; i++) {"
11676 CHECK_EQ(239 + 42, value->Int32Value());
11682 v8::Handle<Value> call_ic_function;
11683 v8::Handle<Value> call_ic_function2;
11684 v8::Handle<Value> call_ic_function3;
11686 static void InterceptorCallICGetter(
11687 Local<String> name,
11688 const v8::PropertyCallbackInfo<v8::Value>& info) {
11689 ApiTestFuzzer::Fuzz();
11690 CHECK(v8_str("x")->Equals(name));
11691 info.GetReturnValue().Set(call_ic_function);
11695 // This test should hit the call IC for the interceptor case.
11696 THREADED_TEST(InterceptorCallIC) {
11697 v8::Isolate* isolate = CcTest::isolate();
11698 v8::HandleScope scope(isolate);
11699 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11700 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11701 LocalContext context;
11702 context->Global()->Set(v8_str("o"), templ->NewInstance());
11704 v8_compile("function f(x) { return x + 1; }; f")->Run();
11705 v8::Handle<Value> value = CompileRun(
11707 "for (var i = 0; i < 1000; i++) {"
11708 " result = o.x(41);"
11710 CHECK_EQ(42, value->Int32Value());
11714 // This test checks that if interceptor doesn't provide
11715 // a value, we can fetch regular value.
11716 THREADED_TEST(InterceptorCallICSeesOthers) {
11717 v8::Isolate* isolate = CcTest::isolate();
11718 v8::HandleScope scope(isolate);
11719 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11720 templ->SetNamedPropertyHandler(NoBlockGetterX);
11721 LocalContext context;
11722 context->Global()->Set(v8_str("o"), templ->NewInstance());
11723 v8::Handle<Value> value = CompileRun(
11724 "o.x = function f(x) { return x + 1; };"
11726 "for (var i = 0; i < 7; i++) {"
11727 " result = o.x(41);"
11729 CHECK_EQ(42, value->Int32Value());
11733 static v8::Handle<Value> call_ic_function4;
11734 static void InterceptorCallICGetter4(
11735 Local<String> name,
11736 const v8::PropertyCallbackInfo<v8::Value>& info) {
11737 ApiTestFuzzer::Fuzz();
11738 CHECK(v8_str("x")->Equals(name));
11739 info.GetReturnValue().Set(call_ic_function4);
11743 // This test checks that if interceptor provides a function,
11744 // even if we cached shadowed variant, interceptor's function
11746 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11747 v8::Isolate* isolate = CcTest::isolate();
11748 v8::HandleScope scope(isolate);
11749 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11750 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11751 LocalContext context;
11752 context->Global()->Set(v8_str("o"), templ->NewInstance());
11753 call_ic_function4 =
11754 v8_compile("function f(x) { return x - 1; }; f")->Run();
11755 v8::Handle<Value> value = CompileRun(
11756 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11758 "for (var i = 0; i < 1000; i++) {"
11759 " result = o.x(42);"
11761 CHECK_EQ(41, value->Int32Value());
11765 // Test the case when we stored cacheable lookup into
11766 // a stub, but it got invalidated later on
11767 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11768 v8::Isolate* isolate = CcTest::isolate();
11769 v8::HandleScope scope(isolate);
11770 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11771 templ->SetNamedPropertyHandler(NoBlockGetterX);
11772 LocalContext context;
11773 context->Global()->Set(v8_str("o"), templ->NewInstance());
11774 v8::Handle<Value> value = CompileRun(
11775 "proto1 = new Object();"
11776 "proto2 = new Object();"
11777 "o.__proto__ = proto1;"
11778 "proto1.__proto__ = proto2;"
11779 "proto2.y = function(x) { return x + 1; };"
11780 // Invoke it many times to compile a stub
11781 "for (var i = 0; i < 7; i++) {"
11784 "proto1.y = function(x) { return x - 1; };"
11786 "for (var i = 0; i < 7; i++) {"
11787 " result += o.y(42);"
11789 CHECK_EQ(41 * 7, value->Int32Value());
11793 // This test checks that if interceptor doesn't provide a function,
11794 // cached constant function is used
11795 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11796 v8::Isolate* isolate = CcTest::isolate();
11797 v8::HandleScope scope(isolate);
11798 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11799 templ->SetNamedPropertyHandler(NoBlockGetterX);
11800 LocalContext context;
11801 context->Global()->Set(v8_str("o"), templ->NewInstance());
11802 v8::Handle<Value> value = CompileRun(
11803 "function inc(x) { return x + 1; };"
11807 "for (var i = 0; i < 1000; i++) {"
11808 " result = o.x(42);"
11810 CHECK_EQ(43, value->Int32Value());
11814 static v8::Handle<Value> call_ic_function5;
11815 static void InterceptorCallICGetter5(
11816 Local<String> name,
11817 const v8::PropertyCallbackInfo<v8::Value>& info) {
11818 ApiTestFuzzer::Fuzz();
11819 if (v8_str("x")->Equals(name))
11820 info.GetReturnValue().Set(call_ic_function5);
11824 // This test checks that if interceptor provides a function,
11825 // even if we cached constant function, interceptor's function
11827 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11828 v8::Isolate* isolate = CcTest::isolate();
11829 v8::HandleScope scope(isolate);
11830 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11831 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11832 LocalContext context;
11833 context->Global()->Set(v8_str("o"), templ->NewInstance());
11834 call_ic_function5 =
11835 v8_compile("function f(x) { return x - 1; }; f")->Run();
11836 v8::Handle<Value> value = CompileRun(
11837 "function inc(x) { return x + 1; };"
11841 "for (var i = 0; i < 1000; i++) {"
11842 " result = o.x(42);"
11844 CHECK_EQ(41, value->Int32Value());
11848 static v8::Handle<Value> call_ic_function6;
11849 static void InterceptorCallICGetter6(
11850 Local<String> name,
11851 const v8::PropertyCallbackInfo<v8::Value>& info) {
11852 ApiTestFuzzer::Fuzz();
11853 if (v8_str("x")->Equals(name))
11854 info.GetReturnValue().Set(call_ic_function6);
11858 // Same test as above, except the code is wrapped in a function
11859 // to test the optimized compiler.
11860 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11861 i::FLAG_allow_natives_syntax = true;
11862 v8::Isolate* isolate = CcTest::isolate();
11863 v8::HandleScope scope(isolate);
11864 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11865 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11866 LocalContext context;
11867 context->Global()->Set(v8_str("o"), templ->NewInstance());
11868 call_ic_function6 =
11869 v8_compile("function f(x) { return x - 1; }; f")->Run();
11870 v8::Handle<Value> value = CompileRun(
11871 "function inc(x) { return x + 1; };"
11874 "function test() {"
11876 " for (var i = 0; i < 1000; i++) {"
11877 " result = o.x(42);"
11884 "%OptimizeFunctionOnNextCall(test);"
11886 CHECK_EQ(41, value->Int32Value());
11890 // Test the case when we stored constant function into
11891 // a stub, but it got invalidated later on
11892 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11893 v8::Isolate* isolate = CcTest::isolate();
11894 v8::HandleScope scope(isolate);
11895 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11896 templ->SetNamedPropertyHandler(NoBlockGetterX);
11897 LocalContext context;
11898 context->Global()->Set(v8_str("o"), templ->NewInstance());
11899 v8::Handle<Value> value = CompileRun(
11900 "function inc(x) { return x + 1; };"
11902 "proto1 = new Object();"
11903 "proto2 = new Object();"
11904 "o.__proto__ = proto1;"
11905 "proto1.__proto__ = proto2;"
11907 // Invoke it many times to compile a stub
11908 "for (var i = 0; i < 7; i++) {"
11911 "proto1.y = function(x) { return x - 1; };"
11913 "for (var i = 0; i < 7; i++) {"
11914 " result += o.y(42);"
11916 CHECK_EQ(41 * 7, value->Int32Value());
11920 // Test the case when we stored constant function into
11921 // a stub, but it got invalidated later on due to override on
11922 // global object which is between interceptor and constant function' holders.
11923 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11924 v8::Isolate* isolate = CcTest::isolate();
11925 v8::HandleScope scope(isolate);
11926 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11927 templ->SetNamedPropertyHandler(NoBlockGetterX);
11928 LocalContext context;
11929 context->Global()->Set(v8_str("o"), templ->NewInstance());
11930 v8::Handle<Value> value = CompileRun(
11931 "function inc(x) { return x + 1; };"
11933 "o.__proto__ = this;"
11934 "this.__proto__.y = inc;"
11935 // Invoke it many times to compile a stub
11936 "for (var i = 0; i < 7; i++) {"
11937 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11939 "this.y = function(x) { return x - 1; };"
11941 "for (var i = 0; i < 7; i++) {"
11942 " result += o.y(42);"
11944 CHECK_EQ(41 * 7, value->Int32Value());
11948 // Test the case when actual function to call sits on global object.
11949 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11950 v8::Isolate* isolate = CcTest::isolate();
11951 v8::HandleScope scope(isolate);
11952 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11953 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11955 LocalContext context;
11956 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11958 v8::Handle<Value> value = CompileRun(
11960 " o.__proto__ = this;"
11961 " for (var i = 0; i < 10; i++) {"
11962 " var v = o.parseFloat('239');"
11963 " if (v != 239) throw v;"
11964 // Now it should be ICed and keep a reference to parseFloat.
11967 " for (var i = 0; i < 10; i++) {"
11968 " result += o.parseFloat('239');"
11974 CHECK_EQ(239 * 10, value->Int32Value());
11977 static void InterceptorCallICFastApi(
11978 Local<String> name,
11979 const v8::PropertyCallbackInfo<v8::Value>& info) {
11980 ApiTestFuzzer::Fuzz();
11981 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11983 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11985 if ((*call_count) % 20 == 0) {
11986 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11990 static void FastApiCallback_TrivialSignature(
11991 const v8::FunctionCallbackInfo<v8::Value>& args) {
11992 ApiTestFuzzer::Fuzz();
11993 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11994 v8::Isolate* isolate = CcTest::isolate();
11995 CHECK_EQ(isolate, args.GetIsolate());
11996 CHECK_EQ(args.This(), args.Holder());
11997 CHECK(args.Data()->Equals(v8_str("method_data")));
11998 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12001 static void FastApiCallback_SimpleSignature(
12002 const v8::FunctionCallbackInfo<v8::Value>& args) {
12003 ApiTestFuzzer::Fuzz();
12004 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12005 v8::Isolate* isolate = CcTest::isolate();
12006 CHECK_EQ(isolate, args.GetIsolate());
12007 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12008 CHECK(args.Data()->Equals(v8_str("method_data")));
12009 // Note, we're using HasRealNamedProperty instead of Has to avoid
12010 // invoking the interceptor again.
12011 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12012 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12016 // Helper to maximize the odds of object moving.
12017 static void GenerateSomeGarbage() {
12020 "for (var i = 0; i < 1000; i++) {"
12021 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12023 "garbage = undefined;");
12027 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12028 static int count = 0;
12029 if (count++ % 3 == 0) {
12030 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12031 // This should move the stub
12032 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12037 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12038 LocalContext context;
12039 v8::Isolate* isolate = context->GetIsolate();
12040 v8::HandleScope scope(isolate);
12041 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12042 v8::ObjectTemplate::New(isolate);
12043 nativeobject_templ->Set(isolate, "callback",
12044 v8::FunctionTemplate::New(isolate,
12045 DirectApiCallback));
12046 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12047 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12048 // call the api function multiple times to ensure direct call stub creation.
12051 " for (var i = 1; i <= 30; i++) {"
12052 " nativeobject.callback();"
12059 void ThrowingDirectApiCallback(
12060 const v8::FunctionCallbackInfo<v8::Value>& args) {
12061 args.GetIsolate()->ThrowException(v8_str("g"));
12065 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12066 LocalContext context;
12067 v8::Isolate* isolate = context->GetIsolate();
12068 v8::HandleScope scope(isolate);
12069 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12070 v8::ObjectTemplate::New(isolate);
12071 nativeobject_templ->Set(isolate, "callback",
12072 v8::FunctionTemplate::New(isolate,
12073 ThrowingDirectApiCallback));
12074 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12075 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12076 // call the api function multiple times to ensure direct call stub creation.
12077 v8::Handle<Value> result = CompileRun(
12080 " for (var i = 1; i <= 5; i++) {"
12081 " try { nativeobject.callback(); } catch (e) { result += e; }"
12085 CHECK_EQ(v8_str("ggggg"), result);
12089 static Handle<Value> DoDirectGetter() {
12090 if (++p_getter_count % 3 == 0) {
12091 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12092 GenerateSomeGarbage();
12094 return v8_str("Direct Getter Result");
12097 static void DirectGetterCallback(
12098 Local<String> name,
12099 const v8::PropertyCallbackInfo<v8::Value>& info) {
12100 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12101 info.GetReturnValue().Set(DoDirectGetter());
12105 template<typename Accessor>
12106 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12107 LocalContext context;
12108 v8::Isolate* isolate = context->GetIsolate();
12109 v8::HandleScope scope(isolate);
12110 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12111 obj->SetAccessor(v8_str("p1"), accessor);
12112 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12113 p_getter_count = 0;
12114 v8::Handle<v8::Value> result = CompileRun(
12116 " for (var i = 0; i < 30; i++) o1.p1;"
12120 CHECK_EQ(v8_str("Direct Getter Result"), result);
12121 CHECK_EQ(31, p_getter_count);
12125 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12126 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12130 void ThrowingDirectGetterCallback(
12131 Local<String> name,
12132 const v8::PropertyCallbackInfo<v8::Value>& info) {
12133 info.GetIsolate()->ThrowException(v8_str("g"));
12137 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12138 LocalContext context;
12139 v8::Isolate* isolate = context->GetIsolate();
12140 v8::HandleScope scope(isolate);
12141 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12142 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12143 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12144 v8::Handle<Value> result = CompileRun(
12146 "for (var i = 0; i < 5; i++) {"
12147 " try { o1.p1; } catch (e) { result += e; }"
12150 CHECK_EQ(v8_str("ggggg"), result);
12154 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12155 int interceptor_call_count = 0;
12156 v8::Isolate* isolate = CcTest::isolate();
12157 v8::HandleScope scope(isolate);
12158 v8::Handle<v8::FunctionTemplate> fun_templ =
12159 v8::FunctionTemplate::New(isolate);
12160 v8::Handle<v8::FunctionTemplate> method_templ =
12161 v8::FunctionTemplate::New(isolate,
12162 FastApiCallback_TrivialSignature,
12163 v8_str("method_data"),
12164 v8::Handle<v8::Signature>());
12165 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12166 proto_templ->Set(v8_str("method"), method_templ);
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 "for (var i = 0; i < 100; i++) {"
12178 " result = o.method(41);"
12180 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12181 CHECK_EQ(100, interceptor_call_count);
12185 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12186 int interceptor_call_count = 0;
12187 v8::Isolate* isolate = CcTest::isolate();
12188 v8::HandleScope scope(isolate);
12189 v8::Handle<v8::FunctionTemplate> fun_templ =
12190 v8::FunctionTemplate::New(isolate);
12191 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12192 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12193 v8::Signature::New(isolate, fun_templ));
12194 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12195 proto_templ->Set(v8_str("method"), method_templ);
12196 fun_templ->SetHiddenPrototype(true);
12197 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12198 templ->SetNamedPropertyHandler(
12199 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12200 v8::External::New(isolate, &interceptor_call_count));
12201 LocalContext context;
12202 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12203 GenerateSomeGarbage();
12204 context->Global()->Set(v8_str("o"), fun->NewInstance());
12207 "var receiver = {};"
12208 "receiver.__proto__ = o;"
12210 "for (var i = 0; i < 100; i++) {"
12211 " result = receiver.method(41);"
12213 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12214 CHECK_EQ(100, interceptor_call_count);
12218 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12219 int interceptor_call_count = 0;
12220 v8::Isolate* isolate = CcTest::isolate();
12221 v8::HandleScope scope(isolate);
12222 v8::Handle<v8::FunctionTemplate> fun_templ =
12223 v8::FunctionTemplate::New(isolate);
12224 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12225 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12226 v8::Signature::New(isolate, fun_templ));
12227 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12228 proto_templ->Set(v8_str("method"), method_templ);
12229 fun_templ->SetHiddenPrototype(true);
12230 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12231 templ->SetNamedPropertyHandler(
12232 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12233 v8::External::New(isolate, &interceptor_call_count));
12234 LocalContext context;
12235 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12236 GenerateSomeGarbage();
12237 context->Global()->Set(v8_str("o"), fun->NewInstance());
12240 "var receiver = {};"
12241 "receiver.__proto__ = o;"
12243 "var saved_result = 0;"
12244 "for (var i = 0; i < 100; i++) {"
12245 " result = receiver.method(41);"
12247 " saved_result = result;"
12248 " receiver = {method: function(x) { return x - 1 }};"
12251 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12252 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12253 CHECK_GE(interceptor_call_count, 50);
12257 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12258 int interceptor_call_count = 0;
12259 v8::Isolate* isolate = CcTest::isolate();
12260 v8::HandleScope scope(isolate);
12261 v8::Handle<v8::FunctionTemplate> fun_templ =
12262 v8::FunctionTemplate::New(isolate);
12263 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12264 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12265 v8::Signature::New(isolate, fun_templ));
12266 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12267 proto_templ->Set(v8_str("method"), method_templ);
12268 fun_templ->SetHiddenPrototype(true);
12269 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12270 templ->SetNamedPropertyHandler(
12271 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12272 v8::External::New(isolate, &interceptor_call_count));
12273 LocalContext context;
12274 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12275 GenerateSomeGarbage();
12276 context->Global()->Set(v8_str("o"), fun->NewInstance());
12279 "var receiver = {};"
12280 "receiver.__proto__ = o;"
12282 "var saved_result = 0;"
12283 "for (var i = 0; i < 100; i++) {"
12284 " result = receiver.method(41);"
12286 " saved_result = result;"
12287 " o.method = function(x) { return x - 1 };"
12290 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12291 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12292 CHECK_GE(interceptor_call_count, 50);
12296 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12297 int interceptor_call_count = 0;
12298 v8::Isolate* isolate = CcTest::isolate();
12299 v8::HandleScope scope(isolate);
12300 v8::Handle<v8::FunctionTemplate> fun_templ =
12301 v8::FunctionTemplate::New(isolate);
12302 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12303 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12304 v8::Signature::New(isolate, fun_templ));
12305 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12306 proto_templ->Set(v8_str("method"), method_templ);
12307 fun_templ->SetHiddenPrototype(true);
12308 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12309 templ->SetNamedPropertyHandler(
12310 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12311 v8::External::New(isolate, &interceptor_call_count));
12312 LocalContext context;
12313 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12314 GenerateSomeGarbage();
12315 context->Global()->Set(v8_str("o"), fun->NewInstance());
12316 v8::TryCatch try_catch;
12319 "var receiver = {};"
12320 "receiver.__proto__ = o;"
12322 "var saved_result = 0;"
12323 "for (var i = 0; i < 100; i++) {"
12324 " result = receiver.method(41);"
12326 " saved_result = result;"
12330 CHECK(try_catch.HasCaught());
12331 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
12332 try_catch.Exception()->ToString());
12333 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12334 CHECK_GE(interceptor_call_count, 50);
12338 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12339 int interceptor_call_count = 0;
12340 v8::Isolate* isolate = CcTest::isolate();
12341 v8::HandleScope scope(isolate);
12342 v8::Handle<v8::FunctionTemplate> fun_templ =
12343 v8::FunctionTemplate::New(isolate);
12344 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12345 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12346 v8::Signature::New(isolate, fun_templ));
12347 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12348 proto_templ->Set(v8_str("method"), method_templ);
12349 fun_templ->SetHiddenPrototype(true);
12350 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12351 templ->SetNamedPropertyHandler(
12352 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12353 v8::External::New(isolate, &interceptor_call_count));
12354 LocalContext context;
12355 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12356 GenerateSomeGarbage();
12357 context->Global()->Set(v8_str("o"), fun->NewInstance());
12358 v8::TryCatch try_catch;
12361 "var receiver = {};"
12362 "receiver.__proto__ = o;"
12364 "var saved_result = 0;"
12365 "for (var i = 0; i < 100; i++) {"
12366 " result = receiver.method(41);"
12368 " saved_result = result;"
12369 " receiver = {method: receiver.method};"
12372 CHECK(try_catch.HasCaught());
12373 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12374 try_catch.Exception()->ToString());
12375 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12376 CHECK_GE(interceptor_call_count, 50);
12380 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12381 v8::Isolate* isolate = CcTest::isolate();
12382 v8::HandleScope scope(isolate);
12383 v8::Handle<v8::FunctionTemplate> fun_templ =
12384 v8::FunctionTemplate::New(isolate);
12385 v8::Handle<v8::FunctionTemplate> method_templ =
12386 v8::FunctionTemplate::New(isolate,
12387 FastApiCallback_TrivialSignature,
12388 v8_str("method_data"),
12389 v8::Handle<v8::Signature>());
12390 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12391 proto_templ->Set(v8_str("method"), method_templ);
12392 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12394 LocalContext context;
12395 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12396 GenerateSomeGarbage();
12397 context->Global()->Set(v8_str("o"), fun->NewInstance());
12400 "for (var i = 0; i < 100; i++) {"
12401 " result = o.method(41);"
12404 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12408 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12409 v8::Isolate* isolate = CcTest::isolate();
12410 v8::HandleScope scope(isolate);
12411 v8::Handle<v8::FunctionTemplate> fun_templ =
12412 v8::FunctionTemplate::New(isolate);
12413 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12414 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12415 v8::Signature::New(isolate, fun_templ));
12416 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12417 proto_templ->Set(v8_str("method"), method_templ);
12418 fun_templ->SetHiddenPrototype(true);
12419 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12420 CHECK(!templ.IsEmpty());
12421 LocalContext context;
12422 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12423 GenerateSomeGarbage();
12424 context->Global()->Set(v8_str("o"), fun->NewInstance());
12427 "var receiver = {};"
12428 "receiver.__proto__ = o;"
12430 "for (var i = 0; i < 100; i++) {"
12431 " result = receiver.method(41);"
12434 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12438 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12439 v8::Isolate* isolate = CcTest::isolate();
12440 v8::HandleScope scope(isolate);
12441 v8::Handle<v8::FunctionTemplate> fun_templ =
12442 v8::FunctionTemplate::New(isolate);
12443 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12444 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12445 v8::Signature::New(isolate, fun_templ));
12446 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12447 proto_templ->Set(v8_str("method"), method_templ);
12448 fun_templ->SetHiddenPrototype(true);
12449 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12450 CHECK(!templ.IsEmpty());
12451 LocalContext context;
12452 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12453 GenerateSomeGarbage();
12454 context->Global()->Set(v8_str("o"), fun->NewInstance());
12457 "var receiver = {};"
12458 "receiver.__proto__ = o;"
12460 "var saved_result = 0;"
12461 "for (var i = 0; i < 100; i++) {"
12462 " result = receiver.method(41);"
12464 " saved_result = result;"
12465 " receiver = {method: function(x) { return x - 1 }};"
12468 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12469 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12473 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12474 v8::Isolate* isolate = CcTest::isolate();
12475 v8::HandleScope scope(isolate);
12476 v8::Handle<v8::FunctionTemplate> fun_templ =
12477 v8::FunctionTemplate::New(isolate);
12478 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12479 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12480 v8::Signature::New(isolate, fun_templ));
12481 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12482 proto_templ->Set(v8_str("method"), method_templ);
12483 fun_templ->SetHiddenPrototype(true);
12484 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12485 CHECK(!templ.IsEmpty());
12486 LocalContext context;
12487 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12488 GenerateSomeGarbage();
12489 context->Global()->Set(v8_str("o"), fun->NewInstance());
12490 v8::TryCatch try_catch;
12493 "var receiver = {};"
12494 "receiver.__proto__ = o;"
12496 "var saved_result = 0;"
12497 "for (var i = 0; i < 100; i++) {"
12498 " result = receiver.method(41);"
12500 " saved_result = result;"
12504 CHECK(try_catch.HasCaught());
12505 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
12506 try_catch.Exception()->ToString());
12507 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12511 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12512 v8::Isolate* isolate = CcTest::isolate();
12513 v8::HandleScope scope(isolate);
12514 v8::Handle<v8::FunctionTemplate> fun_templ =
12515 v8::FunctionTemplate::New(isolate);
12516 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12517 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12518 v8::Signature::New(isolate, fun_templ));
12519 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12520 proto_templ->Set(v8_str("method"), method_templ);
12521 fun_templ->SetHiddenPrototype(true);
12522 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12523 CHECK(!templ.IsEmpty());
12524 LocalContext context;
12525 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12526 GenerateSomeGarbage();
12527 context->Global()->Set(v8_str("o"), fun->NewInstance());
12528 v8::TryCatch try_catch;
12531 "var receiver = {};"
12532 "receiver.__proto__ = o;"
12534 "var saved_result = 0;"
12535 "for (var i = 0; i < 100; i++) {"
12536 " result = receiver.method(41);"
12538 " saved_result = result;"
12539 " receiver = Object.create(receiver);"
12542 CHECK(try_catch.HasCaught());
12543 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12544 try_catch.Exception()->ToString());
12545 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12549 v8::Handle<Value> keyed_call_ic_function;
12551 static void InterceptorKeyedCallICGetter(
12552 Local<String> name,
12553 const v8::PropertyCallbackInfo<v8::Value>& info) {
12554 ApiTestFuzzer::Fuzz();
12555 if (v8_str("x")->Equals(name)) {
12556 info.GetReturnValue().Set(keyed_call_ic_function);
12561 // Test the case when we stored cacheable lookup into
12562 // a stub, but the function name changed (to another cacheable function).
12563 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12564 v8::Isolate* isolate = CcTest::isolate();
12565 v8::HandleScope scope(isolate);
12566 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12567 templ->SetNamedPropertyHandler(NoBlockGetterX);
12568 LocalContext context;
12569 context->Global()->Set(v8_str("o"), templ->NewInstance());
12571 "proto = new Object();"
12572 "proto.y = function(x) { return x + 1; };"
12573 "proto.z = function(x) { return x - 1; };"
12574 "o.__proto__ = proto;"
12576 "var method = 'y';"
12577 "for (var i = 0; i < 10; i++) {"
12578 " if (i == 5) { method = 'z'; };"
12579 " result += o[method](41);"
12581 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12585 // Test the case when we stored cacheable lookup into
12586 // a stub, but the function name changed (and the new function is present
12587 // both before and after the interceptor in the prototype chain).
12588 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12589 v8::Isolate* isolate = CcTest::isolate();
12590 v8::HandleScope scope(isolate);
12591 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12592 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12593 LocalContext context;
12594 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12595 keyed_call_ic_function =
12596 v8_compile("function f(x) { return x - 1; }; f")->Run();
12598 "o = new Object();"
12599 "proto2 = new Object();"
12600 "o.y = function(x) { return x + 1; };"
12601 "proto2.y = function(x) { return x + 2; };"
12602 "o.__proto__ = proto1;"
12603 "proto1.__proto__ = proto2;"
12605 "var method = 'x';"
12606 "for (var i = 0; i < 10; i++) {"
12607 " if (i == 5) { method = 'y'; };"
12608 " result += o[method](41);"
12610 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12614 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12615 // on the global object.
12616 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12617 v8::Isolate* isolate = CcTest::isolate();
12618 v8::HandleScope scope(isolate);
12619 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12620 templ->SetNamedPropertyHandler(NoBlockGetterX);
12621 LocalContext context;
12622 context->Global()->Set(v8_str("o"), templ->NewInstance());
12624 "function inc(x) { return x + 1; };"
12626 "function dec(x) { return x - 1; };"
12628 "o.__proto__ = this;"
12629 "this.__proto__.x = inc;"
12630 "this.__proto__.y = dec;"
12632 "var method = 'x';"
12633 "for (var i = 0; i < 10; i++) {"
12634 " if (i == 5) { method = 'y'; };"
12635 " result += o[method](41);"
12637 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12641 // Test the case when actual function to call sits on global object.
12642 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12643 v8::Isolate* isolate = CcTest::isolate();
12644 v8::HandleScope scope(isolate);
12645 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12646 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12647 LocalContext context;
12648 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12651 "function len(x) { return x.length; };"
12652 "o.__proto__ = this;"
12653 "var m = 'parseFloat';"
12655 "for (var i = 0; i < 10; i++) {"
12658 " saved_result = result;"
12660 " result = o[m]('239');"
12662 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12663 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12667 // Test the map transition before the interceptor.
12668 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12669 v8::Isolate* isolate = CcTest::isolate();
12670 v8::HandleScope scope(isolate);
12671 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12672 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12673 LocalContext context;
12674 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12677 "var o = new Object();"
12678 "o.__proto__ = proto;"
12679 "o.method = function(x) { return x + 1; };"
12680 "var m = 'method';"
12682 "for (var i = 0; i < 10; i++) {"
12683 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12684 " result += o[m](41);"
12686 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12690 // Test the map transition after the interceptor.
12691 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12692 v8::Isolate* isolate = CcTest::isolate();
12693 v8::HandleScope scope(isolate);
12694 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12695 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12696 LocalContext context;
12697 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12700 "var proto = new Object();"
12701 "o.__proto__ = proto;"
12702 "proto.method = function(x) { return x + 1; };"
12703 "var m = 'method';"
12705 "for (var i = 0; i < 10; i++) {"
12706 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12707 " result += o[m](41);"
12709 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12713 static int interceptor_call_count = 0;
12715 static void InterceptorICRefErrorGetter(
12716 Local<String> name,
12717 const v8::PropertyCallbackInfo<v8::Value>& info) {
12718 ApiTestFuzzer::Fuzz();
12719 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12720 info.GetReturnValue().Set(call_ic_function2);
12725 // This test should hit load and call ICs for the interceptor case.
12726 // Once in a while, the interceptor will reply that a property was not
12727 // found in which case we should get a reference error.
12728 THREADED_TEST(InterceptorICReferenceErrors) {
12729 v8::Isolate* isolate = CcTest::isolate();
12730 v8::HandleScope scope(isolate);
12731 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12732 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12733 LocalContext context(0, templ, v8::Handle<Value>());
12734 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12735 v8::Handle<Value> value = CompileRun(
12737 " for (var i = 0; i < 1000; i++) {"
12738 " try { x; } catch(e) { return true; }"
12743 CHECK_EQ(true, value->BooleanValue());
12744 interceptor_call_count = 0;
12745 value = CompileRun(
12747 " for (var i = 0; i < 1000; i++) {"
12748 " try { x(42); } catch(e) { return true; }"
12753 CHECK_EQ(true, value->BooleanValue());
12757 static int interceptor_ic_exception_get_count = 0;
12759 static void InterceptorICExceptionGetter(
12760 Local<String> name,
12761 const v8::PropertyCallbackInfo<v8::Value>& info) {
12762 ApiTestFuzzer::Fuzz();
12763 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12764 info.GetReturnValue().Set(call_ic_function3);
12766 if (interceptor_ic_exception_get_count == 20) {
12767 info.GetIsolate()->ThrowException(v8_num(42));
12773 // Test interceptor load/call IC where the interceptor throws an
12774 // exception once in a while.
12775 THREADED_TEST(InterceptorICGetterExceptions) {
12776 interceptor_ic_exception_get_count = 0;
12777 v8::Isolate* isolate = CcTest::isolate();
12778 v8::HandleScope scope(isolate);
12779 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12780 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12781 LocalContext context(0, templ, v8::Handle<Value>());
12782 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12783 v8::Handle<Value> value = CompileRun(
12785 " for (var i = 0; i < 100; i++) {"
12786 " try { x; } catch(e) { return true; }"
12791 CHECK_EQ(true, value->BooleanValue());
12792 interceptor_ic_exception_get_count = 0;
12793 value = CompileRun(
12795 " for (var i = 0; i < 100; i++) {"
12796 " try { x(42); } catch(e) { return true; }"
12801 CHECK_EQ(true, value->BooleanValue());
12805 static int interceptor_ic_exception_set_count = 0;
12807 static void InterceptorICExceptionSetter(
12809 Local<Value> value,
12810 const v8::PropertyCallbackInfo<v8::Value>& info) {
12811 ApiTestFuzzer::Fuzz();
12812 if (++interceptor_ic_exception_set_count > 20) {
12813 info.GetIsolate()->ThrowException(v8_num(42));
12818 // Test interceptor store IC where the interceptor throws an exception
12819 // once in a while.
12820 THREADED_TEST(InterceptorICSetterExceptions) {
12821 interceptor_ic_exception_set_count = 0;
12822 v8::Isolate* isolate = CcTest::isolate();
12823 v8::HandleScope scope(isolate);
12824 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12825 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12826 LocalContext context(0, templ, v8::Handle<Value>());
12827 v8::Handle<Value> value = CompileRun(
12829 " for (var i = 0; i < 100; i++) {"
12830 " try { x = 42; } catch(e) { return true; }"
12835 CHECK_EQ(true, value->BooleanValue());
12839 // Test that we ignore null interceptors.
12840 THREADED_TEST(NullNamedInterceptor) {
12841 v8::Isolate* isolate = CcTest::isolate();
12842 v8::HandleScope scope(isolate);
12843 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12844 templ->SetNamedPropertyHandler(
12845 static_cast<v8::NamedPropertyGetterCallback>(0));
12846 LocalContext context;
12847 templ->Set(CcTest::isolate(), "x", v8_num(42));
12848 v8::Handle<v8::Object> obj = templ->NewInstance();
12849 context->Global()->Set(v8_str("obj"), obj);
12850 v8::Handle<Value> value = CompileRun("obj.x");
12851 CHECK(value->IsInt32());
12852 CHECK_EQ(42, value->Int32Value());
12856 // Test that we ignore null interceptors.
12857 THREADED_TEST(NullIndexedInterceptor) {
12858 v8::Isolate* isolate = CcTest::isolate();
12859 v8::HandleScope scope(isolate);
12860 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12861 templ->SetIndexedPropertyHandler(
12862 static_cast<v8::IndexedPropertyGetterCallback>(0));
12863 LocalContext context;
12864 templ->Set(CcTest::isolate(), "42", v8_num(42));
12865 v8::Handle<v8::Object> obj = templ->NewInstance();
12866 context->Global()->Set(v8_str("obj"), obj);
12867 v8::Handle<Value> value = CompileRun("obj[42]");
12868 CHECK(value->IsInt32());
12869 CHECK_EQ(42, value->Int32Value());
12873 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12874 v8::Isolate* isolate = CcTest::isolate();
12875 v8::HandleScope scope(isolate);
12876 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12877 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12879 env->Global()->Set(v8_str("obj"),
12880 templ->GetFunction()->NewInstance());
12881 ExpectTrue("obj.x === 42");
12882 ExpectTrue("!obj.propertyIsEnumerable('x')");
12886 static void ThrowingGetter(Local<String> name,
12887 const v8::PropertyCallbackInfo<v8::Value>& info) {
12888 ApiTestFuzzer::Fuzz();
12889 info.GetIsolate()->ThrowException(Handle<Value>());
12890 info.GetReturnValue().SetUndefined();
12894 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12895 LocalContext context;
12896 HandleScope scope(context->GetIsolate());
12898 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12899 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12900 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12902 Local<Object> instance = templ->GetFunction()->NewInstance();
12904 Local<Object> another = Object::New(context->GetIsolate());
12905 another->SetPrototype(instance);
12907 Local<Object> with_js_getter = CompileRun(
12909 "o.__defineGetter__('f', function() { throw undefined; });\n"
12910 "o\n").As<Object>();
12911 CHECK(!with_js_getter.IsEmpty());
12913 TryCatch try_catch;
12915 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12916 CHECK(try_catch.HasCaught());
12918 CHECK(result.IsEmpty());
12920 result = another->GetRealNamedProperty(v8_str("f"));
12921 CHECK(try_catch.HasCaught());
12923 CHECK(result.IsEmpty());
12925 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12926 CHECK(try_catch.HasCaught());
12928 CHECK(result.IsEmpty());
12930 result = another->Get(v8_str("f"));
12931 CHECK(try_catch.HasCaught());
12933 CHECK(result.IsEmpty());
12935 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12936 CHECK(try_catch.HasCaught());
12938 CHECK(result.IsEmpty());
12940 result = with_js_getter->Get(v8_str("f"));
12941 CHECK(try_catch.HasCaught());
12943 CHECK(result.IsEmpty());
12947 static void ThrowingCallbackWithTryCatch(
12948 const v8::FunctionCallbackInfo<v8::Value>& args) {
12949 TryCatch try_catch;
12950 // Verboseness is important: it triggers message delivery which can call into
12952 try_catch.SetVerbose(true);
12953 CompileRun("throw 'from JS';");
12954 CHECK(try_catch.HasCaught());
12955 CHECK(!CcTest::i_isolate()->has_pending_exception());
12956 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12960 static int call_depth;
12963 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12964 TryCatch try_catch;
12968 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12969 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12973 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12974 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12978 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12979 Handle<String> errorMessageString = message->Get();
12980 CHECK(!errorMessageString.IsEmpty());
12981 message->GetStackTrace();
12982 message->GetScriptResourceName();
12986 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12987 LocalContext context;
12988 v8::Isolate* isolate = context->GetIsolate();
12989 HandleScope scope(isolate);
12991 Local<Function> func =
12992 FunctionTemplate::New(isolate,
12993 ThrowingCallbackWithTryCatch)->GetFunction();
12994 context->Global()->Set(v8_str("func"), func);
12996 MessageCallback callbacks[] =
12997 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12998 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12999 MessageCallback callback = callbacks[i];
13000 if (callback != NULL) {
13001 V8::AddMessageListener(callback);
13003 // Some small number to control number of times message handler should
13004 // throw an exception.
13007 "var thrown = false;\n"
13008 "try { func(); } catch(e) { thrown = true; }\n"
13010 if (callback != NULL) {
13011 V8::RemoveMessageListeners(callback);
13017 static void ParentGetter(Local<String> name,
13018 const v8::PropertyCallbackInfo<v8::Value>& info) {
13019 ApiTestFuzzer::Fuzz();
13020 info.GetReturnValue().Set(v8_num(1));
13024 static void ChildGetter(Local<String> name,
13025 const v8::PropertyCallbackInfo<v8::Value>& info) {
13026 ApiTestFuzzer::Fuzz();
13027 info.GetReturnValue().Set(v8_num(42));
13031 THREADED_TEST(Overriding) {
13032 i::FLAG_es5_readonly = true;
13033 LocalContext context;
13034 v8::Isolate* isolate = context->GetIsolate();
13035 v8::HandleScope scope(isolate);
13037 // Parent template.
13038 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13039 Local<ObjectTemplate> parent_instance_templ =
13040 parent_templ->InstanceTemplate();
13041 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13043 // Template that inherits from the parent template.
13044 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13045 Local<ObjectTemplate> child_instance_templ =
13046 child_templ->InstanceTemplate();
13047 child_templ->Inherit(parent_templ);
13048 // Override 'f'. The child version of 'f' should get called for child
13050 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13051 // Add 'g' twice. The 'g' added last should get called for instances.
13052 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13053 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13055 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13056 // so 'h' can be shadowed on the instance object.
13057 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13058 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13059 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13061 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13062 // but the attribute does not have effect because it is duplicated with
13064 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13065 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13069 // Instantiate the child template.
13070 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13072 // Check that the child function overrides the parent one.
13073 context->Global()->Set(v8_str("o"), instance);
13074 Local<Value> value = v8_compile("o.f")->Run();
13075 // Check that the 'g' that was added last is hit.
13076 CHECK_EQ(42, value->Int32Value());
13077 value = v8_compile("o.g")->Run();
13078 CHECK_EQ(42, value->Int32Value());
13080 // Check that 'h' cannot be shadowed.
13081 value = v8_compile("o.h = 3; o.h")->Run();
13082 CHECK_EQ(1, value->Int32Value());
13084 // Check that 'i' cannot be shadowed or changed.
13085 value = v8_compile("o.i = 3; o.i")->Run();
13086 CHECK_EQ(42, value->Int32Value());
13090 static void IsConstructHandler(
13091 const v8::FunctionCallbackInfo<v8::Value>& args) {
13092 ApiTestFuzzer::Fuzz();
13093 args.GetReturnValue().Set(args.IsConstructCall());
13097 THREADED_TEST(IsConstructCall) {
13098 v8::Isolate* isolate = CcTest::isolate();
13099 v8::HandleScope scope(isolate);
13101 // Function template with call handler.
13102 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13103 templ->SetCallHandler(IsConstructHandler);
13105 LocalContext context;
13107 context->Global()->Set(v8_str("f"), templ->GetFunction());
13108 Local<Value> value = v8_compile("f()")->Run();
13109 CHECK(!value->BooleanValue());
13110 value = v8_compile("new f()")->Run();
13111 CHECK(value->BooleanValue());
13115 THREADED_TEST(ObjectProtoToString) {
13116 v8::Isolate* isolate = CcTest::isolate();
13117 v8::HandleScope scope(isolate);
13118 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13119 templ->SetClassName(v8_str("MyClass"));
13121 LocalContext context;
13123 Local<String> customized_tostring = v8_str("customized toString");
13125 // Replace Object.prototype.toString
13126 v8_compile("Object.prototype.toString = function() {"
13127 " return 'customized toString';"
13130 // Normal ToString call should call replaced Object.prototype.toString
13131 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13132 Local<String> value = instance->ToString();
13133 CHECK(value->IsString() && value->Equals(customized_tostring));
13135 // ObjectProtoToString should not call replace toString function.
13136 value = instance->ObjectProtoToString();
13137 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13140 value = context->Global()->ObjectProtoToString();
13141 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13143 // Check ordinary object
13144 Local<Value> object = v8_compile("new Object()")->Run();
13145 value = object.As<v8::Object>()->ObjectProtoToString();
13146 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13150 THREADED_TEST(ObjectGetConstructorName) {
13151 LocalContext context;
13152 v8::HandleScope scope(context->GetIsolate());
13153 v8_compile("function Parent() {};"
13154 "function Child() {};"
13155 "Child.prototype = new Parent();"
13156 "var outer = { inner: function() { } };"
13157 "var p = new Parent();"
13158 "var c = new Child();"
13159 "var x = new outer.inner();")->Run();
13161 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13162 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13163 v8_str("Parent")));
13165 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13166 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13169 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13170 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13171 v8_str("outer.inner")));
13175 bool ApiTestFuzzer::fuzzing_ = false;
13176 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13177 int ApiTestFuzzer::active_tests_;
13178 int ApiTestFuzzer::tests_being_run_;
13179 int ApiTestFuzzer::current_;
13182 // We are in a callback and want to switch to another thread (if we
13183 // are currently running the thread fuzzing test).
13184 void ApiTestFuzzer::Fuzz() {
13185 if (!fuzzing_) return;
13186 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13187 test->ContextSwitch();
13191 // Let the next thread go. Since it is also waiting on the V8 lock it may
13192 // not start immediately.
13193 bool ApiTestFuzzer::NextThread() {
13194 int test_position = GetNextTestNumber();
13195 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13196 if (test_position == current_) {
13198 printf("Stay with %s\n", test_name);
13201 if (kLogThreading) {
13202 printf("Switch from %s to %s\n",
13204 RegisterThreadedTest::nth(test_position)->name());
13206 current_ = test_position;
13207 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13212 void ApiTestFuzzer::Run() {
13213 // When it is our turn...
13216 // ... get the V8 lock and start running the test.
13217 v8::Locker locker(CcTest::isolate());
13220 // This test finished.
13223 // If it was the last then signal that fact.
13224 if (active_tests_ == 0) {
13225 all_tests_done_.Signal();
13227 // Otherwise select a new test and start that.
13233 static unsigned linear_congruential_generator;
13236 void ApiTestFuzzer::SetUp(PartOfTest part) {
13237 linear_congruential_generator = i::FLAG_testing_prng_seed;
13239 int count = RegisterThreadedTest::count();
13240 int start = count * part / (LAST_PART + 1);
13241 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13242 active_tests_ = tests_being_run_ = end - start + 1;
13243 for (int i = 0; i < tests_being_run_; i++) {
13244 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13246 for (int i = 0; i < active_tests_; i++) {
13247 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13252 static void CallTestNumber(int test_number) {
13253 (RegisterThreadedTest::nth(test_number)->callback())();
13257 void ApiTestFuzzer::RunAllTests() {
13258 // Set off the first test.
13261 // Wait till they are all done.
13262 all_tests_done_.Wait();
13266 int ApiTestFuzzer::GetNextTestNumber() {
13269 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13270 linear_congruential_generator *= 1664525u;
13271 linear_congruential_generator += 1013904223u;
13272 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13277 void ApiTestFuzzer::ContextSwitch() {
13278 // If the new thread is the same as the current thread there is nothing to do.
13279 if (NextThread()) {
13280 // Now it can start.
13281 v8::Unlocker unlocker(CcTest::isolate());
13282 // Wait till someone starts us again.
13289 void ApiTestFuzzer::TearDown() {
13291 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13292 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13293 if (fuzzer != NULL) fuzzer->Join();
13298 // Lets not be needlessly self-referential.
13300 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13301 ApiTestFuzzer::RunAllTests();
13302 ApiTestFuzzer::TearDown();
13307 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13308 ApiTestFuzzer::RunAllTests();
13309 ApiTestFuzzer::TearDown();
13314 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13315 ApiTestFuzzer::RunAllTests();
13316 ApiTestFuzzer::TearDown();
13321 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13322 ApiTestFuzzer::RunAllTests();
13323 ApiTestFuzzer::TearDown();
13327 void ApiTestFuzzer::CallTest() {
13328 v8::Isolate::Scope scope(CcTest::isolate());
13330 printf("Start test %d\n", test_number_);
13331 CallTestNumber(test_number_);
13333 printf("End test %d\n", test_number_);
13337 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13338 v8::Isolate* isolate = args.GetIsolate();
13339 CHECK(v8::Locker::IsLocked(isolate));
13340 ApiTestFuzzer::Fuzz();
13341 v8::Unlocker unlocker(isolate);
13342 const char* code = "throw 7;";
13344 v8::Locker nested_locker(isolate);
13345 v8::HandleScope scope(isolate);
13346 v8::Handle<Value> exception;
13347 { v8::TryCatch try_catch;
13348 v8::Handle<Value> value = CompileRun(code);
13349 CHECK(value.IsEmpty());
13350 CHECK(try_catch.HasCaught());
13351 // Make sure to wrap the exception in a new handle because
13352 // the handle returned from the TryCatch is destroyed
13353 // when the TryCatch is destroyed.
13354 exception = Local<Value>::New(isolate, try_catch.Exception());
13356 args.GetIsolate()->ThrowException(exception);
13361 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13362 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13363 ApiTestFuzzer::Fuzz();
13364 v8::Unlocker unlocker(CcTest::isolate());
13365 const char* code = "throw 7;";
13367 v8::Locker nested_locker(CcTest::isolate());
13368 v8::HandleScope scope(args.GetIsolate());
13369 v8::Handle<Value> value = CompileRun(code);
13370 CHECK(value.IsEmpty());
13371 args.GetReturnValue().Set(v8_str("foo"));
13376 // These are locking tests that don't need to be run again
13377 // as part of the locking aggregation tests.
13378 TEST(NestedLockers) {
13379 v8::Isolate* isolate = CcTest::isolate();
13380 v8::Locker locker(isolate);
13381 CHECK(v8::Locker::IsLocked(isolate));
13383 v8::HandleScope scope(env->GetIsolate());
13384 Local<v8::FunctionTemplate> fun_templ =
13385 v8::FunctionTemplate::New(isolate, ThrowInJS);
13386 Local<Function> fun = fun_templ->GetFunction();
13387 env->Global()->Set(v8_str("throw_in_js"), fun);
13388 Local<Script> script = v8_compile("(function () {"
13396 CHECK_EQ(91, script->Run()->Int32Value());
13400 // These are locking tests that don't need to be run again
13401 // as part of the locking aggregation tests.
13402 TEST(NestedLockersNoTryCatch) {
13403 v8::Locker locker(CcTest::isolate());
13405 v8::HandleScope scope(env->GetIsolate());
13406 Local<v8::FunctionTemplate> fun_templ =
13407 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13408 Local<Function> fun = fun_templ->GetFunction();
13409 env->Global()->Set(v8_str("throw_in_js"), fun);
13410 Local<Script> script = v8_compile("(function () {"
13418 CHECK_EQ(91, script->Run()->Int32Value());
13422 THREADED_TEST(RecursiveLocking) {
13423 v8::Locker locker(CcTest::isolate());
13425 v8::Locker locker2(CcTest::isolate());
13426 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13431 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13432 ApiTestFuzzer::Fuzz();
13433 v8::Unlocker unlocker(CcTest::isolate());
13437 THREADED_TEST(LockUnlockLock) {
13439 v8::Locker locker(CcTest::isolate());
13440 v8::HandleScope scope(CcTest::isolate());
13442 Local<v8::FunctionTemplate> fun_templ =
13443 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13444 Local<Function> fun = fun_templ->GetFunction();
13445 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13446 Local<Script> script = v8_compile("(function () {"
13447 " unlock_for_a_moment();"
13450 CHECK_EQ(42, script->Run()->Int32Value());
13453 v8::Locker locker(CcTest::isolate());
13454 v8::HandleScope scope(CcTest::isolate());
13456 Local<v8::FunctionTemplate> fun_templ =
13457 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13458 Local<Function> fun = fun_templ->GetFunction();
13459 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13460 Local<Script> script = v8_compile("(function () {"
13461 " unlock_for_a_moment();"
13464 CHECK_EQ(42, script->Run()->Int32Value());
13469 static int GetGlobalObjectsCount() {
13470 CcTest::heap()->EnsureHeapIsIterable();
13472 i::HeapIterator it(CcTest::heap());
13473 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13474 if (object->IsJSGlobalObject()) count++;
13479 static void CheckSurvivingGlobalObjectsCount(int expected) {
13480 // We need to collect all garbage twice to be sure that everything
13481 // has been collected. This is because inline caches are cleared in
13482 // the first garbage collection but some of the maps have already
13483 // been marked at that point. Therefore some of the maps are not
13484 // collected until the second garbage collection.
13485 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13486 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13487 int count = GetGlobalObjectsCount();
13489 if (count != expected) CcTest::heap()->TracePathToGlobal();
13491 CHECK_EQ(expected, count);
13495 TEST(DontLeakGlobalObjects) {
13496 // Regression test for issues 1139850 and 1174891.
13498 i::FLAG_expose_gc = true;
13499 v8::V8::Initialize();
13501 for (int i = 0; i < 5; i++) {
13502 { v8::HandleScope scope(CcTest::isolate());
13503 LocalContext context;
13505 v8::V8::ContextDisposedNotification();
13506 CheckSurvivingGlobalObjectsCount(0);
13508 { v8::HandleScope scope(CcTest::isolate());
13509 LocalContext context;
13510 v8_compile("Date")->Run();
13512 v8::V8::ContextDisposedNotification();
13513 CheckSurvivingGlobalObjectsCount(0);
13515 { v8::HandleScope scope(CcTest::isolate());
13516 LocalContext context;
13517 v8_compile("/aaa/")->Run();
13519 v8::V8::ContextDisposedNotification();
13520 CheckSurvivingGlobalObjectsCount(0);
13522 { v8::HandleScope scope(CcTest::isolate());
13523 const char* extension_list[] = { "v8/gc" };
13524 v8::ExtensionConfiguration extensions(1, extension_list);
13525 LocalContext context(&extensions);
13526 v8_compile("gc();")->Run();
13528 v8::V8::ContextDisposedNotification();
13529 CheckSurvivingGlobalObjectsCount(0);
13534 TEST(CopyablePersistent) {
13535 LocalContext context;
13536 v8::Isolate* isolate = context->GetIsolate();
13537 i::GlobalHandles* globals =
13538 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13539 int initial_handles = globals->global_handles_count();
13540 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13543 CopyableObject handle1;
13545 v8::HandleScope scope(isolate);
13546 handle1.Reset(isolate, v8::Object::New(isolate));
13548 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13549 CopyableObject handle2;
13551 CHECK(handle1 == handle2);
13552 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13553 CopyableObject handle3(handle2);
13554 CHECK(handle1 == handle3);
13555 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13557 // Verify autodispose
13558 CHECK_EQ(initial_handles, globals->global_handles_count());
13562 static void WeakApiCallback(
13563 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13564 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13565 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13566 data.GetParameter()->Reset();
13567 delete data.GetParameter();
13571 TEST(WeakCallbackApi) {
13572 LocalContext context;
13573 v8::Isolate* isolate = context->GetIsolate();
13574 i::GlobalHandles* globals =
13575 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13576 int initial_handles = globals->global_handles_count();
13578 v8::HandleScope scope(isolate);
13579 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13580 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13581 v8::Persistent<v8::Object>* handle =
13582 new v8::Persistent<v8::Object>(isolate, obj);
13583 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13586 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13587 CollectAllGarbage(i::Heap::kNoGCFlags);
13588 // Verify disposed.
13589 CHECK_EQ(initial_handles, globals->global_handles_count());
13593 v8::Persistent<v8::Object> some_object;
13594 v8::Persistent<v8::Object> bad_handle;
13596 void NewPersistentHandleCallback(
13597 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13598 v8::HandleScope scope(data.GetIsolate());
13599 bad_handle.Reset(data.GetIsolate(), some_object);
13600 data.GetParameter()->Reset();
13604 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13605 LocalContext context;
13606 v8::Isolate* isolate = context->GetIsolate();
13608 v8::Persistent<v8::Object> handle1, handle2;
13610 v8::HandleScope scope(isolate);
13611 some_object.Reset(isolate, v8::Object::New(isolate));
13612 handle1.Reset(isolate, v8::Object::New(isolate));
13613 handle2.Reset(isolate, v8::Object::New(isolate));
13615 // Note: order is implementation dependent alas: currently
13616 // global handle nodes are processed by PostGarbageCollectionProcessing
13617 // in reverse allocation order, so if second allocated handle is deleted,
13618 // weak callback of the first handle would be able to 'reallocate' it.
13619 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13621 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13625 v8::Persistent<v8::Object> to_be_disposed;
13627 void DisposeAndForceGcCallback(
13628 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13629 to_be_disposed.Reset();
13630 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13631 data.GetParameter()->Reset();
13635 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13636 LocalContext context;
13637 v8::Isolate* isolate = context->GetIsolate();
13639 v8::Persistent<v8::Object> handle1, handle2;
13641 v8::HandleScope scope(isolate);
13642 handle1.Reset(isolate, v8::Object::New(isolate));
13643 handle2.Reset(isolate, v8::Object::New(isolate));
13645 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13646 to_be_disposed.Reset(isolate, handle2);
13647 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13650 void DisposingCallback(
13651 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13652 data.GetParameter()->Reset();
13655 void HandleCreatingCallback(
13656 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13657 v8::HandleScope scope(data.GetIsolate());
13658 v8::Persistent<v8::Object>(data.GetIsolate(),
13659 v8::Object::New(data.GetIsolate()));
13660 data.GetParameter()->Reset();
13664 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13665 LocalContext context;
13666 v8::Isolate* isolate = context->GetIsolate();
13668 v8::Persistent<v8::Object> handle1, handle2, handle3;
13670 v8::HandleScope scope(isolate);
13671 handle3.Reset(isolate, v8::Object::New(isolate));
13672 handle2.Reset(isolate, v8::Object::New(isolate));
13673 handle1.Reset(isolate, v8::Object::New(isolate));
13675 handle2.SetWeak(&handle2, DisposingCallback);
13676 handle3.SetWeak(&handle3, HandleCreatingCallback);
13677 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13681 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13682 v8::V8::Initialize();
13685 const char* sources[nof] = {
13686 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13690 for (int i = 0; i < nof; i++) {
13691 const char* source = sources[i];
13692 { v8::HandleScope scope(CcTest::isolate());
13693 LocalContext context;
13694 CompileRun(source);
13696 { v8::HandleScope scope(CcTest::isolate());
13697 LocalContext context;
13698 CompileRun(source);
13704 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13705 v8::EscapableHandleScope inner(env->GetIsolate());
13707 v8::Local<Value> three = v8_num(3);
13708 v8::Local<Value> value = inner.Escape(three);
13714 THREADED_TEST(NestedHandleScopeAndContexts) {
13715 v8::Isolate* isolate = CcTest::isolate();
13716 v8::HandleScope outer(isolate);
13717 v8::Local<Context> env = Context::New(isolate);
13719 v8::Handle<Value> value = NestedScope(env);
13720 v8::Handle<String> str(value->ToString());
13721 CHECK(!str.IsEmpty());
13726 static bool MatchPointers(void* key1, void* key2) {
13727 return key1 == key2;
13731 struct SymbolInfo {
13738 class SetFunctionEntryHookTest {
13740 SetFunctionEntryHookTest() {
13741 CHECK(instance_ == NULL);
13744 ~SetFunctionEntryHookTest() {
13745 CHECK(instance_ == this);
13750 symbol_locations_.clear();
13751 invocations_.clear();
13754 void OnJitEvent(const v8::JitCodeEvent* event);
13755 static void JitEvent(const v8::JitCodeEvent* event) {
13756 CHECK(instance_ != NULL);
13757 instance_->OnJitEvent(event);
13760 void OnEntryHook(uintptr_t function,
13761 uintptr_t return_addr_location);
13762 static void EntryHook(uintptr_t function,
13763 uintptr_t return_addr_location) {
13764 CHECK(instance_ != NULL);
13765 instance_->OnEntryHook(function, return_addr_location);
13768 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13769 CHECK(instance_ != NULL);
13770 args.GetReturnValue().Set(v8_num(42));
13772 void RunLoopInNewEnv(v8::Isolate* isolate);
13774 // Records addr as location of symbol.
13775 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13777 // Finds the symbol containing addr
13778 SymbolInfo* FindSymbolForAddr(i::Address addr);
13779 // Returns the number of invocations where the caller name contains
13780 // \p caller_name and the function name contains \p function_name.
13781 int CountInvocations(const char* caller_name,
13782 const char* function_name);
13784 i::Handle<i::JSFunction> foo_func_;
13785 i::Handle<i::JSFunction> bar_func_;
13787 typedef std::map<size_t, SymbolInfo> SymbolMap;
13788 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13789 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13790 SymbolMap symbols_;
13791 SymbolLocationMap symbol_locations_;
13792 InvocationMap invocations_;
13794 static SetFunctionEntryHookTest* instance_;
13796 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13799 // Returns true if addr is in the range [start, start+len).
13800 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13801 if (start <= addr && start + len > addr)
13807 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13808 SymbolInfo* symbol) {
13809 // Insert the symbol at the new location.
13810 SymbolLocationMap::iterator it =
13811 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13812 // Now erase symbols to the left and right that overlap this one.
13813 while (it != symbol_locations_.begin()) {
13814 SymbolLocationMap::iterator left = it;
13816 if (!Overlaps(left->first, left->second->size, addr))
13818 symbol_locations_.erase(left);
13821 // Now erase symbols to the left and right that overlap this one.
13823 SymbolLocationMap::iterator right = it;
13825 if (right == symbol_locations_.end())
13827 if (!Overlaps(addr, symbol->size, right->first))
13829 symbol_locations_.erase(right);
13834 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13835 switch (event->type) {
13836 case v8::JitCodeEvent::CODE_ADDED: {
13837 CHECK(event->code_start != NULL);
13838 CHECK_NE(0, static_cast<int>(event->code_len));
13839 CHECK(event->name.str != NULL);
13840 size_t symbol_id = symbols_.size();
13842 // Record the new symbol.
13843 SymbolInfo& info = symbols_[symbol_id];
13844 info.id = symbol_id;
13845 info.size = event->code_len;
13846 info.name.assign(event->name.str, event->name.str + event->name.len);
13848 // And record it's location.
13849 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13853 case v8::JitCodeEvent::CODE_MOVED: {
13854 // We would like to never see code move that we haven't seen before,
13855 // but the code creation event does not happen until the line endings
13856 // have been calculated (this is so that we can report the line in the
13857 // script at which the function source is found, see
13858 // Compiler::RecordFunctionCompilation) and the line endings
13859 // calculations can cause a GC, which can move the newly created code
13860 // before its existence can be logged.
13861 SymbolLocationMap::iterator it(
13862 symbol_locations_.find(
13863 reinterpret_cast<i::Address>(event->code_start)));
13864 if (it != symbol_locations_.end()) {
13865 // Found a symbol at this location, move it.
13866 SymbolInfo* info = it->second;
13867 symbol_locations_.erase(it);
13868 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13877 void SetFunctionEntryHookTest::OnEntryHook(
13878 uintptr_t function, uintptr_t return_addr_location) {
13879 // Get the function's code object.
13880 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13881 reinterpret_cast<i::Address>(function));
13882 CHECK(function_code != NULL);
13884 // Then try and look up the caller's code object.
13885 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13887 // Count the invocation.
13888 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13889 SymbolInfo* function_symbol =
13890 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13891 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13893 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13894 // Check that we have a symbol for the "bar" function at the right location.
13895 SymbolLocationMap::iterator it(
13896 symbol_locations_.find(function_code->instruction_start()));
13897 CHECK(it != symbol_locations_.end());
13900 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13901 // Check that we have a symbol for "foo" at the right location.
13902 SymbolLocationMap::iterator it(
13903 symbol_locations_.find(function_code->instruction_start()));
13904 CHECK(it != symbol_locations_.end());
13909 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13910 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13911 // Do we have a direct hit on a symbol?
13912 if (it != symbol_locations_.end()) {
13913 if (it->first == addr)
13917 // If not a direct hit, it'll have to be the previous symbol.
13918 if (it == symbol_locations_.begin())
13922 size_t offs = addr - it->first;
13923 if (offs < it->second->size)
13930 int SetFunctionEntryHookTest::CountInvocations(
13931 const char* caller_name, const char* function_name) {
13932 InvocationMap::iterator it(invocations_.begin());
13933 int invocations = 0;
13934 for (; it != invocations_.end(); ++it) {
13935 SymbolInfo* caller = it->first.first;
13936 SymbolInfo* function = it->first.second;
13938 // Filter out non-matching functions.
13939 if (function_name != NULL) {
13940 if (function->name.find(function_name) == std::string::npos)
13944 // Filter out non-matching callers.
13945 if (caller_name != NULL) {
13946 if (caller == NULL)
13948 if (caller->name.find(caller_name) == std::string::npos)
13952 // It matches add the invocation count to the tally.
13953 invocations += it->second;
13956 return invocations;
13960 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13961 v8::HandleScope outer(isolate);
13962 v8::Local<Context> env = Context::New(isolate);
13965 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13966 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13967 env->Global()->Set(v8_str("obj"), t->NewInstance());
13969 const char* script =
13970 "function bar() {\n"
13972 " for (i = 0; i < 100; ++i)\n"
13976 "function foo(i) { return i * i; }\n"
13977 "// Invoke on the runtime function.\n"
13979 CompileRun(script);
13980 bar_func_ = i::Handle<i::JSFunction>::cast(
13981 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13982 ASSERT(!bar_func_.is_null());
13985 i::Handle<i::JSFunction>::cast(
13986 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13987 ASSERT(!foo_func_.is_null());
13989 v8::Handle<v8::Value> value = CompileRun("bar();");
13990 CHECK(value->IsNumber());
13991 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13993 // Test the optimized codegen path.
13994 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13996 CHECK(value->IsNumber());
13997 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14003 void SetFunctionEntryHookTest::RunTest() {
14004 // Work in a new isolate throughout.
14005 v8::Isolate* isolate = v8::Isolate::New();
14007 // Test setting the entry hook on the new isolate.
14008 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14010 // Replacing the hook, once set should fail.
14011 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14014 v8::Isolate::Scope scope(isolate);
14016 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14018 RunLoopInNewEnv(isolate);
14020 // Check the exepected invocation counts.
14021 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14022 CHECK_EQ(200, CountInvocations("bar", "foo"));
14023 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14025 // Verify that we have an entry hook on some specific stubs.
14026 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14027 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14028 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14030 isolate->Dispose();
14034 // Make sure a second isolate is unaffected by the previous entry hook.
14035 isolate = v8::Isolate::New();
14037 v8::Isolate::Scope scope(isolate);
14039 // Reset the entry count to zero and set the entry hook.
14040 RunLoopInNewEnv(isolate);
14042 // We should record no invocations in this isolate.
14043 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14045 // Since the isolate has been used, we shouldn't be able to set an entry
14047 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14049 isolate->Dispose();
14053 TEST(SetFunctionEntryHook) {
14054 // FunctionEntryHook does not work well with experimental natives.
14055 // Experimental natives are compiled during snapshot deserialization.
14056 // This test breaks because InstallGetter (function from snapshot that
14057 // only gets called from experimental natives) is compiled with entry hooks.
14058 i::FLAG_allow_natives_syntax = true;
14059 i::FLAG_use_inlining = false;
14061 SetFunctionEntryHookTest test;
14066 static i::HashMap* code_map = NULL;
14067 static i::HashMap* jitcode_line_info = NULL;
14068 static int saw_bar = 0;
14069 static int move_events = 0;
14072 static bool FunctionNameIs(const char* expected,
14073 const v8::JitCodeEvent* event) {
14074 // Log lines for functions are of the general form:
14075 // "LazyCompile:<type><function_name>", where the type is one of
14077 static const char kPreamble[] = "LazyCompile:";
14078 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14080 if (event->name.len < sizeof(kPreamble) - 1 ||
14081 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14085 const char* tail = event->name.str + kPreambleLen;
14086 size_t tail_len = event->name.len - kPreambleLen;
14087 size_t expected_len = strlen(expected);
14088 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14093 // Check for tails like 'bar :1'.
14094 if (tail_len > expected_len + 2 &&
14095 tail[expected_len] == ' ' &&
14096 tail[expected_len + 1] == ':' &&
14097 tail[expected_len + 2] &&
14098 !strncmp(tail, expected, expected_len)) {
14102 if (tail_len != expected_len)
14105 return strncmp(tail, expected, expected_len) == 0;
14109 static void event_handler(const v8::JitCodeEvent* event) {
14110 CHECK(event != NULL);
14111 CHECK(code_map != NULL);
14112 CHECK(jitcode_line_info != NULL);
14114 class DummyJitCodeLineInfo {
14117 switch (event->type) {
14118 case v8::JitCodeEvent::CODE_ADDED: {
14119 CHECK(event->code_start != NULL);
14120 CHECK_NE(0, static_cast<int>(event->code_len));
14121 CHECK(event->name.str != NULL);
14122 i::HashMap::Entry* entry =
14123 code_map->Lookup(event->code_start,
14124 i::ComputePointerHash(event->code_start),
14126 entry->value = reinterpret_cast<void*>(event->code_len);
14128 if (FunctionNameIs("bar", event)) {
14134 case v8::JitCodeEvent::CODE_MOVED: {
14135 uint32_t hash = i::ComputePointerHash(event->code_start);
14136 // We would like to never see code move that we haven't seen before,
14137 // but the code creation event does not happen until the line endings
14138 // have been calculated (this is so that we can report the line in the
14139 // script at which the function source is found, see
14140 // Compiler::RecordFunctionCompilation) and the line endings
14141 // calculations can cause a GC, which can move the newly created code
14142 // before its existence can be logged.
14143 i::HashMap::Entry* entry =
14144 code_map->Lookup(event->code_start, hash, false);
14145 if (entry != NULL) {
14148 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14149 code_map->Remove(event->code_start, hash);
14151 entry = code_map->Lookup(event->new_code_start,
14152 i::ComputePointerHash(event->new_code_start),
14154 CHECK(entry != NULL);
14155 entry->value = reinterpret_cast<void*>(event->code_len);
14160 case v8::JitCodeEvent::CODE_REMOVED:
14161 // Object/code removal events are currently not dispatched from the GC.
14165 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14166 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14167 // record it in jitcode_line_info.
14168 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14169 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14170 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14171 temp_event->user_data = line_info;
14172 i::HashMap::Entry* entry =
14173 jitcode_line_info->Lookup(line_info,
14174 i::ComputePointerHash(line_info),
14176 entry->value = reinterpret_cast<void*>(line_info);
14179 // For these two events, we will check whether the event->user_data
14180 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14181 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14182 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14183 CHECK(event->user_data != NULL);
14184 uint32_t hash = i::ComputePointerHash(event->user_data);
14185 i::HashMap::Entry* entry =
14186 jitcode_line_info->Lookup(event->user_data, hash, false);
14187 CHECK(entry != NULL);
14188 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14192 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14193 CHECK(event->user_data != NULL);
14194 uint32_t hash = i::ComputePointerHash(event->user_data);
14195 i::HashMap::Entry* entry =
14196 jitcode_line_info->Lookup(event->user_data, hash, false);
14197 CHECK(entry != NULL);
14202 // Impossible event.
14209 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14210 i::FLAG_stress_compaction = true;
14211 i::FLAG_incremental_marking = false;
14212 const char* script =
14215 " for (i = 0; i < 100; ++i)"
14219 "function foo(i) { return i * i; };"
14222 // Run this test in a new isolate to make sure we don't
14223 // have remnants of state from other code.
14224 v8::Isolate* isolate = v8::Isolate::New();
14226 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
14229 v8::HandleScope scope(isolate);
14230 i::HashMap code(MatchPointers);
14233 i::HashMap lineinfo(MatchPointers);
14234 jitcode_line_info = &lineinfo;
14239 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14241 // Generate new code objects sparsely distributed across several
14242 // different fragmented code-space pages.
14243 const int kIterations = 10;
14244 for (int i = 0; i < kIterations; ++i) {
14245 LocalContext env(isolate);
14246 i::AlwaysAllocateScope always_allocate;
14247 SimulateFullSpace(heap->code_space());
14248 CompileRun(script);
14250 // Keep a strong reference to the code object in the handle scope.
14251 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14252 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14253 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14254 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14256 // Clear the compilation cache to get more wastage.
14257 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14260 // Force code movement.
14261 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14263 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14265 CHECK_LE(kIterations, saw_bar);
14266 CHECK_LT(0, move_events);
14269 jitcode_line_info = NULL;
14273 isolate->Dispose();
14275 // Do this in a new isolate.
14276 isolate = v8::Isolate::New();
14279 // Verify that we get callbacks for existing code objects when we
14280 // request enumeration of existing code.
14282 v8::HandleScope scope(isolate);
14283 LocalContext env(isolate);
14284 CompileRun(script);
14286 // Now get code through initial iteration.
14287 i::HashMap code(MatchPointers);
14290 i::HashMap lineinfo(MatchPointers);
14291 jitcode_line_info = &lineinfo;
14293 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14294 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14296 jitcode_line_info = NULL;
14297 // We expect that we got some events. Note that if we could get code removal
14298 // notifications, we could compare two collections, one created by listening
14299 // from the time of creation of an isolate, and the other by subscribing
14300 // with EnumExisting.
14301 CHECK_LT(0, code.occupancy());
14307 isolate->Dispose();
14311 THREADED_TEST(ExternalAllocatedMemory) {
14312 v8::Isolate* isolate = CcTest::isolate();
14313 v8::HandleScope outer(isolate);
14314 v8::Local<Context> env(Context::New(isolate));
14315 CHECK(!env.IsEmpty());
14316 const int64_t kSize = 1024*1024;
14317 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14318 CHECK_EQ(baseline + kSize,
14319 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14321 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14325 // Regression test for issue 54, object templates with internal fields
14326 // but no accessors or interceptors did not get their internal field
14327 // count set on instances.
14328 THREADED_TEST(Regress54) {
14329 LocalContext context;
14330 v8::Isolate* isolate = context->GetIsolate();
14331 v8::HandleScope outer(isolate);
14332 static v8::Persistent<v8::ObjectTemplate> templ;
14333 if (templ.IsEmpty()) {
14334 v8::EscapableHandleScope inner(isolate);
14335 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14336 local->SetInternalFieldCount(1);
14337 templ.Reset(isolate, inner.Escape(local));
14339 v8::Handle<v8::Object> result =
14340 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14341 CHECK_EQ(1, result->InternalFieldCount());
14345 // If part of the threaded tests, this test makes ThreadingTest fail
14347 TEST(CatchStackOverflow) {
14348 LocalContext context;
14349 v8::HandleScope scope(context->GetIsolate());
14350 v8::TryCatch try_catch;
14351 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8(
14352 context->GetIsolate(),
14358 v8::Handle<v8::Value> result = script->Run();
14359 CHECK(result.IsEmpty());
14363 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14364 const char* resource_name,
14366 v8::HandleScope scope(CcTest::isolate());
14367 v8::TryCatch try_catch;
14368 v8::Handle<v8::Value> result = script->Run();
14369 CHECK(result.IsEmpty());
14370 CHECK(try_catch.HasCaught());
14371 v8::Handle<v8::Message> message = try_catch.Message();
14372 CHECK(!message.IsEmpty());
14373 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14374 CHECK_EQ(91, message->GetStartPosition());
14375 CHECK_EQ(92, message->GetEndPosition());
14376 CHECK_EQ(2, message->GetStartColumn());
14377 CHECK_EQ(3, message->GetEndColumn());
14378 v8::String::Utf8Value line(message->GetSourceLine());
14379 CHECK_EQ(" throw 'nirk';", *line);
14380 v8::String::Utf8Value name(message->GetScriptResourceName());
14381 CHECK_EQ(resource_name, *name);
14385 THREADED_TEST(TryCatchSourceInfo) {
14386 LocalContext context;
14387 v8::HandleScope scope(context->GetIsolate());
14388 v8::Handle<v8::String> source = v8::String::NewFromUtf8(
14389 context->GetIsolate(),
14390 "function Foo() {\n"
14394 "function Bar() {\n"
14398 "function Baz() {\n"
14404 const char* resource_name;
14405 v8::Handle<v8::Script> script;
14406 resource_name = "test.js";
14407 script = v8::Script::Compile(
14408 source, v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14409 CheckTryCatchSourceInfo(script, resource_name, 0);
14411 resource_name = "test1.js";
14412 v8::ScriptOrigin origin1(
14413 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14414 script = v8::Script::Compile(source, &origin1);
14415 CheckTryCatchSourceInfo(script, resource_name, 0);
14417 resource_name = "test2.js";
14418 v8::ScriptOrigin origin2(
14419 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14420 v8::Integer::New(context->GetIsolate(), 7));
14421 script = v8::Script::Compile(source, &origin2);
14422 CheckTryCatchSourceInfo(script, resource_name, 7);
14426 THREADED_TEST(CompilationCache) {
14427 LocalContext context;
14428 v8::HandleScope scope(context->GetIsolate());
14429 v8::Handle<v8::String> source0 =
14430 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14431 v8::Handle<v8::String> source1 =
14432 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14433 v8::Handle<v8::Script> script0 = v8::Script::Compile(
14434 source0, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14435 v8::Handle<v8::Script> script1 = v8::Script::Compile(
14436 source1, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14437 v8::Handle<v8::Script> script2 =
14438 v8::Script::Compile(source0); // different origin
14439 CHECK_EQ(1234, script0->Run()->Int32Value());
14440 CHECK_EQ(1234, script1->Run()->Int32Value());
14441 CHECK_EQ(1234, script2->Run()->Int32Value());
14445 static void FunctionNameCallback(
14446 const v8::FunctionCallbackInfo<v8::Value>& args) {
14447 ApiTestFuzzer::Fuzz();
14448 args.GetReturnValue().Set(v8_num(42));
14452 THREADED_TEST(CallbackFunctionName) {
14453 LocalContext context;
14454 v8::Isolate* isolate = context->GetIsolate();
14455 v8::HandleScope scope(isolate);
14456 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14457 t->Set(v8_str("asdf"),
14458 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14459 context->Global()->Set(v8_str("obj"), t->NewInstance());
14460 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14461 CHECK(value->IsString());
14462 v8::String::Utf8Value name(value);
14463 CHECK_EQ("asdf", *name);
14467 THREADED_TEST(DateAccess) {
14468 LocalContext context;
14469 v8::HandleScope scope(context->GetIsolate());
14470 v8::Handle<v8::Value> date =
14471 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14472 CHECK(date->IsDate());
14473 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14477 void CheckProperties(v8::Isolate* isolate,
14478 v8::Handle<v8::Value> val,
14480 const char* elmv[]) {
14481 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14482 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14483 CHECK_EQ(elmc, props->Length());
14484 for (int i = 0; i < elmc; i++) {
14485 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14486 CHECK_EQ(elmv[i], *elm);
14491 void CheckOwnProperties(v8::Isolate* isolate,
14492 v8::Handle<v8::Value> val,
14494 const char* elmv[]) {
14495 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14496 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14497 CHECK_EQ(elmc, props->Length());
14498 for (int i = 0; i < elmc; i++) {
14499 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14500 CHECK_EQ(elmv[i], *elm);
14505 THREADED_TEST(PropertyEnumeration) {
14506 LocalContext context;
14507 v8::Isolate* isolate = context->GetIsolate();
14508 v8::HandleScope scope(isolate);
14509 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14510 context->GetIsolate(),
14513 "result[1] = {a: 1, b: 2};"
14514 "result[2] = [1, 2, 3];"
14515 "var proto = {x: 1, y: 2, z: 3};"
14516 "var x = { __proto__: proto, w: 0, z: 1 };"
14518 "result;"))->Run();
14519 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14520 CHECK_EQ(4, elms->Length());
14522 const char** elmv0 = NULL;
14524 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14525 CheckOwnProperties(
14526 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14528 const char* elmv1[] = {"a", "b"};
14530 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14531 CheckOwnProperties(
14532 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14534 const char* elmv2[] = {"0", "1", "2"};
14536 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14537 CheckOwnProperties(
14538 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14540 const char* elmv3[] = {"w", "z", "x", "y"};
14542 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14544 const char* elmv4[] = {"w", "z"};
14545 CheckOwnProperties(
14546 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14550 THREADED_TEST(PropertyEnumeration2) {
14551 LocalContext context;
14552 v8::Isolate* isolate = context->GetIsolate();
14553 v8::HandleScope scope(isolate);
14554 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14555 context->GetIsolate(),
14558 "result[1] = {a: 1, b: 2};"
14559 "result[2] = [1, 2, 3];"
14560 "var proto = {x: 1, y: 2, z: 3};"
14561 "var x = { __proto__: proto, w: 0, z: 1 };"
14563 "result;"))->Run();
14564 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14565 CHECK_EQ(4, elms->Length());
14567 const char** elmv0 = NULL;
14568 CheckProperties(isolate,
14569 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14571 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14572 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14573 CHECK_EQ(0, props->Length());
14574 for (uint32_t i = 0; i < props->Length(); i++) {
14575 printf("p[%d]\n", i);
14579 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14581 v8::AccessType type,
14582 Local<Value> data) {
14583 return type != v8::ACCESS_SET;
14587 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14589 v8::AccessType type,
14590 Local<Value> data) {
14591 return type != v8::ACCESS_SET;
14595 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14596 LocalContext context;
14597 v8::Isolate* isolate = context->GetIsolate();
14598 v8::HandleScope scope(isolate);
14599 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14600 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14601 IndexedSetAccessBlocker);
14602 templ->Set(v8_str("x"), v8::True(isolate));
14603 Local<v8::Object> instance = templ->NewInstance();
14604 context->Global()->Set(v8_str("obj"), instance);
14605 Local<Value> value = CompileRun("obj.x");
14606 CHECK(value->BooleanValue());
14610 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14612 v8::AccessType type,
14613 Local<Value> data) {
14618 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14620 v8::AccessType type,
14621 Local<Value> data) {
14627 THREADED_TEST(AccessChecksReenabledCorrectly) {
14628 LocalContext context;
14629 v8::Isolate* isolate = context->GetIsolate();
14630 v8::HandleScope scope(isolate);
14631 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14632 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14633 IndexedGetAccessBlocker);
14634 templ->Set(v8_str("a"), v8_str("a"));
14635 // Add more than 8 (see kMaxFastProperties) properties
14636 // so that the constructor will force copying map.
14637 // Cannot sprintf, gcc complains unsafety.
14639 for (char i = '0'; i <= '9' ; i++) {
14641 for (char j = '0'; j <= '9'; j++) {
14643 for (char k = '0'; k <= '9'; k++) {
14646 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14651 Local<v8::Object> instance_1 = templ->NewInstance();
14652 context->Global()->Set(v8_str("obj_1"), instance_1);
14654 Local<Value> value_1 = CompileRun("obj_1.a");
14655 CHECK(value_1->IsUndefined());
14657 Local<v8::Object> instance_2 = templ->NewInstance();
14658 context->Global()->Set(v8_str("obj_2"), instance_2);
14660 Local<Value> value_2 = CompileRun("obj_2.a");
14661 CHECK(value_2->IsUndefined());
14665 // This tests that access check information remains on the global
14666 // object template when creating contexts.
14667 THREADED_TEST(AccessControlRepeatedContextCreation) {
14668 v8::Isolate* isolate = CcTest::isolate();
14669 v8::HandleScope handle_scope(isolate);
14670 v8::Handle<v8::ObjectTemplate> global_template =
14671 v8::ObjectTemplate::New(isolate);
14672 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14673 IndexedSetAccessBlocker);
14674 i::Handle<i::ObjectTemplateInfo> internal_template =
14675 v8::Utils::OpenHandle(*global_template);
14676 CHECK(!internal_template->constructor()->IsUndefined());
14677 i::Handle<i::FunctionTemplateInfo> constructor(
14678 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14679 CHECK(!constructor->access_check_info()->IsUndefined());
14680 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14681 CHECK(!context0.IsEmpty());
14682 CHECK(!constructor->access_check_info()->IsUndefined());
14686 THREADED_TEST(TurnOnAccessCheck) {
14687 v8::Isolate* isolate = CcTest::isolate();
14688 v8::HandleScope handle_scope(isolate);
14690 // Create an environment with access check to the global object disabled by
14692 v8::Handle<v8::ObjectTemplate> global_template =
14693 v8::ObjectTemplate::New(isolate);
14694 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14695 IndexedGetAccessBlocker,
14696 v8::Handle<v8::Value>(),
14698 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14699 Context::Scope context_scope(context);
14701 // Set up a property and a number of functions.
14702 context->Global()->Set(v8_str("a"), v8_num(1));
14703 CompileRun("function f1() {return a;}"
14704 "function f2() {return a;}"
14705 "function g1() {return h();}"
14706 "function g2() {return h();}"
14707 "function h() {return 1;}");
14708 Local<Function> f1 =
14709 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14710 Local<Function> f2 =
14711 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14712 Local<Function> g1 =
14713 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14714 Local<Function> g2 =
14715 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14716 Local<Function> h =
14717 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14719 // Get the global object.
14720 v8::Handle<v8::Object> global = context->Global();
14722 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14723 // uses the runtime system to retreive property a whereas f2 uses global load
14725 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14726 for (int i = 0; i < 4; i++) {
14727 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14730 // Same for g1 and g2.
14731 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14732 for (int i = 0; i < 4; i++) {
14733 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14736 // Detach the global and turn on access check.
14737 Local<Object> hidden_global = Local<Object>::Cast(
14738 context->Global()->GetPrototype());
14739 context->DetachGlobal();
14740 hidden_global->TurnOnAccessCheck();
14742 // Failing access check to property get results in undefined.
14743 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14744 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14746 // Failing access check to function call results in exception.
14747 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14748 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14750 // No failing access check when just returning a constant.
14751 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14755 static const char* kPropertyA = "a";
14756 static const char* kPropertyH = "h";
14758 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14760 v8::AccessType type,
14761 Local<Value> data) {
14762 if (!name->IsString()) return false;
14763 i::Handle<i::String> name_handle =
14764 v8::Utils::OpenHandle(String::Cast(*name));
14765 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14766 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14770 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14771 v8::Isolate* isolate = CcTest::isolate();
14772 v8::HandleScope handle_scope(isolate);
14774 // Create an environment with access check to the global object disabled by
14775 // default. When the registered access checker will block access to properties
14777 v8::Handle<v8::ObjectTemplate> global_template =
14778 v8::ObjectTemplate::New(isolate);
14779 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14780 IndexedGetAccessBlocker,
14781 v8::Handle<v8::Value>(),
14783 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14784 Context::Scope context_scope(context);
14786 // Set up a property and a number of functions.
14787 context->Global()->Set(v8_str("a"), v8_num(1));
14788 static const char* source = "function f1() {return a;}"
14789 "function f2() {return a;}"
14790 "function g1() {return h();}"
14791 "function g2() {return h();}"
14792 "function h() {return 1;}";
14794 CompileRun(source);
14795 Local<Function> f1;
14796 Local<Function> f2;
14797 Local<Function> g1;
14798 Local<Function> g2;
14800 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14801 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14802 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14803 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14804 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14806 // Get the global object.
14807 v8::Handle<v8::Object> global = context->Global();
14809 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14810 // uses the runtime system to retreive property a whereas f2 uses global load
14812 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14813 for (int i = 0; i < 4; i++) {
14814 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14817 // Same for g1 and g2.
14818 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14819 for (int i = 0; i < 4; i++) {
14820 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14823 // Detach the global and turn on access check now blocking access to property
14824 // a and function h.
14825 Local<Object> hidden_global = Local<Object>::Cast(
14826 context->Global()->GetPrototype());
14827 context->DetachGlobal();
14828 hidden_global->TurnOnAccessCheck();
14830 // Failing access check to property get results in undefined.
14831 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14832 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14834 // Failing access check to function call results in exception.
14835 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14836 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14838 // No failing access check when just returning a constant.
14839 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14841 // Now compile the source again. And get the newly compiled functions, except
14842 // for h for which access is blocked.
14843 CompileRun(source);
14844 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14845 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14846 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14847 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14848 CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14850 // Failing access check to property get results in undefined.
14851 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14852 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14854 // Failing access check to function call results in exception.
14855 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14856 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14860 // This test verifies that pre-compilation (aka preparsing) can be called
14861 // without initializing the whole VM. Thus we cannot run this test in a
14862 // multi-threaded setup.
14864 // TODO(155): This test would break without the initialization of V8. This is
14865 // a workaround for now to make this test not fail.
14866 v8::V8::Initialize();
14867 v8::Isolate* isolate = CcTest::isolate();
14868 HandleScope handle_scope(isolate);
14869 const char* script = "function foo(a) { return a+1; }";
14870 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14871 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14872 CHECK_NE(sd->Length(), 0);
14873 CHECK_NE(sd->Data(), NULL);
14874 CHECK(!sd->HasError());
14879 TEST(PreCompileWithError) {
14880 v8::V8::Initialize();
14881 v8::Isolate* isolate = CcTest::isolate();
14882 HandleScope handle_scope(isolate);
14883 const char* script = "function foo(a) { return 1 * * 2; }";
14884 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14885 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14886 CHECK(sd->HasError());
14891 TEST(Regress31661) {
14892 v8::V8::Initialize();
14893 v8::Isolate* isolate = CcTest::isolate();
14894 HandleScope handle_scope(isolate);
14895 const char* script = " The Definintive Guide";
14896 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14897 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14898 CHECK(sd->HasError());
14903 // Tests that ScriptData can be serialized and deserialized.
14904 TEST(PreCompileSerialization) {
14905 v8::V8::Initialize();
14906 v8::Isolate* isolate = CcTest::isolate();
14907 HandleScope handle_scope(isolate);
14908 const char* script = "function foo(a) { return a+1; }";
14909 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14910 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14913 int serialized_data_length = sd->Length();
14914 char* serialized_data = i::NewArray<char>(serialized_data_length);
14915 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14918 v8::ScriptData* deserialized_sd =
14919 v8::ScriptData::New(serialized_data, serialized_data_length);
14921 // Verify that the original is the same as the deserialized.
14922 CHECK_EQ(sd->Length(), deserialized_sd->Length());
14923 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14924 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14927 delete deserialized_sd;
14931 // Attempts to deserialize bad data.
14932 TEST(PreCompileDeserializationError) {
14933 v8::V8::Initialize();
14934 const char* data = "DONT CARE";
14935 int invalid_size = 3;
14936 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14938 CHECK_EQ(0, sd->Length());
14944 // Attempts to deserialize bad data.
14945 TEST(PreCompileInvalidPreparseDataError) {
14946 v8::V8::Initialize();
14947 v8::Isolate* isolate = CcTest::isolate();
14948 LocalContext context;
14949 v8::HandleScope scope(context->GetIsolate());
14951 const char* script = "function foo(){ return 5;}\n"
14952 "function bar(){ return 6 + 7;} foo();";
14953 v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14954 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14955 CHECK(!sd->HasError());
14956 // ScriptDataImpl private implementation details
14957 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14958 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14959 const int kFunctionEntryStartOffset = 0;
14960 const int kFunctionEntryEndOffset = 1;
14961 unsigned* sd_data =
14962 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14964 // Overwrite function bar's end position with 0.
14965 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14966 v8::TryCatch try_catch;
14968 Local<String> source = String::NewFromUtf8(isolate, script);
14969 Local<Script> compiled_script = Script::New(source, NULL, sd);
14970 CHECK(try_catch.HasCaught());
14971 String::Utf8Value exception_value(try_catch.Message()->Get());
14972 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14977 // Overwrite function bar's start position with 200. The function entry
14978 // will not be found when searching for it by position and we should fall
14979 // back on eager compilation.
14980 sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14981 isolate, script, v8::String::kNormalString, i::StrLength(script)));
14982 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14983 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14985 compiled_script = Script::New(source, NULL, sd);
14986 CHECK(!try_catch.HasCaught());
14992 // This tests that we do not allow dictionary load/call inline caches
14993 // to use functions that have not yet been compiled. The potential
14994 // problem of loading a function that has not yet been compiled can
14995 // arise because we share code between contexts via the compilation
14997 THREADED_TEST(DictionaryICLoadedFunction) {
14998 v8::HandleScope scope(CcTest::isolate());
15000 for (int i = 0; i < 2; i++) {
15001 LocalContext context;
15002 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15003 context->Global()->Delete(v8_str("tmp"));
15004 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15007 for (int i = 0; i < 2; i++) {
15008 LocalContext context;
15009 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15010 context->Global()->Delete(v8_str("tmp"));
15011 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15016 // Test that cross-context new calls use the context of the callee to
15017 // create the new JavaScript object.
15018 THREADED_TEST(CrossContextNew) {
15019 v8::Isolate* isolate = CcTest::isolate();
15020 v8::HandleScope scope(isolate);
15021 v8::Local<Context> context0 = Context::New(isolate);
15022 v8::Local<Context> context1 = Context::New(isolate);
15024 // Allow cross-domain access.
15025 Local<String> token = v8_str("<security token>");
15026 context0->SetSecurityToken(token);
15027 context1->SetSecurityToken(token);
15029 // Set an 'x' property on the Object prototype and define a
15030 // constructor function in context0.
15032 CompileRun("Object.prototype.x = 42; function C() {};");
15035 // Call the constructor function from context0 and check that the
15036 // result has the 'x' property.
15038 context1->Global()->Set(v8_str("other"), context0->Global());
15039 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15040 CHECK(value->IsInt32());
15041 CHECK_EQ(42, value->Int32Value());
15046 // Verify that we can clone an object
15047 TEST(ObjectClone) {
15049 v8::Isolate* isolate = env->GetIsolate();
15050 v8::HandleScope scope(isolate);
15052 const char* sample =
15054 "rv.alpha = 'hello';" \
15058 // Create an object, verify basics.
15059 Local<Value> val = CompileRun(sample);
15060 CHECK(val->IsObject());
15061 Local<v8::Object> obj = val.As<v8::Object>();
15062 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15064 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15065 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15066 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15069 Local<v8::Object> clone = obj->Clone();
15070 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15071 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15072 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15074 // Set a property on the clone, verify each object.
15075 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15076 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15077 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15081 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15083 explicit AsciiVectorResource(i::Vector<const char> vector)
15085 virtual ~AsciiVectorResource() {}
15086 virtual size_t length() const { return data_.length(); }
15087 virtual const char* data() const { return data_.start(); }
15089 i::Vector<const char> data_;
15093 class UC16VectorResource : public v8::String::ExternalStringResource {
15095 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15097 virtual ~UC16VectorResource() {}
15098 virtual size_t length() const { return data_.length(); }
15099 virtual const i::uc16* data() const { return data_.start(); }
15101 i::Vector<const i::uc16> data_;
15105 static void MorphAString(i::String* string,
15106 AsciiVectorResource* ascii_resource,
15107 UC16VectorResource* uc16_resource) {
15108 CHECK(i::StringShape(string).IsExternal());
15109 if (string->IsOneByteRepresentation()) {
15110 // Check old map is not internalized or long.
15111 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15112 // Morph external string to be TwoByte string.
15113 string->set_map(CcTest::heap()->external_string_map());
15114 i::ExternalTwoByteString* morphed =
15115 i::ExternalTwoByteString::cast(string);
15116 morphed->set_resource(uc16_resource);
15118 // Check old map is not internalized or long.
15119 CHECK(string->map() == CcTest::heap()->external_string_map());
15120 // Morph external string to be ASCII string.
15121 string->set_map(CcTest::heap()->external_ascii_string_map());
15122 i::ExternalAsciiString* morphed =
15123 i::ExternalAsciiString::cast(string);
15124 morphed->set_resource(ascii_resource);
15129 // Test that we can still flatten a string if the components it is built up
15130 // from have been turned into 16 bit strings in the mean time.
15131 THREADED_TEST(MorphCompositeStringTest) {
15132 char utf_buffer[129];
15133 const char* c_string = "Now is the time for all good men"
15134 " to come to the aid of the party";
15135 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15138 i::Factory* factory = CcTest::i_isolate()->factory();
15139 v8::HandleScope scope(env->GetIsolate());
15140 AsciiVectorResource ascii_resource(
15141 i::Vector<const char>(c_string, i::StrLength(c_string)));
15142 UC16VectorResource uc16_resource(
15143 i::Vector<const uint16_t>(two_byte_string,
15144 i::StrLength(c_string)));
15146 Local<String> lhs(v8::Utils::ToLocal(
15147 factory->NewExternalStringFromAscii(&ascii_resource)));
15148 Local<String> rhs(v8::Utils::ToLocal(
15149 factory->NewExternalStringFromAscii(&ascii_resource)));
15151 env->Global()->Set(v8_str("lhs"), lhs);
15152 env->Global()->Set(v8_str("rhs"), rhs);
15155 "var cons = lhs + rhs;"
15156 "var slice = lhs.substring(1, lhs.length - 1);"
15157 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15159 CHECK(lhs->IsOneByte());
15160 CHECK(rhs->IsOneByte());
15162 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15163 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15165 // This should UTF-8 without flattening, since everything is ASCII.
15166 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15167 CHECK_EQ(128, cons->Utf8Length());
15169 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15170 CHECK_EQ(128, nchars);
15171 CHECK_EQ(0, strcmp(
15173 "Now is the time for all good men to come to the aid of the party"
15174 "Now is the time for all good men to come to the aid of the party"));
15176 // Now do some stuff to make sure the strings are flattened, etc.
15178 "/[^a-z]/.test(cons);"
15179 "/[^a-z]/.test(slice);"
15180 "/[^a-z]/.test(slice_on_cons);");
15181 const char* expected_cons =
15182 "Now is the time for all good men to come to the aid of the party"
15183 "Now is the time for all good men to come to the aid of the party";
15184 const char* expected_slice =
15185 "ow is the time for all good men to come to the aid of the part";
15186 const char* expected_slice_on_cons =
15187 "ow is the time for all good men to come to the aid of the party"
15188 "Now is the time for all good men to come to the aid of the part";
15189 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15190 env->Global()->Get(v8_str("cons")));
15191 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15192 env->Global()->Get(v8_str("slice")));
15193 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15194 env->Global()->Get(v8_str("slice_on_cons")));
15196 i::DeleteArray(two_byte_string);
15200 TEST(CompileExternalTwoByteSource) {
15201 LocalContext context;
15202 v8::HandleScope scope(context->GetIsolate());
15204 // This is a very short list of sources, which currently is to check for a
15205 // regression caused by r2703.
15206 const char* ascii_sources[] = {
15208 "-0.5", // This mainly testes PushBack in the Scanner.
15209 "--0.5", // This mainly testes PushBack in the Scanner.
15213 // Compile the sources as external two byte strings.
15214 for (int i = 0; ascii_sources[i] != NULL; i++) {
15215 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15216 UC16VectorResource uc16_resource(
15217 i::Vector<const uint16_t>(two_byte_string,
15218 i::StrLength(ascii_sources[i])));
15219 v8::Local<v8::String> source =
15220 v8::String::NewExternal(context->GetIsolate(), &uc16_resource);
15221 v8::Script::Compile(source);
15222 i::DeleteArray(two_byte_string);
15227 #ifndef V8_INTERPRETED_REGEXP
15229 struct RegExpInterruptionData {
15231 UC16VectorResource* string_resource;
15232 v8::Persistent<v8::String> string;
15233 } regexp_interruption_data;
15236 class RegExpInterruptionThread : public i::Thread {
15238 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15239 : Thread("TimeoutThread"), isolate_(isolate) {}
15241 virtual void Run() {
15242 for (regexp_interruption_data.loop_count = 0;
15243 regexp_interruption_data.loop_count < 7;
15244 regexp_interruption_data.loop_count++) {
15245 i::OS::Sleep(50); // Wait a bit before requesting GC.
15246 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15248 i::OS::Sleep(50); // Wait a bit before terminating.
15249 v8::V8::TerminateExecution(isolate_);
15253 v8::Isolate* isolate_;
15257 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15258 if (regexp_interruption_data.loop_count != 2) return;
15259 v8::HandleScope scope(CcTest::isolate());
15260 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15261 CcTest::isolate(), regexp_interruption_data.string);
15262 string->MakeExternal(regexp_interruption_data.string_resource);
15266 // Test that RegExp execution can be interrupted. Specifically, we test
15267 // * interrupting with GC
15268 // * turn the subject string from one-byte internal to two-byte external string
15269 // * force termination
15270 TEST(RegExpInterruption) {
15271 v8::HandleScope scope(CcTest::isolate());
15274 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15276 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15277 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15278 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15279 v8::Local<v8::String> string = v8_str(ascii_content);
15281 CcTest::global()->Set(v8_str("a"), string);
15282 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15283 regexp_interruption_data.string_resource = new UC16VectorResource(
15284 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15286 v8::TryCatch try_catch;
15287 timeout_thread.Start();
15289 CompileRun("/((a*)*)*b/.exec(a)");
15290 CHECK(try_catch.HasTerminated());
15292 timeout_thread.Join();
15294 delete regexp_interruption_data.string_resource;
15295 regexp_interruption_data.string.Reset();
15298 #endif // V8_INTERPRETED_REGEXP
15301 // Test that we cannot set a property on the global object if there
15302 // is a read-only property in the prototype chain.
15303 TEST(ReadOnlyPropertyInGlobalProto) {
15304 i::FLAG_es5_readonly = true;
15305 v8::Isolate* isolate = CcTest::isolate();
15306 v8::HandleScope scope(isolate);
15307 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15308 LocalContext context(0, templ);
15309 v8::Handle<v8::Object> global = context->Global();
15310 v8::Handle<v8::Object> global_proto =
15311 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15312 global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15313 global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15314 // Check without 'eval' or 'with'.
15315 v8::Handle<v8::Value> res =
15316 CompileRun("function f() { x = 42; return x; }; f()");
15317 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15318 // Check with 'eval'.
15319 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15320 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15321 // Check with 'with'.
15322 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15323 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15326 static int force_set_set_count = 0;
15327 static int force_set_get_count = 0;
15328 bool pass_on_get = false;
15330 static void ForceSetGetter(v8::Local<v8::String> name,
15331 const v8::PropertyCallbackInfo<v8::Value>& info) {
15332 force_set_get_count++;
15336 info.GetReturnValue().Set(3);
15339 static void ForceSetSetter(v8::Local<v8::String> name,
15340 v8::Local<v8::Value> value,
15341 const v8::PropertyCallbackInfo<void>& info) {
15342 force_set_set_count++;
15345 static void ForceSetInterceptSetter(
15346 v8::Local<v8::String> name,
15347 v8::Local<v8::Value> value,
15348 const v8::PropertyCallbackInfo<v8::Value>& info) {
15349 force_set_set_count++;
15350 info.GetReturnValue().SetUndefined();
15355 force_set_get_count = 0;
15356 force_set_set_count = 0;
15357 pass_on_get = false;
15359 v8::Isolate* isolate = CcTest::isolate();
15360 v8::HandleScope scope(isolate);
15361 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15362 v8::Handle<v8::String> access_property =
15363 v8::String::NewFromUtf8(isolate, "a");
15364 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15365 LocalContext context(NULL, templ);
15366 v8::Handle<v8::Object> global = context->Global();
15368 // Ordinary properties
15369 v8::Handle<v8::String> simple_property =
15370 v8::String::NewFromUtf8(isolate, "p");
15371 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15372 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15373 // This should fail because the property is read-only
15374 global->Set(simple_property, v8::Int32::New(isolate, 5));
15375 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15376 // This should succeed even though the property is read-only
15377 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15378 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15381 CHECK_EQ(0, force_set_set_count);
15382 CHECK_EQ(0, force_set_get_count);
15383 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15384 // CHECK_EQ the property shouldn't override it, just call the setter
15385 // which in this case does nothing.
15386 global->Set(access_property, v8::Int32::New(isolate, 7));
15387 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15388 CHECK_EQ(1, force_set_set_count);
15389 CHECK_EQ(2, force_set_get_count);
15390 // Forcing the property to be set should override the accessor without
15392 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15393 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15394 CHECK_EQ(1, force_set_set_count);
15395 CHECK_EQ(2, force_set_get_count);
15399 TEST(ForceSetWithInterceptor) {
15400 force_set_get_count = 0;
15401 force_set_set_count = 0;
15402 pass_on_get = false;
15404 v8::Isolate* isolate = CcTest::isolate();
15405 v8::HandleScope scope(isolate);
15406 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15407 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15408 LocalContext context(NULL, templ);
15409 v8::Handle<v8::Object> global = context->Global();
15411 v8::Handle<v8::String> some_property =
15412 v8::String::NewFromUtf8(isolate, "a");
15413 CHECK_EQ(0, force_set_set_count);
15414 CHECK_EQ(0, force_set_get_count);
15415 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15416 // Setting the property shouldn't override it, just call the setter
15417 // which in this case does nothing.
15418 global->Set(some_property, v8::Int32::New(isolate, 7));
15419 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15420 CHECK_EQ(1, force_set_set_count);
15421 CHECK_EQ(2, force_set_get_count);
15422 // Getting the property when the interceptor returns an empty handle
15423 // should yield undefined, since the property isn't present on the
15424 // object itself yet.
15425 pass_on_get = true;
15426 CHECK(global->Get(some_property)->IsUndefined());
15427 CHECK_EQ(1, force_set_set_count);
15428 CHECK_EQ(3, force_set_get_count);
15429 // Forcing the property to be set should cause the value to be
15430 // set locally without calling the interceptor.
15431 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15432 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15433 CHECK_EQ(1, force_set_set_count);
15434 CHECK_EQ(4, force_set_get_count);
15435 // Reenabling the interceptor should cause it to take precedence over
15437 pass_on_get = false;
15438 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15439 CHECK_EQ(1, force_set_set_count);
15440 CHECK_EQ(5, force_set_get_count);
15441 // The interceptor should also work for other properties
15442 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15444 CHECK_EQ(1, force_set_set_count);
15445 CHECK_EQ(6, force_set_get_count);
15449 THREADED_TEST(ForceDelete) {
15450 v8::Isolate* isolate = CcTest::isolate();
15451 v8::HandleScope scope(isolate);
15452 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15453 LocalContext context(NULL, templ);
15454 v8::Handle<v8::Object> global = context->Global();
15456 // Ordinary properties
15457 v8::Handle<v8::String> simple_property =
15458 v8::String::NewFromUtf8(isolate, "p");
15459 global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15460 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15461 // This should fail because the property is dont-delete.
15462 CHECK(!global->Delete(simple_property));
15463 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15464 // This should succeed even though the property is dont-delete.
15465 CHECK(global->ForceDelete(simple_property));
15466 CHECK(global->Get(simple_property)->IsUndefined());
15470 static int force_delete_interceptor_count = 0;
15471 static bool pass_on_delete = false;
15474 static void ForceDeleteDeleter(
15475 v8::Local<v8::String> name,
15476 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15477 force_delete_interceptor_count++;
15478 if (pass_on_delete) return;
15479 info.GetReturnValue().Set(true);
15483 THREADED_TEST(ForceDeleteWithInterceptor) {
15484 force_delete_interceptor_count = 0;
15485 pass_on_delete = false;
15487 v8::Isolate* isolate = CcTest::isolate();
15488 v8::HandleScope scope(isolate);
15489 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15490 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15491 LocalContext context(NULL, templ);
15492 v8::Handle<v8::Object> global = context->Global();
15494 v8::Handle<v8::String> some_property =
15495 v8::String::NewFromUtf8(isolate, "a");
15496 global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15498 // Deleting a property should get intercepted and nothing should
15500 CHECK_EQ(0, force_delete_interceptor_count);
15501 CHECK(global->Delete(some_property));
15502 CHECK_EQ(1, force_delete_interceptor_count);
15503 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15504 // Deleting the property when the interceptor returns an empty
15505 // handle should not delete the property since it is DontDelete.
15506 pass_on_delete = true;
15507 CHECK(!global->Delete(some_property));
15508 CHECK_EQ(2, force_delete_interceptor_count);
15509 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15510 // Forcing the property to be deleted should delete the value
15511 // without calling the interceptor.
15512 CHECK(global->ForceDelete(some_property));
15513 CHECK(global->Get(some_property)->IsUndefined());
15514 CHECK_EQ(2, force_delete_interceptor_count);
15518 // Make sure that forcing a delete invalidates any IC stubs, so we
15519 // don't read the hole value.
15520 THREADED_TEST(ForceDeleteIC) {
15521 LocalContext context;
15522 v8::HandleScope scope(context->GetIsolate());
15523 // Create a DontDelete variable on the global object.
15524 CompileRun("this.__proto__ = { foo: 'horse' };"
15525 "var foo = 'fish';"
15526 "function f() { return foo.length; }");
15527 // Initialize the IC for foo in f.
15528 CompileRun("for (var i = 0; i < 4; i++) f();");
15529 // Make sure the value of foo is correct before the deletion.
15530 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15531 // Force the deletion of foo.
15532 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15533 // Make sure the value for foo is read from the prototype, and that
15534 // we don't get in trouble with reading the deleted cell value
15536 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15540 TEST(InlinedFunctionAcrossContexts) {
15541 i::FLAG_allow_natives_syntax = true;
15542 v8::Isolate* isolate = CcTest::isolate();
15543 v8::HandleScope outer_scope(isolate);
15544 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15545 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15549 v8::HandleScope inner_scope(CcTest::isolate());
15550 CompileRun("var G = 42; function foo() { return G; }");
15551 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15553 ctx2->Global()->Set(v8_str("o"), foo);
15554 v8::Local<v8::Value> res = CompileRun(
15555 "function f() { return o(); }"
15556 "for (var i = 0; i < 10; ++i) f();"
15557 "%OptimizeFunctionOnNextCall(f);"
15559 CHECK_EQ(42, res->Int32Value());
15561 v8::Handle<v8::String> G_property =
15562 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15563 CHECK(ctx1->Global()->ForceDelete(G_property));
15570 " return e.toString();"
15573 "ReferenceError: G is not defined");
15580 static v8::Local<Context> calling_context0;
15581 static v8::Local<Context> calling_context1;
15582 static v8::Local<Context> calling_context2;
15585 // Check that the call to the callback is initiated in
15586 // calling_context2, the directly calling context is calling_context1
15587 // and the callback itself is in calling_context0.
15588 static void GetCallingContextCallback(
15589 const v8::FunctionCallbackInfo<v8::Value>& args) {
15590 ApiTestFuzzer::Fuzz();
15591 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15592 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15593 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15594 args.GetReturnValue().Set(42);
15598 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15599 i::Isolate* isolate = CcTest::i_isolate();
15600 CHECK(isolate != NULL);
15601 CHECK(isolate->context() == NULL);
15602 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15603 v8::HandleScope scope(v8_isolate);
15604 // The following should not crash, but return an empty handle.
15605 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15606 CHECK(current.IsEmpty());
15610 THREADED_TEST(GetCallingContext) {
15611 v8::Isolate* isolate = CcTest::isolate();
15612 v8::HandleScope scope(isolate);
15614 Local<Context> calling_context0(Context::New(isolate));
15615 Local<Context> calling_context1(Context::New(isolate));
15616 Local<Context> calling_context2(Context::New(isolate));
15617 ::calling_context0 = calling_context0;
15618 ::calling_context1 = calling_context1;
15619 ::calling_context2 = calling_context2;
15621 // Allow cross-domain access.
15622 Local<String> token = v8_str("<security token>");
15623 calling_context0->SetSecurityToken(token);
15624 calling_context1->SetSecurityToken(token);
15625 calling_context2->SetSecurityToken(token);
15627 // Create an object with a C++ callback in context0.
15628 calling_context0->Enter();
15629 Local<v8::FunctionTemplate> callback_templ =
15630 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15631 calling_context0->Global()->Set(v8_str("callback"),
15632 callback_templ->GetFunction());
15633 calling_context0->Exit();
15635 // Expose context0 in context1 and set up a function that calls the
15636 // callback function.
15637 calling_context1->Enter();
15638 calling_context1->Global()->Set(v8_str("context0"),
15639 calling_context0->Global());
15640 CompileRun("function f() { context0.callback() }");
15641 calling_context1->Exit();
15643 // Expose context1 in context2 and call the callback function in
15644 // context0 indirectly through f in context1.
15645 calling_context2->Enter();
15646 calling_context2->Global()->Set(v8_str("context1"),
15647 calling_context1->Global());
15648 CompileRun("context1.f()");
15649 calling_context2->Exit();
15650 ::calling_context0.Clear();
15651 ::calling_context1.Clear();
15652 ::calling_context2.Clear();
15656 // Check that a variable declaration with no explicit initialization
15657 // value does shadow an existing property in the prototype chain.
15658 THREADED_TEST(InitGlobalVarInProtoChain) {
15659 i::FLAG_es52_globals = true;
15660 LocalContext context;
15661 v8::HandleScope scope(context->GetIsolate());
15662 // Introduce a variable in the prototype chain.
15663 CompileRun("__proto__.x = 42");
15664 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15665 CHECK(!result->IsUndefined());
15666 CHECK_EQ(43, result->Int32Value());
15670 // Regression test for issue 398.
15671 // If a function is added to an object, creating a constant function
15672 // field, and the result is cloned, replacing the constant function on the
15673 // original should not affect the clone.
15674 // See http://code.google.com/p/v8/issues/detail?id=398
15675 THREADED_TEST(ReplaceConstantFunction) {
15676 LocalContext context;
15677 v8::Isolate* isolate = context->GetIsolate();
15678 v8::HandleScope scope(isolate);
15679 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15680 v8::Handle<v8::FunctionTemplate> func_templ =
15681 v8::FunctionTemplate::New(isolate);
15682 v8::Handle<v8::String> foo_string =
15683 v8::String::NewFromUtf8(isolate, "foo");
15684 obj->Set(foo_string, func_templ->GetFunction());
15685 v8::Handle<v8::Object> obj_clone = obj->Clone();
15686 obj_clone->Set(foo_string,
15687 v8::String::NewFromUtf8(isolate, "Hello"));
15688 CHECK(!obj->Get(foo_string)->IsUndefined());
15692 static void CheckElementValue(i::Isolate* isolate,
15694 i::Handle<i::Object> obj,
15696 i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15697 CHECK_EQ(expected, i::Smi::cast(element)->value());
15701 THREADED_TEST(PixelArray) {
15702 LocalContext context;
15703 i::Isolate* isolate = CcTest::i_isolate();
15704 i::Factory* factory = isolate->factory();
15705 v8::HandleScope scope(context->GetIsolate());
15706 const int kElementCount = 260;
15707 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15708 i::Handle<i::ExternalUint8ClampedArray> pixels =
15709 i::Handle<i::ExternalUint8ClampedArray>::cast(
15710 factory->NewExternalArray(kElementCount,
15711 v8::kExternalUint8ClampedArray,
15713 // Force GC to trigger verification.
15714 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15715 for (int i = 0; i < kElementCount; i++) {
15716 pixels->set(i, i % 256);
15718 // Force GC to trigger verification.
15719 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15720 for (int i = 0; i < kElementCount; i++) {
15721 CHECK_EQ(i % 256, pixels->get_scalar(i));
15722 CHECK_EQ(i % 256, pixel_data[i]);
15725 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15726 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15727 // Set the elements to be the pixels.
15728 // jsobj->set_elements(*pixels);
15729 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15730 CheckElementValue(isolate, 1, jsobj, 1);
15731 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15732 context->Global()->Set(v8_str("pixels"), obj);
15733 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15734 CHECK_EQ(1503, result->Int32Value());
15735 result = CompileRun("pixels[1]");
15736 CHECK_EQ(1, result->Int32Value());
15738 result = CompileRun("var sum = 0;"
15739 "for (var i = 0; i < 8; i++) {"
15740 " sum += pixels[i] = pixels[i] = -i;"
15743 CHECK_EQ(-28, result->Int32Value());
15745 result = CompileRun("var sum = 0;"
15746 "for (var i = 0; i < 8; i++) {"
15747 " sum += pixels[i] = pixels[i] = 0;"
15750 CHECK_EQ(0, result->Int32Value());
15752 result = CompileRun("var sum = 0;"
15753 "for (var i = 0; i < 8; i++) {"
15754 " sum += pixels[i] = pixels[i] = 255;"
15757 CHECK_EQ(8 * 255, result->Int32Value());
15759 result = CompileRun("var sum = 0;"
15760 "for (var i = 0; i < 8; i++) {"
15761 " sum += pixels[i] = pixels[i] = 256 + i;"
15764 CHECK_EQ(2076, result->Int32Value());
15766 result = CompileRun("var sum = 0;"
15767 "for (var i = 0; i < 8; i++) {"
15768 " sum += pixels[i] = pixels[i] = i;"
15771 CHECK_EQ(28, result->Int32Value());
15773 result = CompileRun("var sum = 0;"
15774 "for (var i = 0; i < 8; i++) {"
15775 " sum += pixels[i];"
15778 CHECK_EQ(28, result->Int32Value());
15780 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15781 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15782 i::Handle<i::Object> no_failure;
15784 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15785 ASSERT(!no_failure.is_null());
15786 i::USE(no_failure);
15787 CheckElementValue(isolate, 2, jsobj, 1);
15788 *value.location() = i::Smi::FromInt(256);
15790 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15791 ASSERT(!no_failure.is_null());
15792 i::USE(no_failure);
15793 CheckElementValue(isolate, 255, jsobj, 1);
15794 *value.location() = i::Smi::FromInt(-1);
15796 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15797 ASSERT(!no_failure.is_null());
15798 i::USE(no_failure);
15799 CheckElementValue(isolate, 0, jsobj, 1);
15801 result = CompileRun("for (var i = 0; i < 8; i++) {"
15802 " pixels[i] = (i * 65) - 109;"
15804 "pixels[1] + pixels[6];");
15805 CHECK_EQ(255, result->Int32Value());
15806 CheckElementValue(isolate, 0, jsobj, 0);
15807 CheckElementValue(isolate, 0, jsobj, 1);
15808 CheckElementValue(isolate, 21, jsobj, 2);
15809 CheckElementValue(isolate, 86, jsobj, 3);
15810 CheckElementValue(isolate, 151, jsobj, 4);
15811 CheckElementValue(isolate, 216, jsobj, 5);
15812 CheckElementValue(isolate, 255, jsobj, 6);
15813 CheckElementValue(isolate, 255, jsobj, 7);
15814 result = CompileRun("var sum = 0;"
15815 "for (var i = 0; i < 8; i++) {"
15816 " sum += pixels[i];"
15819 CHECK_EQ(984, result->Int32Value());
15821 result = CompileRun("for (var i = 0; i < 8; i++) {"
15822 " pixels[i] = (i * 1.1);"
15824 "pixels[1] + pixels[6];");
15825 CHECK_EQ(8, result->Int32Value());
15826 CheckElementValue(isolate, 0, jsobj, 0);
15827 CheckElementValue(isolate, 1, jsobj, 1);
15828 CheckElementValue(isolate, 2, jsobj, 2);
15829 CheckElementValue(isolate, 3, jsobj, 3);
15830 CheckElementValue(isolate, 4, jsobj, 4);
15831 CheckElementValue(isolate, 6, jsobj, 5);
15832 CheckElementValue(isolate, 7, jsobj, 6);
15833 CheckElementValue(isolate, 8, jsobj, 7);
15835 result = CompileRun("for (var i = 0; i < 8; i++) {"
15836 " pixels[7] = undefined;"
15839 CHECK_EQ(0, result->Int32Value());
15840 CheckElementValue(isolate, 0, jsobj, 7);
15842 result = CompileRun("for (var i = 0; i < 8; i++) {"
15843 " pixels[6] = '2.3';"
15846 CHECK_EQ(2, result->Int32Value());
15847 CheckElementValue(isolate, 2, jsobj, 6);
15849 result = CompileRun("for (var i = 0; i < 8; i++) {"
15850 " pixels[5] = NaN;"
15853 CHECK_EQ(0, result->Int32Value());
15854 CheckElementValue(isolate, 0, jsobj, 5);
15856 result = CompileRun("for (var i = 0; i < 8; i++) {"
15857 " pixels[8] = Infinity;"
15860 CHECK_EQ(255, result->Int32Value());
15861 CheckElementValue(isolate, 255, jsobj, 8);
15863 result = CompileRun("for (var i = 0; i < 8; i++) {"
15864 " pixels[9] = -Infinity;"
15867 CHECK_EQ(0, result->Int32Value());
15868 CheckElementValue(isolate, 0, jsobj, 9);
15870 result = CompileRun("pixels[3] = 33;"
15871 "delete pixels[3];"
15873 CHECK_EQ(33, result->Int32Value());
15875 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15876 "pixels[2] = 12; pixels[3] = 13;"
15877 "pixels.__defineGetter__('2',"
15878 "function() { return 120; });"
15880 CHECK_EQ(12, result->Int32Value());
15882 result = CompileRun("var js_array = new Array(40);"
15883 "js_array[0] = 77;"
15885 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15887 result = CompileRun("pixels[1] = 23;"
15888 "pixels.__proto__ = [];"
15889 "js_array.__proto__ = pixels;"
15890 "js_array.concat(pixels);");
15891 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15892 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15894 result = CompileRun("pixels[1] = 23;");
15895 CHECK_EQ(23, result->Int32Value());
15897 // Test for index greater than 255. Regression test for:
15898 // http://code.google.com/p/chromium/issues/detail?id=26337.
15899 result = CompileRun("pixels[256] = 255;");
15900 CHECK_EQ(255, result->Int32Value());
15901 result = CompileRun("var i = 0;"
15902 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15904 CHECK_EQ(255, result->Int32Value());
15906 // Make sure that pixel array ICs recognize when a non-pixel array
15907 // is passed to it.
15908 result = CompileRun("function pa_load(p) {"
15910 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15913 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15914 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15915 "just_ints = new Object();"
15916 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15917 "for (var i = 0; i < 10; ++i) {"
15918 " result = pa_load(just_ints);"
15921 CHECK_EQ(32640, result->Int32Value());
15923 // Make sure that pixel array ICs recognize out-of-bound accesses.
15924 result = CompileRun("function pa_load(p, start) {"
15926 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15929 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15930 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15931 "for (var i = 0; i < 10; ++i) {"
15932 " result = pa_load(pixels,-10);"
15935 CHECK_EQ(0, result->Int32Value());
15937 // Make sure that generic ICs properly handles a pixel array.
15938 result = CompileRun("function pa_load(p) {"
15940 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15943 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15944 "just_ints = new Object();"
15945 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15946 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15947 "for (var i = 0; i < 10; ++i) {"
15948 " result = pa_load(pixels);"
15951 CHECK_EQ(32640, result->Int32Value());
15953 // Make sure that generic load ICs recognize out-of-bound accesses in
15955 result = CompileRun("function pa_load(p, start) {"
15957 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15960 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15961 "just_ints = new Object();"
15962 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15963 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15964 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15965 "for (var i = 0; i < 10; ++i) {"
15966 " result = pa_load(pixels,-10);"
15969 CHECK_EQ(0, result->Int32Value());
15971 // Make sure that generic ICs properly handles other types than pixel
15972 // arrays (that the inlined fast pixel array test leaves the right information
15973 // in the right registers).
15974 result = CompileRun("function pa_load(p) {"
15976 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15979 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15980 "just_ints = new Object();"
15981 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15982 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15983 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15984 "sparse_array = new Object();"
15985 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15986 "sparse_array[1000000] = 3;"
15987 "for (var i = 0; i < 10; ++i) {"
15988 " result = pa_load(sparse_array);"
15991 CHECK_EQ(32640, result->Int32Value());
15993 // Make sure that pixel array store ICs clamp values correctly.
15994 result = CompileRun("function pa_store(p) {"
15995 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15997 "pa_store(pixels);"
15999 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16001 CHECK_EQ(48896, result->Int32Value());
16003 // Make sure that pixel array stores correctly handle accesses outside
16004 // of the pixel array..
16005 result = CompileRun("function pa_store(p,start) {"
16006 " for (var j = 0; j < 256; j++) {"
16007 " p[j+start] = j * 2;"
16010 "pa_store(pixels,0);"
16011 "pa_store(pixels,-128);"
16013 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16015 CHECK_EQ(65280, result->Int32Value());
16017 // Make sure that the generic store stub correctly handle accesses outside
16018 // of the pixel array..
16019 result = CompileRun("function pa_store(p,start) {"
16020 " for (var j = 0; j < 256; j++) {"
16021 " p[j+start] = j * 2;"
16024 "pa_store(pixels,0);"
16025 "just_ints = new Object();"
16026 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16027 "pa_store(just_ints, 0);"
16028 "pa_store(pixels,-128);"
16030 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16032 CHECK_EQ(65280, result->Int32Value());
16034 // Make sure that the generic keyed store stub clamps pixel array values
16036 result = CompileRun("function pa_store(p) {"
16037 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16039 "pa_store(pixels);"
16040 "just_ints = new Object();"
16041 "pa_store(just_ints);"
16042 "pa_store(pixels);"
16044 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16046 CHECK_EQ(48896, result->Int32Value());
16048 // Make sure that pixel array loads are optimized by crankshaft.
16049 result = CompileRun("function pa_load(p) {"
16051 " for (var i=0; i<256; ++i) {"
16056 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16057 "for (var i = 0; i < 5000; ++i) {"
16058 " result = pa_load(pixels);"
16061 CHECK_EQ(32640, result->Int32Value());
16063 // Make sure that pixel array stores are optimized by crankshaft.
16064 result = CompileRun("function pa_init(p) {"
16065 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16067 "function pa_load(p) {"
16069 " for (var i=0; i<256; ++i) {"
16074 "for (var i = 0; i < 5000; ++i) {"
16075 " pa_init(pixels);"
16077 "result = pa_load(pixels);"
16079 CHECK_EQ(32640, result->Int32Value());
16085 THREADED_TEST(PixelArrayInfo) {
16086 LocalContext context;
16087 v8::HandleScope scope(context->GetIsolate());
16088 for (int size = 0; size < 100; size += 10) {
16089 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16090 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16091 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16092 CHECK(obj->HasIndexedPropertiesInPixelData());
16093 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16094 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16100 static void NotHandledIndexedPropertyGetter(
16102 const v8::PropertyCallbackInfo<v8::Value>& info) {
16103 ApiTestFuzzer::Fuzz();
16107 static void NotHandledIndexedPropertySetter(
16109 Local<Value> value,
16110 const v8::PropertyCallbackInfo<v8::Value>& info) {
16111 ApiTestFuzzer::Fuzz();
16115 THREADED_TEST(PixelArrayWithInterceptor) {
16116 LocalContext context;
16117 i::Factory* factory = CcTest::i_isolate()->factory();
16118 v8::Isolate* isolate = context->GetIsolate();
16119 v8::HandleScope scope(isolate);
16120 const int kElementCount = 260;
16121 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16122 i::Handle<i::ExternalUint8ClampedArray> pixels =
16123 i::Handle<i::ExternalUint8ClampedArray>::cast(
16124 factory->NewExternalArray(kElementCount,
16125 v8::kExternalUint8ClampedArray,
16127 for (int i = 0; i < kElementCount; i++) {
16128 pixels->set(i, i % 256);
16130 v8::Handle<v8::ObjectTemplate> templ =
16131 v8::ObjectTemplate::New(context->GetIsolate());
16132 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16133 NotHandledIndexedPropertySetter);
16134 v8::Handle<v8::Object> obj = templ->NewInstance();
16135 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16136 context->Global()->Set(v8_str("pixels"), obj);
16137 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16138 CHECK_EQ(1, result->Int32Value());
16139 result = CompileRun("var sum = 0;"
16140 "for (var i = 0; i < 8; i++) {"
16141 " sum += pixels[i] = pixels[i] = -i;"
16144 CHECK_EQ(-28, result->Int32Value());
16145 result = CompileRun("pixels.hasOwnProperty('1')");
16146 CHECK(result->BooleanValue());
16151 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16152 switch (array_type) {
16153 case v8::kExternalInt8Array:
16154 case v8::kExternalUint8Array:
16155 case v8::kExternalUint8ClampedArray:
16158 case v8::kExternalInt16Array:
16159 case v8::kExternalUint16Array:
16162 case v8::kExternalInt32Array:
16163 case v8::kExternalUint32Array:
16164 case v8::kExternalFloat32Array:
16167 case v8::kExternalFloat64Array:
16179 template <class ExternalArrayClass, class ElementType>
16180 static void ObjectWithExternalArrayTestHelper(
16181 Handle<Context> context,
16182 v8::Handle<Object> obj,
16184 v8::ExternalArrayType array_type,
16185 int64_t low, int64_t high) {
16186 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16187 i::Isolate* isolate = jsobj->GetIsolate();
16188 obj->Set(v8_str("field"),
16189 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16190 context->Global()->Set(v8_str("ext_array"), obj);
16191 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16192 CHECK_EQ(1503, result->Int32Value());
16193 result = CompileRun("ext_array[1]");
16194 CHECK_EQ(1, result->Int32Value());
16196 // Check assigned smis
16197 result = CompileRun("for (var i = 0; i < 8; i++) {"
16198 " ext_array[i] = i;"
16201 "for (var i = 0; i < 8; i++) {"
16202 " sum += ext_array[i];"
16206 CHECK_EQ(28, result->Int32Value());
16207 // Check pass through of assigned smis
16208 result = CompileRun("var sum = 0;"
16209 "for (var i = 0; i < 8; i++) {"
16210 " sum += ext_array[i] = ext_array[i] = -i;"
16213 CHECK_EQ(-28, result->Int32Value());
16216 // Check assigned smis in reverse order
16217 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16218 " ext_array[i] = i;"
16221 "for (var i = 0; i < 8; i++) {"
16222 " sum += ext_array[i];"
16225 CHECK_EQ(28, result->Int32Value());
16227 // Check pass through of assigned HeapNumbers
16228 result = CompileRun("var sum = 0;"
16229 "for (var i = 0; i < 16; i+=2) {"
16230 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16233 CHECK_EQ(-28, result->Int32Value());
16235 // Check assigned HeapNumbers
16236 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16237 " ext_array[i] = (i * 0.5);"
16240 "for (var i = 0; i < 16; i+=2) {"
16241 " sum += ext_array[i];"
16244 CHECK_EQ(28, result->Int32Value());
16246 // Check assigned HeapNumbers in reverse order
16247 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16248 " ext_array[i] = (i * 0.5);"
16251 "for (var i = 0; i < 16; i+=2) {"
16252 " sum += ext_array[i];"
16255 CHECK_EQ(28, result->Int32Value());
16257 i::ScopedVector<char> test_buf(1024);
16259 // Check legal boundary conditions.
16260 // The repeated loads and stores ensure the ICs are exercised.
16261 const char* boundary_program =
16263 "for (var i = 0; i < 16; i++) {"
16264 " ext_array[i] = %lld;"
16266 " res = ext_array[i];"
16270 i::OS::SNPrintF(test_buf,
16273 result = CompileRun(test_buf.start());
16274 CHECK_EQ(low, result->IntegerValue());
16276 i::OS::SNPrintF(test_buf,
16279 result = CompileRun(test_buf.start());
16280 CHECK_EQ(high, result->IntegerValue());
16282 // Check misprediction of type in IC.
16283 result = CompileRun("var tmp_array = ext_array;"
16285 "for (var i = 0; i < 8; i++) {"
16286 " tmp_array[i] = i;"
16287 " sum += tmp_array[i];"
16293 // Force GC to trigger verification.
16294 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16295 CHECK_EQ(28, result->Int32Value());
16297 // Make sure out-of-range loads do not throw.
16298 i::OS::SNPrintF(test_buf,
16299 "var caught_exception = false;"
16303 " caught_exception = true;"
16305 "caught_exception;",
16307 result = CompileRun(test_buf.start());
16308 CHECK_EQ(false, result->BooleanValue());
16310 // Make sure out-of-range stores do not throw.
16311 i::OS::SNPrintF(test_buf,
16312 "var caught_exception = false;"
16314 " ext_array[%d] = 1;"
16316 " caught_exception = true;"
16318 "caught_exception;",
16320 result = CompileRun(test_buf.start());
16321 CHECK_EQ(false, result->BooleanValue());
16323 // Check other boundary conditions, values and operations.
16324 result = CompileRun("for (var i = 0; i < 8; i++) {"
16325 " ext_array[7] = undefined;"
16328 CHECK_EQ(0, result->Int32Value());
16329 if (array_type == v8::kExternalFloat64Array ||
16330 array_type == v8::kExternalFloat32Array) {
16331 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16333 jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
16335 CheckElementValue(isolate, 0, jsobj, 7);
16338 result = CompileRun("for (var i = 0; i < 8; i++) {"
16339 " ext_array[6] = '2.3';"
16342 CHECK_EQ(2, result->Int32Value());
16345 jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
16347 if (array_type != v8::kExternalFloat32Array &&
16348 array_type != v8::kExternalFloat64Array) {
16349 // Though the specification doesn't state it, be explicit about
16350 // converting NaNs and +/-Infinity to zero.
16351 result = CompileRun("for (var i = 0; i < 8; i++) {"
16352 " ext_array[i] = 5;"
16354 "for (var i = 0; i < 8; i++) {"
16355 " ext_array[i] = NaN;"
16358 CHECK_EQ(0, result->Int32Value());
16359 CheckElementValue(isolate, 0, jsobj, 5);
16361 result = CompileRun("for (var i = 0; i < 8; i++) {"
16362 " ext_array[i] = 5;"
16364 "for (var i = 0; i < 8; i++) {"
16365 " ext_array[i] = Infinity;"
16368 int expected_value =
16369 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16370 CHECK_EQ(expected_value, result->Int32Value());
16371 CheckElementValue(isolate, expected_value, jsobj, 5);
16373 result = CompileRun("for (var i = 0; i < 8; i++) {"
16374 " ext_array[i] = 5;"
16376 "for (var i = 0; i < 8; i++) {"
16377 " ext_array[i] = -Infinity;"
16380 CHECK_EQ(0, result->Int32Value());
16381 CheckElementValue(isolate, 0, jsobj, 5);
16383 // Check truncation behavior of integral arrays.
16384 const char* unsigned_data =
16385 "var source_data = [0.6, 10.6];"
16386 "var expected_results = [0, 10];";
16387 const char* signed_data =
16388 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16389 "var expected_results = [0, 10, 0, -10];";
16390 const char* pixel_data =
16391 "var source_data = [0.6, 10.6];"
16392 "var expected_results = [1, 11];";
16394 (array_type == v8::kExternalUint8Array ||
16395 array_type == v8::kExternalUint16Array ||
16396 array_type == v8::kExternalUint32Array);
16397 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16399 i::OS::SNPrintF(test_buf,
16401 "var all_passed = true;"
16402 "for (var i = 0; i < source_data.length; i++) {"
16403 " for (var j = 0; j < 8; j++) {"
16404 " ext_array[j] = source_data[i];"
16406 " all_passed = all_passed &&"
16407 " (ext_array[5] == expected_results[i]);"
16412 (is_pixel_data ? pixel_data : signed_data)));
16413 result = CompileRun(test_buf.start());
16414 CHECK_EQ(true, result->BooleanValue());
16417 i::Handle<ExternalArrayClass> array(
16418 ExternalArrayClass::cast(jsobj->elements()));
16419 for (int i = 0; i < element_count; i++) {
16420 array->set(i, static_cast<ElementType>(i));
16423 // Test complex assignments
16424 result = CompileRun("function ee_op_test_complex_func(sum) {"
16425 " for (var i = 0; i < 40; ++i) {"
16426 " sum += (ext_array[i] += 1);"
16427 " sum += (ext_array[i] -= 1);"
16432 "for (var i=0;i<10000;++i) {"
16433 " sum=ee_op_test_complex_func(sum);"
16436 CHECK_EQ(16000000, result->Int32Value());
16438 // Test count operations
16439 result = CompileRun("function ee_op_test_count_func(sum) {"
16440 " for (var i = 0; i < 40; ++i) {"
16441 " sum += (++ext_array[i]);"
16442 " sum += (--ext_array[i]);"
16447 "for (var i=0;i<10000;++i) {"
16448 " sum=ee_op_test_count_func(sum);"
16451 CHECK_EQ(16000000, result->Int32Value());
16453 result = CompileRun("ext_array[3] = 33;"
16454 "delete ext_array[3];"
16456 CHECK_EQ(33, result->Int32Value());
16458 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16459 "ext_array[2] = 12; ext_array[3] = 13;"
16460 "ext_array.__defineGetter__('2',"
16461 "function() { return 120; });"
16463 CHECK_EQ(12, result->Int32Value());
16465 result = CompileRun("var js_array = new Array(40);"
16466 "js_array[0] = 77;"
16468 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16470 result = CompileRun("ext_array[1] = 23;"
16471 "ext_array.__proto__ = [];"
16472 "js_array.__proto__ = ext_array;"
16473 "js_array.concat(ext_array);");
16474 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16475 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16477 result = CompileRun("ext_array[1] = 23;");
16478 CHECK_EQ(23, result->Int32Value());
16482 template <class FixedTypedArrayClass,
16483 i::ElementsKind elements_kind,
16485 static void FixedTypedArrayTestHelper(
16486 v8::ExternalArrayType array_type,
16488 ElementType high) {
16489 i::FLAG_allow_natives_syntax = true;
16490 LocalContext context;
16491 i::Isolate* isolate = CcTest::i_isolate();
16492 i::Factory* factory = isolate->factory();
16493 v8::HandleScope scope(context->GetIsolate());
16494 const int kElementCount = 260;
16495 i::Handle<FixedTypedArrayClass> fixed_array =
16496 i::Handle<FixedTypedArrayClass>::cast(
16497 factory->NewFixedTypedArray(kElementCount, array_type));
16498 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16499 fixed_array->map()->instance_type());
16500 CHECK_EQ(kElementCount, fixed_array->length());
16501 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16502 for (int i = 0; i < kElementCount; i++) {
16503 fixed_array->set(i, static_cast<ElementType>(i));
16505 // Force GC to trigger verification.
16506 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16507 for (int i = 0; i < kElementCount; i++) {
16508 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16509 static_cast<int64_t>(fixed_array->get_scalar(i)));
16511 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16512 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16513 i::Handle<i::Map> fixed_array_map =
16514 isolate->factory()->GetElementsTransitionMap(jsobj, elements_kind);
16515 jsobj->set_map(*fixed_array_map);
16516 jsobj->set_elements(*fixed_array);
16518 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16519 context.local(), obj, kElementCount, array_type,
16520 static_cast<int64_t>(low),
16521 static_cast<int64_t>(high));
16525 THREADED_TEST(FixedUint8Array) {
16526 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16527 v8::kExternalUint8Array,
16532 THREADED_TEST(FixedUint8ClampedArray) {
16533 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16534 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16535 v8::kExternalUint8ClampedArray,
16540 THREADED_TEST(FixedInt8Array) {
16541 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16542 v8::kExternalInt8Array,
16547 THREADED_TEST(FixedUint16Array) {
16548 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16549 v8::kExternalUint16Array,
16554 THREADED_TEST(FixedInt16Array) {
16555 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16556 v8::kExternalInt16Array,
16561 THREADED_TEST(FixedUint32Array) {
16562 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16563 v8::kExternalUint32Array,
16568 THREADED_TEST(FixedInt32Array) {
16569 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16570 v8::kExternalInt32Array,
16575 THREADED_TEST(FixedFloat32Array) {
16576 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16577 v8::kExternalFloat32Array,
16582 THREADED_TEST(FixedFloat64Array) {
16583 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16584 v8::kExternalFloat64Array,
16589 template <class ExternalArrayClass, class ElementType>
16590 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16593 LocalContext context;
16594 i::Isolate* isolate = CcTest::i_isolate();
16595 i::Factory* factory = isolate->factory();
16596 v8::HandleScope scope(context->GetIsolate());
16597 const int kElementCount = 40;
16598 int element_size = ExternalArrayElementSize(array_type);
16599 ElementType* array_data =
16600 static_cast<ElementType*>(malloc(kElementCount * element_size));
16601 i::Handle<ExternalArrayClass> array =
16602 i::Handle<ExternalArrayClass>::cast(
16603 factory->NewExternalArray(kElementCount, array_type, array_data));
16604 // Force GC to trigger verification.
16605 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16606 for (int i = 0; i < kElementCount; i++) {
16607 array->set(i, static_cast<ElementType>(i));
16609 // Force GC to trigger verification.
16610 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16611 for (int i = 0; i < kElementCount; i++) {
16612 CHECK_EQ(static_cast<int64_t>(i),
16613 static_cast<int64_t>(array->get_scalar(i)));
16614 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16617 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16618 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16619 // Set the elements to be the external array.
16620 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16625 jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
16627 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16628 context.local(), obj, kElementCount, array_type, low, high);
16630 v8::Handle<v8::Value> result;
16632 // Test more complex manipulations which cause eax to contain values
16633 // that won't be completely overwritten by loads from the arrays.
16634 // This catches bugs in the instructions used for the KeyedLoadIC
16635 // for byte and word types.
16637 const int kXSize = 300;
16638 const int kYSize = 300;
16639 const int kLargeElementCount = kXSize * kYSize * 4;
16640 ElementType* large_array_data =
16641 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16642 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16643 // Set the elements to be the external array.
16644 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16646 kLargeElementCount);
16647 context->Global()->Set(v8_str("large_array"), large_obj);
16648 // Initialize contents of a few rows.
16649 for (int x = 0; x < 300; x++) {
16651 int offset = row * 300 * 4;
16652 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16653 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16654 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16655 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16657 offset = row * 300 * 4;
16658 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16659 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16660 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16661 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16663 offset = row * 300 * 4;
16664 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16665 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16666 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16667 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16669 // The goal of the code below is to make "offset" large enough
16670 // that the computation of the index (which goes into eax) has
16671 // high bits set which will not be overwritten by a byte or short
16673 result = CompileRun("var failed = false;"
16675 "for (var i = 0; i < 300; i++) {"
16676 " if (large_array[4 * i] != 127 ||"
16677 " large_array[4 * i + 1] != 0 ||"
16678 " large_array[4 * i + 2] != 0 ||"
16679 " large_array[4 * i + 3] != 127) {"
16683 "offset = 150 * 300 * 4;"
16684 "for (var i = 0; i < 300; i++) {"
16685 " if (large_array[offset + 4 * i] != 127 ||"
16686 " large_array[offset + 4 * i + 1] != 0 ||"
16687 " large_array[offset + 4 * i + 2] != 0 ||"
16688 " large_array[offset + 4 * i + 3] != 127) {"
16692 "offset = 298 * 300 * 4;"
16693 "for (var i = 0; i < 300; i++) {"
16694 " if (large_array[offset + 4 * i] != 127 ||"
16695 " large_array[offset + 4 * i + 1] != 0 ||"
16696 " large_array[offset + 4 * i + 2] != 0 ||"
16697 " large_array[offset + 4 * i + 3] != 127) {"
16702 CHECK_EQ(true, result->BooleanValue());
16703 free(large_array_data);
16706 // The "" property descriptor is overloaded to store information about
16707 // the external array. Ensure that setting and accessing the "" property
16708 // works (it should overwrite the information cached about the external
16709 // array in the DescriptorArray) in various situations.
16710 result = CompileRun("ext_array[''] = 23; ext_array['']");
16711 CHECK_EQ(23, result->Int32Value());
16713 // Property "" set after the external array is associated with the object.
16715 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16716 obj2->Set(v8_str("ee_test_field"),
16717 v8::Int32::New(context->GetIsolate(), 256));
16718 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16719 // Set the elements to be the external array.
16720 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16723 context->Global()->Set(v8_str("ext_array"), obj2);
16724 result = CompileRun("ext_array['']");
16725 CHECK_EQ(1503, result->Int32Value());
16728 // Property "" set after the external array is associated with the object.
16730 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16731 obj2->Set(v8_str("ee_test_field_2"),
16732 v8::Int32::New(context->GetIsolate(), 256));
16733 // Set the elements to be the external array.
16734 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16737 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16738 context->Global()->Set(v8_str("ext_array"), obj2);
16739 result = CompileRun("ext_array['']");
16740 CHECK_EQ(1503, result->Int32Value());
16743 // Should reuse the map from previous test.
16745 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16746 obj2->Set(v8_str("ee_test_field_2"),
16747 v8::Int32::New(context->GetIsolate(), 256));
16748 // Set the elements to be the external array. Should re-use the map
16749 // from previous test.
16750 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16753 context->Global()->Set(v8_str("ext_array"), obj2);
16754 result = CompileRun("ext_array['']");
16757 // Property "" is a constant function that shouldn't not be interfered with
16758 // when an external array is set.
16760 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16762 obj2->Set(v8_str("ee_test_field3"),
16763 v8::Int32::New(context->GetIsolate(), 256));
16765 // Add a constant function to an object.
16766 context->Global()->Set(v8_str("ext_array"), obj2);
16767 result = CompileRun("ext_array[''] = function() {return 1503;};"
16768 "ext_array['']();");
16770 // Add an external array transition to the same map that
16771 // has the constant transition.
16772 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16773 obj3->Set(v8_str("ee_test_field3"),
16774 v8::Int32::New(context->GetIsolate(), 256));
16775 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16778 context->Global()->Set(v8_str("ext_array"), obj3);
16781 // If a external array transition is in the map, it should get clobbered
16782 // by a constant function.
16784 // Add an external array transition.
16785 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16786 obj3->Set(v8_str("ee_test_field4"),
16787 v8::Int32::New(context->GetIsolate(), 256));
16788 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16792 // Add a constant function to the same map that just got an external array
16794 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16795 obj2->Set(v8_str("ee_test_field4"),
16796 v8::Int32::New(context->GetIsolate(), 256));
16797 context->Global()->Set(v8_str("ext_array"), obj2);
16798 result = CompileRun("ext_array[''] = function() {return 1503;};"
16799 "ext_array['']();");
16806 THREADED_TEST(ExternalInt8Array) {
16807 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16808 v8::kExternalInt8Array,
16814 THREADED_TEST(ExternalUint8Array) {
16815 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16816 v8::kExternalUint8Array,
16822 THREADED_TEST(ExternalUint8ClampedArray) {
16823 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16824 v8::kExternalUint8ClampedArray,
16830 THREADED_TEST(ExternalInt16Array) {
16831 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16832 v8::kExternalInt16Array,
16838 THREADED_TEST(ExternalUint16Array) {
16839 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16840 v8::kExternalUint16Array,
16846 THREADED_TEST(ExternalInt32Array) {
16847 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16848 v8::kExternalInt32Array,
16849 INT_MIN, // -2147483648
16850 INT_MAX); // 2147483647
16854 THREADED_TEST(ExternalUint32Array) {
16855 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16856 v8::kExternalUint32Array,
16858 UINT_MAX); // 4294967295
16862 THREADED_TEST(ExternalFloat32Array) {
16863 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16864 v8::kExternalFloat32Array,
16870 THREADED_TEST(ExternalFloat64Array) {
16871 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16872 v8::kExternalFloat64Array,
16878 THREADED_TEST(ExternalArrays) {
16879 TestExternalInt8Array();
16880 TestExternalUint8Array();
16881 TestExternalInt16Array();
16882 TestExternalUint16Array();
16883 TestExternalInt32Array();
16884 TestExternalUint32Array();
16885 TestExternalFloat32Array();
16889 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16890 LocalContext context;
16891 v8::HandleScope scope(context->GetIsolate());
16892 for (int size = 0; size < 100; size += 10) {
16893 int element_size = ExternalArrayElementSize(array_type);
16894 void* external_data = malloc(size * element_size);
16895 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16896 obj->SetIndexedPropertiesToExternalArrayData(
16897 external_data, array_type, size);
16898 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16899 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16900 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16901 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16902 free(external_data);
16907 THREADED_TEST(ExternalArrayInfo) {
16908 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16909 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16910 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16911 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16912 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16913 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16914 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16915 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16916 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16920 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16921 v8::ExternalArrayType array_type,
16923 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16924 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16925 last_location = last_message = NULL;
16926 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16927 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16928 CHECK_NE(NULL, last_location);
16929 CHECK_NE(NULL, last_message);
16933 TEST(ExternalArrayLimits) {
16934 LocalContext context;
16935 v8::Isolate* isolate = context->GetIsolate();
16936 v8::HandleScope scope(isolate);
16937 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16938 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16939 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16940 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16941 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16942 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16943 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16944 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16945 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16946 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16947 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16948 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16949 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16950 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16951 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16952 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16953 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16954 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16958 template <typename ElementType, typename TypedArray,
16959 class ExternalArrayClass>
16960 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16961 int64_t low, int64_t high) {
16962 const int kElementCount = 50;
16964 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16967 v8::Isolate* isolate = env->GetIsolate();
16968 v8::HandleScope handle_scope(isolate);
16970 Local<v8::ArrayBuffer> ab =
16971 v8::ArrayBuffer::New(isolate, backing_store.start(),
16972 (kElementCount + 2) * sizeof(ElementType));
16973 Local<TypedArray> ta =
16974 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16975 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16976 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16977 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16978 CHECK_EQ(kElementCount*sizeof(ElementType),
16979 static_cast<int>(ta->ByteLength()));
16980 CHECK_EQ(ab, ta->Buffer());
16982 ElementType* data = backing_store.start() + 2;
16983 for (int i = 0; i < kElementCount; i++) {
16984 data[i] = static_cast<ElementType>(i);
16987 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16988 env.local(), ta, kElementCount, array_type, low, high);
16992 THREADED_TEST(Uint8Array) {
16993 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16994 v8::kExternalUint8Array, 0, 0xFF);
16998 THREADED_TEST(Int8Array) {
16999 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17000 v8::kExternalInt8Array, -0x80, 0x7F);
17004 THREADED_TEST(Uint16Array) {
17005 TypedArrayTestHelper<uint16_t,
17007 i::ExternalUint16Array>(
17008 v8::kExternalUint16Array, 0, 0xFFFF);
17012 THREADED_TEST(Int16Array) {
17013 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17014 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17018 THREADED_TEST(Uint32Array) {
17019 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17020 v8::kExternalUint32Array, 0, UINT_MAX);
17024 THREADED_TEST(Int32Array) {
17025 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17026 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17030 THREADED_TEST(Float32Array) {
17031 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17032 v8::kExternalFloat32Array, -500, 500);
17036 THREADED_TEST(Float64Array) {
17037 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17038 v8::kExternalFloat64Array, -500, 500);
17042 THREADED_TEST(Uint8ClampedArray) {
17043 TypedArrayTestHelper<uint8_t,
17044 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17045 v8::kExternalUint8ClampedArray, 0, 0xFF);
17049 THREADED_TEST(DataView) {
17050 const int kSize = 50;
17052 i::ScopedVector<uint8_t> backing_store(kSize+2);
17055 v8::Isolate* isolate = env->GetIsolate();
17056 v8::HandleScope handle_scope(isolate);
17058 Local<v8::ArrayBuffer> ab =
17059 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17060 Local<v8::DataView> dv =
17061 v8::DataView::New(ab, 2, kSize);
17062 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17063 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17064 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17065 CHECK_EQ(ab, dv->Buffer());
17069 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17070 THREADED_TEST(Is##View) { \
17071 LocalContext env; \
17072 v8::Isolate* isolate = env->GetIsolate(); \
17073 v8::HandleScope handle_scope(isolate); \
17075 Handle<Value> result = CompileRun( \
17076 "var ab = new ArrayBuffer(128);" \
17077 "new " #View "(ab)"); \
17078 CHECK(result->IsArrayBufferView()); \
17079 CHECK(result->Is##View()); \
17080 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17083 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17084 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17085 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17086 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17087 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17088 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17089 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17090 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17091 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17092 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17094 #undef IS_ARRAY_BUFFER_VIEW_TEST
17098 THREADED_TEST(ScriptContextDependence) {
17100 v8::HandleScope scope(c1->GetIsolate());
17101 const char *source = "foo";
17102 v8::Handle<v8::Script> dep =
17103 v8::Script::Compile(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17104 v8::Handle<v8::Script> indep =
17105 v8::Script::New(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17106 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17107 v8::Integer::New(c1->GetIsolate(), 100));
17108 CHECK_EQ(dep->Run()->Int32Value(), 100);
17109 CHECK_EQ(indep->Run()->Int32Value(), 100);
17111 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17112 v8::Integer::New(c2->GetIsolate(), 101));
17113 CHECK_EQ(dep->Run()->Int32Value(), 100);
17114 CHECK_EQ(indep->Run()->Int32Value(), 101);
17118 THREADED_TEST(StackTrace) {
17119 LocalContext context;
17120 v8::HandleScope scope(context->GetIsolate());
17121 v8::TryCatch try_catch;
17122 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17123 v8::Handle<v8::String> src =
17124 v8::String::NewFromUtf8(context->GetIsolate(), source);
17125 v8::Handle<v8::String> origin =
17126 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17127 v8::Script::New(src, origin)->Run();
17128 CHECK(try_catch.HasCaught());
17129 v8::String::Utf8Value stack(try_catch.StackTrace());
17130 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17134 // Checks that a StackFrame has certain expected values.
17135 void checkStackFrame(const char* expected_script_name,
17136 const char* expected_func_name, int expected_line_number,
17137 int expected_column, bool is_eval, bool is_constructor,
17138 v8::Handle<v8::StackFrame> frame) {
17139 v8::HandleScope scope(CcTest::isolate());
17140 v8::String::Utf8Value func_name(frame->GetFunctionName());
17141 v8::String::Utf8Value script_name(frame->GetScriptName());
17142 if (*script_name == NULL) {
17143 // The situation where there is no associated script, like for evals.
17144 CHECK(expected_script_name == NULL);
17146 CHECK(strstr(*script_name, expected_script_name) != NULL);
17148 CHECK(strstr(*func_name, expected_func_name) != NULL);
17149 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17150 CHECK_EQ(expected_column, frame->GetColumn());
17151 CHECK_EQ(is_eval, frame->IsEval());
17152 CHECK_EQ(is_constructor, frame->IsConstructor());
17156 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17157 v8::HandleScope scope(args.GetIsolate());
17158 const char* origin = "capture-stack-trace-test";
17159 const int kOverviewTest = 1;
17160 const int kDetailedTest = 2;
17162 ASSERT(args.Length() == 1);
17164 int testGroup = args[0]->Int32Value();
17165 if (testGroup == kOverviewTest) {
17166 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17167 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17168 CHECK_EQ(4, stackTrace->GetFrameCount());
17169 checkStackFrame(origin, "bar", 2, 10, false, false,
17170 stackTrace->GetFrame(0));
17171 checkStackFrame(origin, "foo", 6, 3, false, false,
17172 stackTrace->GetFrame(1));
17173 // This is the source string inside the eval which has the call to foo.
17174 checkStackFrame(NULL, "", 1, 5, false, false,
17175 stackTrace->GetFrame(2));
17176 // The last frame is an anonymous function which has the initial eval call.
17177 checkStackFrame(origin, "", 8, 7, false, false,
17178 stackTrace->GetFrame(3));
17180 CHECK(stackTrace->AsArray()->IsArray());
17181 } else if (testGroup == kDetailedTest) {
17182 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17183 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17184 CHECK_EQ(4, stackTrace->GetFrameCount());
17185 checkStackFrame(origin, "bat", 4, 22, false, false,
17186 stackTrace->GetFrame(0));
17187 checkStackFrame(origin, "baz", 8, 3, false, true,
17188 stackTrace->GetFrame(1));
17189 #ifdef ENABLE_DEBUGGER_SUPPORT
17190 bool is_eval = true;
17191 #else // ENABLE_DEBUGGER_SUPPORT
17192 bool is_eval = false;
17193 #endif // ENABLE_DEBUGGER_SUPPORT
17195 // This is the source string inside the eval which has the call to baz.
17196 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17197 stackTrace->GetFrame(2));
17198 // The last frame is an anonymous function which has the initial eval call.
17199 checkStackFrame(origin, "", 10, 1, false, false,
17200 stackTrace->GetFrame(3));
17202 CHECK(stackTrace->AsArray()->IsArray());
17207 // Tests the C++ StackTrace API.
17208 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17209 // THREADED_TEST(CaptureStackTrace) {
17210 TEST(CaptureStackTrace) {
17211 v8::Isolate* isolate = CcTest::isolate();
17212 v8::HandleScope scope(isolate);
17213 v8::Handle<v8::String> origin =
17214 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17215 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17216 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17217 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17218 LocalContext context(0, templ);
17220 // Test getting OVERVIEW information. Should ignore information that is not
17221 // script name, function name, line number, and column offset.
17222 const char *overview_source =
17223 "function bar() {\n"
17224 " var y; AnalyzeStackInNativeCode(1);\n"
17226 "function foo() {\n"
17230 "var x;eval('new foo();');";
17231 v8::Handle<v8::String> overview_src =
17232 v8::String::NewFromUtf8(isolate, overview_source);
17233 v8::Handle<Value> overview_result(
17234 v8::Script::New(overview_src, origin)->Run());
17235 CHECK(!overview_result.IsEmpty());
17236 CHECK(overview_result->IsObject());
17238 // Test getting DETAILED information.
17239 const char *detailed_source =
17240 "function bat() {AnalyzeStackInNativeCode(2);\n"
17243 "function baz() {\n"
17246 "eval('new baz();');";
17247 v8::Handle<v8::String> detailed_src =
17248 v8::String::NewFromUtf8(isolate, detailed_source);
17249 // Make the script using a non-zero line and column offset.
17250 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17251 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17252 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17253 v8::Handle<v8::Script> detailed_script(
17254 v8::Script::New(detailed_src, &detailed_origin));
17255 v8::Handle<Value> detailed_result(detailed_script->Run());
17256 CHECK(!detailed_result.IsEmpty());
17257 CHECK(detailed_result->IsObject());
17261 static void StackTraceForUncaughtExceptionListener(
17262 v8::Handle<v8::Message> message,
17263 v8::Handle<Value>) {
17264 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17265 CHECK_EQ(2, stack_trace->GetFrameCount());
17266 checkStackFrame("origin", "foo", 2, 3, false, false,
17267 stack_trace->GetFrame(0));
17268 checkStackFrame("origin", "bar", 5, 3, false, false,
17269 stack_trace->GetFrame(1));
17273 TEST(CaptureStackTraceForUncaughtException) {
17276 v8::HandleScope scope(env->GetIsolate());
17277 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17278 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17280 Script::Compile(v8_str("function foo() {\n"
17283 "function bar() {\n"
17286 v8_str("origin"))->Run();
17287 v8::Local<v8::Object> global = env->Global();
17288 Local<Value> trouble = global->Get(v8_str("bar"));
17289 CHECK(trouble->IsFunction());
17290 Function::Cast(*trouble)->Call(global, 0, NULL);
17291 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17292 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17296 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17298 v8::HandleScope scope(env->GetIsolate());
17299 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17301 v8::StackTrace::kDetailed);
17304 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17305 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17306 " 'isConstructor'];\n"
17307 "for (var i = 0; i < setters.length; i++) {\n"
17308 " var prop = setters[i];\n"
17309 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17311 CompileRun("throw 'exception';");
17312 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17316 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17317 v8::Handle<v8::Value> data) {
17318 // Use the frame where JavaScript is called from.
17319 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17320 CHECK(!stack_trace.IsEmpty());
17321 int frame_count = stack_trace->GetFrameCount();
17322 CHECK_EQ(3, frame_count);
17323 int line_number[] = {1, 2, 5};
17324 for (int i = 0; i < frame_count; i++) {
17325 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17330 // Test that we only return the stack trace at the site where the exception
17331 // is first thrown (not where it is rethrown).
17332 TEST(RethrowStackTrace) {
17334 v8::HandleScope scope(env->GetIsolate());
17335 // We make sure that
17336 // - the stack trace of the ReferenceError in g() is reported.
17337 // - the stack trace is not overwritten when e1 is rethrown by t().
17338 // - the stack trace of e2 does not overwrite that of e1.
17339 const char* source =
17340 "function g() { error; } \n"
17341 "function f() { g(); } \n"
17342 "function t(e) { throw e; } \n"
17345 "} catch (e1) { \n"
17348 " } catch (e2) { \n"
17352 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17353 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17354 CompileRun(source);
17355 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17356 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17360 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17361 v8::Handle<v8::Value> data) {
17362 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17363 CHECK(!stack_trace.IsEmpty());
17364 int frame_count = stack_trace->GetFrameCount();
17365 CHECK_EQ(2, frame_count);
17366 int line_number[] = {3, 7};
17367 for (int i = 0; i < frame_count; i++) {
17368 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17373 // Test that we do not recognize identity for primitive exceptions.
17374 TEST(RethrowPrimitiveStackTrace) {
17376 v8::HandleScope scope(env->GetIsolate());
17377 // We do not capture stack trace for non Error objects on creation time.
17378 // Instead, we capture the stack trace on last throw.
17379 const char* source =
17380 "function g() { throw 404; } \n"
17381 "function f() { g(); } \n"
17382 "function t(e) { throw e; } \n"
17385 "} catch (e1) { \n"
17388 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17389 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17390 CompileRun(source);
17391 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17392 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17396 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17397 v8::Handle<v8::Value> data) {
17398 // Use the frame where JavaScript is called from.
17399 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17400 CHECK(!stack_trace.IsEmpty());
17401 CHECK_EQ(1, stack_trace->GetFrameCount());
17402 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17406 // Test that the stack trace is captured when the error object is created and
17407 // not where it is thrown.
17408 TEST(RethrowExistingStackTrace) {
17410 v8::HandleScope scope(env->GetIsolate());
17411 const char* source =
17412 "var e = new Error(); \n"
17414 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17415 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17416 CompileRun(source);
17417 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17418 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17422 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17423 v8::Handle<v8::Value> data) {
17424 // Use the frame where JavaScript is called from.
17425 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17426 CHECK(!stack_trace.IsEmpty());
17427 CHECK_EQ(1, stack_trace->GetFrameCount());
17428 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17432 // Test that the stack trace is captured where the bogus Error object is thrown.
17433 TEST(RethrowBogusErrorStackTrace) {
17435 v8::HandleScope scope(env->GetIsolate());
17436 const char* source =
17437 "var e = {__proto__: new Error()} \n"
17439 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17440 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17441 CompileRun(source);
17442 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17443 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17447 void AnalyzeStackOfEvalWithSourceURL(
17448 const v8::FunctionCallbackInfo<v8::Value>& args) {
17449 v8::HandleScope scope(args.GetIsolate());
17450 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17451 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17452 CHECK_EQ(5, stackTrace->GetFrameCount());
17453 v8::Handle<v8::String> url = v8_str("eval_url");
17454 for (int i = 0; i < 3; i++) {
17455 v8::Handle<v8::String> name =
17456 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17457 CHECK(!name.IsEmpty());
17458 CHECK_EQ(url, name);
17463 TEST(SourceURLInStackTrace) {
17464 v8::Isolate* isolate = CcTest::isolate();
17465 v8::HandleScope scope(isolate);
17466 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17467 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17468 v8::FunctionTemplate::New(isolate,
17469 AnalyzeStackOfEvalWithSourceURL));
17470 LocalContext context(0, templ);
17472 const char *source =
17473 "function outer() {\n"
17474 "function bar() {\n"
17475 " AnalyzeStackOfEvalWithSourceURL();\n"
17477 "function foo() {\n"
17483 "eval('(' + outer +')()%s');";
17485 i::ScopedVector<char> code(1024);
17486 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17487 CHECK(CompileRun(code.start())->IsUndefined());
17488 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17489 CHECK(CompileRun(code.start())->IsUndefined());
17493 static int scriptIdInStack[2];
17495 void AnalyzeScriptIdInStack(
17496 const v8::FunctionCallbackInfo<v8::Value>& args) {
17497 v8::HandleScope scope(args.GetIsolate());
17498 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17499 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17500 CHECK_EQ(2, stackTrace->GetFrameCount());
17501 for (int i = 0; i < 2; i++) {
17502 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17507 TEST(ScriptIdInStackTrace) {
17508 v8::Isolate* isolate = CcTest::isolate();
17509 v8::HandleScope scope(isolate);
17510 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17511 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17512 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17513 LocalContext context(0, templ);
17515 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17517 "function foo() {\n"
17518 " AnalyzeScriptIdInStack();"
17521 v8::ScriptOrigin origin =
17522 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"));
17523 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17525 for (int i = 0; i < 2; i++) {
17526 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17527 CHECK_EQ(scriptIdInStack[i], script->GetId());
17532 void AnalyzeStackOfInlineScriptWithSourceURL(
17533 const v8::FunctionCallbackInfo<v8::Value>& args) {
17534 v8::HandleScope scope(args.GetIsolate());
17535 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17536 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17537 CHECK_EQ(4, stackTrace->GetFrameCount());
17538 v8::Handle<v8::String> url = v8_str("url");
17539 for (int i = 0; i < 3; i++) {
17540 v8::Handle<v8::String> name =
17541 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17542 CHECK(!name.IsEmpty());
17543 CHECK_EQ(url, name);
17548 TEST(InlineScriptWithSourceURLInStackTrace) {
17549 v8::Isolate* isolate = CcTest::isolate();
17550 v8::HandleScope scope(isolate);
17551 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17552 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17553 v8::FunctionTemplate::New(
17554 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17555 LocalContext context(0, templ);
17557 const char *source =
17558 "function outer() {\n"
17559 "function bar() {\n"
17560 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17562 "function foo() {\n"
17570 i::ScopedVector<char> code(1024);
17571 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17572 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17573 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17574 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17578 void AnalyzeStackOfDynamicScriptWithSourceURL(
17579 const v8::FunctionCallbackInfo<v8::Value>& args) {
17580 v8::HandleScope scope(args.GetIsolate());
17581 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17582 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17583 CHECK_EQ(4, stackTrace->GetFrameCount());
17584 v8::Handle<v8::String> url = v8_str("source_url");
17585 for (int i = 0; i < 3; i++) {
17586 v8::Handle<v8::String> name =
17587 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17588 CHECK(!name.IsEmpty());
17589 CHECK_EQ(url, name);
17594 TEST(DynamicWithSourceURLInStackTrace) {
17595 v8::Isolate* isolate = CcTest::isolate();
17596 v8::HandleScope scope(isolate);
17597 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17598 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17599 v8::FunctionTemplate::New(
17600 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17601 LocalContext context(0, templ);
17603 const char *source =
17604 "function outer() {\n"
17605 "function bar() {\n"
17606 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17608 "function foo() {\n"
17616 i::ScopedVector<char> code(1024);
17617 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17618 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17619 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17620 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17624 static void CreateGarbageInOldSpace() {
17625 i::Factory* factory = CcTest::i_isolate()->factory();
17626 v8::HandleScope scope(CcTest::isolate());
17627 i::AlwaysAllocateScope always_allocate;
17628 for (int i = 0; i < 1000; i++) {
17629 factory->NewFixedArray(1000, i::TENURED);
17634 // Test that idle notification can be handled and eventually returns true.
17635 TEST(IdleNotification) {
17636 const intptr_t MB = 1024 * 1024;
17638 v8::HandleScope scope(env->GetIsolate());
17639 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17640 CreateGarbageInOldSpace();
17641 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17642 CHECK_GT(size_with_garbage, initial_size + MB);
17643 bool finished = false;
17644 for (int i = 0; i < 200 && !finished; i++) {
17645 finished = v8::V8::IdleNotification();
17647 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17649 CHECK_LT(final_size, initial_size + 1);
17653 // Test that idle notification can be handled and eventually collects garbage.
17654 TEST(IdleNotificationWithSmallHint) {
17655 const intptr_t MB = 1024 * 1024;
17656 const int IdlePauseInMs = 900;
17658 v8::HandleScope scope(env->GetIsolate());
17659 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17660 CreateGarbageInOldSpace();
17661 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17662 CHECK_GT(size_with_garbage, initial_size + MB);
17663 bool finished = false;
17664 for (int i = 0; i < 200 && !finished; i++) {
17665 finished = v8::V8::IdleNotification(IdlePauseInMs);
17667 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17669 CHECK_LT(final_size, initial_size + 1);
17673 // Test that idle notification can be handled and eventually collects garbage.
17674 TEST(IdleNotificationWithLargeHint) {
17675 const intptr_t MB = 1024 * 1024;
17676 const int IdlePauseInMs = 900;
17678 v8::HandleScope scope(env->GetIsolate());
17679 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17680 CreateGarbageInOldSpace();
17681 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17682 CHECK_GT(size_with_garbage, initial_size + MB);
17683 bool finished = false;
17684 for (int i = 0; i < 200 && !finished; i++) {
17685 finished = v8::V8::IdleNotification(IdlePauseInMs);
17687 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17689 CHECK_LT(final_size, initial_size + 1);
17693 TEST(Regress2107) {
17694 const intptr_t MB = 1024 * 1024;
17695 const int kShortIdlePauseInMs = 100;
17696 const int kLongIdlePauseInMs = 1000;
17698 v8::Isolate* isolate = env->GetIsolate();
17699 v8::HandleScope scope(env->GetIsolate());
17700 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17701 // Send idle notification to start a round of incremental GCs.
17702 v8::V8::IdleNotification(kShortIdlePauseInMs);
17703 // Emulate 7 page reloads.
17704 for (int i = 0; i < 7; i++) {
17706 v8::HandleScope inner_scope(env->GetIsolate());
17707 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17709 CreateGarbageInOldSpace();
17712 v8::V8::ContextDisposedNotification();
17713 v8::V8::IdleNotification(kLongIdlePauseInMs);
17715 // Create garbage and check that idle notification still collects it.
17716 CreateGarbageInOldSpace();
17717 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17718 CHECK_GT(size_with_garbage, initial_size + MB);
17719 bool finished = false;
17720 for (int i = 0; i < 200 && !finished; i++) {
17721 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17723 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17724 CHECK_LT(final_size, initial_size + 1);
17728 TEST(Regress2333) {
17730 for (int i = 0; i < 3; i++) {
17731 CcTest::heap()->PerformScavenge();
17735 static uint32_t* stack_limit;
17737 static void GetStackLimitCallback(
17738 const v8::FunctionCallbackInfo<v8::Value>& args) {
17739 stack_limit = reinterpret_cast<uint32_t*>(
17740 CcTest::i_isolate()->stack_guard()->real_climit());
17744 // Uses the address of a local variable to determine the stack top now.
17745 // Given a size, returns an address that is that far from the current
17747 static uint32_t* ComputeStackLimit(uint32_t size) {
17748 uint32_t* answer = &size - (size / sizeof(size));
17749 // If the size is very large and the stack is very near the bottom of
17750 // memory then the calculation above may wrap around and give an address
17751 // that is above the (downwards-growing) stack. In that case we return
17752 // a very low address.
17753 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17758 // We need at least 165kB for an x64 debug build with clang and ASAN.
17759 static const int stack_breathing_room = 256 * i::KB;
17762 TEST(SetResourceConstraints) {
17763 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17765 // Set stack limit.
17766 v8::ResourceConstraints constraints;
17767 constraints.set_stack_limit(set_limit);
17768 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17770 // Execute a script.
17772 v8::HandleScope scope(env->GetIsolate());
17773 Local<v8::FunctionTemplate> fun_templ =
17774 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17775 Local<Function> fun = fun_templ->GetFunction();
17776 env->Global()->Set(v8_str("get_stack_limit"), fun);
17777 CompileRun("get_stack_limit();");
17779 CHECK(stack_limit == set_limit);
17783 TEST(SetResourceConstraintsInThread) {
17784 uint32_t* set_limit;
17786 v8::Locker locker(CcTest::isolate());
17787 set_limit = ComputeStackLimit(stack_breathing_room);
17789 // Set stack limit.
17790 v8::ResourceConstraints constraints;
17791 constraints.set_stack_limit(set_limit);
17792 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17794 // Execute a script.
17795 v8::HandleScope scope(CcTest::isolate());
17797 Local<v8::FunctionTemplate> fun_templ =
17798 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17799 Local<Function> fun = fun_templ->GetFunction();
17800 env->Global()->Set(v8_str("get_stack_limit"), fun);
17801 CompileRun("get_stack_limit();");
17803 CHECK(stack_limit == set_limit);
17806 v8::Locker locker(CcTest::isolate());
17807 CHECK(stack_limit == set_limit);
17812 THREADED_TEST(GetHeapStatistics) {
17814 v8::HandleScope scope(c1->GetIsolate());
17815 v8::HeapStatistics heap_statistics;
17816 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17817 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17818 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17819 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17820 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17824 class VisitorImpl : public v8::ExternalResourceVisitor {
17826 explicit VisitorImpl(TestResource** resource) {
17827 for (int i = 0; i < 4; i++) {
17828 resource_[i] = resource[i];
17829 found_resource_[i] = false;
17832 virtual ~VisitorImpl() {}
17833 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17834 if (!string->IsExternal()) {
17835 CHECK(string->IsExternalAscii());
17838 v8::String::ExternalStringResource* resource =
17839 string->GetExternalStringResource();
17841 for (int i = 0; i < 4; i++) {
17842 if (resource_[i] == resource) {
17843 CHECK(!found_resource_[i]);
17844 found_resource_[i] = true;
17848 void CheckVisitedResources() {
17849 for (int i = 0; i < 4; i++) {
17850 CHECK(found_resource_[i]);
17855 v8::String::ExternalStringResource* resource_[4];
17856 bool found_resource_[4];
17860 TEST(VisitExternalStrings) {
17862 v8::HandleScope scope(env->GetIsolate());
17863 const char* string = "Some string";
17864 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17865 TestResource* resource[4];
17866 resource[0] = new TestResource(two_byte_string);
17867 v8::Local<v8::String> string0 =
17868 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17869 resource[1] = new TestResource(two_byte_string);
17870 v8::Local<v8::String> string1 =
17871 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17873 // Externalized symbol.
17874 resource[2] = new TestResource(two_byte_string);
17875 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17876 env->GetIsolate(), string, v8::String::kInternalizedString);
17877 CHECK(string2->MakeExternal(resource[2]));
17879 // Symbolized External.
17880 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17881 v8::Local<v8::String> string3 =
17882 v8::String::NewExternal(env->GetIsolate(), resource[3]);
17883 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17884 // Turn into a symbol.
17885 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17886 CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17887 CHECK(string3_i->IsInternalizedString());
17889 // We need to add usages for string* to avoid warnings in GCC 4.7
17890 CHECK(string0->IsExternal());
17891 CHECK(string1->IsExternal());
17892 CHECK(string2->IsExternal());
17893 CHECK(string3->IsExternal());
17895 VisitorImpl visitor(resource);
17896 v8::V8::VisitExternalResources(&visitor);
17897 visitor.CheckVisitedResources();
17901 TEST(ExternalStringCollectedAtTearDown) {
17903 v8::Isolate* isolate = v8::Isolate::New();
17904 { v8::Isolate::Scope isolate_scope(isolate);
17905 v8::HandleScope handle_scope(isolate);
17906 const char* s = "One string to test them all, one string to find them.";
17907 TestAsciiResource* inscription =
17908 new TestAsciiResource(i::StrDup(s), &destroyed);
17909 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17910 // Ring is still alive. Orcs are roaming freely across our lands.
17911 CHECK_EQ(0, destroyed);
17915 isolate->Dispose();
17916 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17917 CHECK_EQ(1, destroyed);
17921 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17923 v8::Isolate* isolate = v8::Isolate::New();
17924 { v8::Isolate::Scope isolate_scope(isolate);
17925 LocalContext env(isolate);
17926 v8::HandleScope handle_scope(isolate);
17927 CompileRun("var ring = 'One string to test them all';");
17928 const char* s = "One string to test them all";
17929 TestAsciiResource* inscription =
17930 new TestAsciiResource(i::StrDup(s), &destroyed);
17931 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17932 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17933 ring->MakeExternal(inscription);
17934 // Ring is still alive. Orcs are roaming freely across our lands.
17935 CHECK_EQ(0, destroyed);
17939 isolate->Dispose();
17940 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17941 CHECK_EQ(1, destroyed);
17945 TEST(ExternalInternalizedStringCollectedAtGC) {
17947 { LocalContext env;
17948 v8::HandleScope handle_scope(env->GetIsolate());
17949 CompileRun("var ring = 'One string to test them all';");
17950 const char* s = "One string to test them all";
17951 TestAsciiResource* inscription =
17952 new TestAsciiResource(i::StrDup(s), &destroyed);
17953 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17954 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17955 ring->MakeExternal(inscription);
17956 // Ring is still alive. Orcs are roaming freely across our lands.
17957 CHECK_EQ(0, destroyed);
17961 // Garbage collector deals swift blows to evil.
17962 CcTest::i_isolate()->compilation_cache()->Clear();
17963 CcTest::heap()->CollectAllAvailableGarbage();
17965 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17966 CHECK_EQ(1, destroyed);
17970 static double DoubleFromBits(uint64_t value) {
17972 i::OS::MemCopy(&target, &value, sizeof(target));
17977 static uint64_t DoubleToBits(double value) {
17979 i::OS::MemCopy(&target, &value, sizeof(target));
17984 static double DoubleToDateTime(double input) {
17985 double date_limit = 864e13;
17986 if (std::isnan(input) || input < -date_limit || input > date_limit) {
17987 return i::OS::nan_value();
17989 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17993 // We don't have a consistent way to write 64-bit constants syntactically, so we
17994 // split them into two 32-bit constants and combine them programmatically.
17995 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17996 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18000 THREADED_TEST(QuietSignalingNaNs) {
18001 LocalContext context;
18002 v8::Isolate* isolate = context->GetIsolate();
18003 v8::HandleScope scope(isolate);
18004 v8::TryCatch try_catch;
18006 // Special double values.
18007 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18008 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18009 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18010 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18011 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18012 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18013 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18015 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18016 // on either side of the epoch.
18017 double date_limit = 864e13;
18019 double test_values[] = {
18041 int num_test_values = 20;
18043 for (int i = 0; i < num_test_values; i++) {
18044 double test_value = test_values[i];
18046 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18047 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18048 double stored_number = number->NumberValue();
18049 if (!std::isnan(test_value)) {
18050 CHECK_EQ(test_value, stored_number);
18052 uint64_t stored_bits = DoubleToBits(stored_number);
18053 // Check if quiet nan (bits 51..62 all set).
18054 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18055 // Most significant fraction bit for quiet nan is set to 0
18056 // on MIPS architecture. Allowed by IEEE-754.
18057 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18059 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18063 // Check that Date::New preserves non-NaNs in the date range and
18065 v8::Handle<v8::Value> date =
18066 v8::Date::New(isolate, test_value);
18067 double expected_stored_date = DoubleToDateTime(test_value);
18068 double stored_date = date->NumberValue();
18069 if (!std::isnan(expected_stored_date)) {
18070 CHECK_EQ(expected_stored_date, stored_date);
18072 uint64_t stored_bits = DoubleToBits(stored_date);
18073 // Check if quiet nan (bits 51..62 all set).
18074 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18075 // Most significant fraction bit for quiet nan is set to 0
18076 // on MIPS architecture. Allowed by IEEE-754.
18077 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18079 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18086 static void SpaghettiIncident(
18087 const v8::FunctionCallbackInfo<v8::Value>& args) {
18088 v8::HandleScope scope(args.GetIsolate());
18090 v8::Handle<v8::String> str(args[0]->ToString());
18092 if (tc.HasCaught())
18097 // Test that an exception can be propagated down through a spaghetti
18098 // stack using ReThrow.
18099 THREADED_TEST(SpaghettiStackReThrow) {
18100 v8::Isolate* isolate = CcTest::isolate();
18101 v8::HandleScope scope(isolate);
18102 LocalContext context;
18103 context->Global()->Set(
18104 v8::String::NewFromUtf8(isolate, "s"),
18105 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18106 v8::TryCatch try_catch;
18110 " toString: function () {"
18120 CHECK(try_catch.HasCaught());
18121 v8::String::Utf8Value value(try_catch.Exception());
18122 CHECK_EQ(0, strcmp(*value, "Hey!"));
18127 v8::V8::Initialize();
18128 v8::Isolate* isolate = CcTest::isolate();
18129 v8::HandleScope scope(isolate);
18130 v8::Local<Context> other_context;
18133 // Create a context used to keep the code from aging in the compilation
18135 other_context = Context::New(isolate);
18137 // Context-dependent context data creates reference from the compilation
18138 // cache to the global object.
18139 const char* source_simple = "1";
18141 v8::HandleScope scope(isolate);
18142 v8::Local<Context> context = Context::New(isolate);
18145 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18146 context->SetEmbedderData(0, obj);
18147 CompileRun(source_simple);
18150 v8::V8::ContextDisposedNotification();
18151 for (gc_count = 1; gc_count < 10; gc_count++) {
18152 other_context->Enter();
18153 CompileRun(source_simple);
18154 other_context->Exit();
18155 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18156 if (GetGlobalObjectsCount() == 1) break;
18158 CHECK_GE(2, gc_count);
18159 CHECK_EQ(1, GetGlobalObjectsCount());
18161 // Eval in a function creates reference from the compilation cache to the
18163 const char* source_eval = "function f(){eval('1')}; f()";
18165 v8::HandleScope scope(isolate);
18166 v8::Local<Context> context = Context::New(isolate);
18169 CompileRun(source_eval);
18172 v8::V8::ContextDisposedNotification();
18173 for (gc_count = 1; gc_count < 10; gc_count++) {
18174 other_context->Enter();
18175 CompileRun(source_eval);
18176 other_context->Exit();
18177 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18178 if (GetGlobalObjectsCount() == 1) break;
18180 CHECK_GE(2, gc_count);
18181 CHECK_EQ(1, GetGlobalObjectsCount());
18183 // Looking up the line number for an exception creates reference from the
18184 // compilation cache to the global object.
18185 const char* source_exception = "function f(){throw 1;} f()";
18187 v8::HandleScope scope(isolate);
18188 v8::Local<Context> context = Context::New(isolate);
18191 v8::TryCatch try_catch;
18192 CompileRun(source_exception);
18193 CHECK(try_catch.HasCaught());
18194 v8::Handle<v8::Message> message = try_catch.Message();
18195 CHECK(!message.IsEmpty());
18196 CHECK_EQ(1, message->GetLineNumber());
18199 v8::V8::ContextDisposedNotification();
18200 for (gc_count = 1; gc_count < 10; gc_count++) {
18201 other_context->Enter();
18202 CompileRun(source_exception);
18203 other_context->Exit();
18204 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18205 if (GetGlobalObjectsCount() == 1) break;
18207 CHECK_GE(2, gc_count);
18208 CHECK_EQ(1, GetGlobalObjectsCount());
18210 v8::V8::ContextDisposedNotification();
18214 THREADED_TEST(ScriptOrigin) {
18216 v8::HandleScope scope(env->GetIsolate());
18217 v8::ScriptOrigin origin =
18218 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18219 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18220 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18221 v8::Script::Compile(script, &origin)->Run();
18222 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18223 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18224 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18225 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18227 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18228 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18229 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18231 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18232 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18233 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18237 THREADED_TEST(FunctionGetInferredName) {
18239 v8::HandleScope scope(env->GetIsolate());
18240 v8::ScriptOrigin origin =
18241 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18242 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18244 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18245 v8::Script::Compile(script, &origin)->Run();
18246 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18247 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18248 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18252 THREADED_TEST(FunctionGetDisplayName) {
18254 v8::HandleScope scope(env->GetIsolate());
18255 const char* code = "var error = false;"
18256 "function a() { this.x = 1; };"
18257 "a.displayName = 'display_a';"
18258 "var b = (function() {"
18259 " var f = function() { this.x = 2; };"
18260 " f.displayName = 'display_b';"
18263 "var c = function() {};"
18264 "c.__defineGetter__('displayName', function() {"
18266 " throw new Error();"
18269 "d.__defineGetter__('displayName', function() {"
18271 " return 'wrong_display_name';"
18274 "e.displayName = 'wrong_display_name';"
18275 "e.__defineSetter__('displayName', function() {"
18277 " throw new Error();"
18280 "f.displayName = { 'foo': 6, toString: function() {"
18282 " return 'wrong_display_name';"
18284 "var g = function() {"
18285 " arguments.callee.displayName = 'set_in_runtime';"
18288 v8::ScriptOrigin origin =
18289 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18290 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18292 v8::Local<v8::Value> error =
18293 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18294 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18295 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18296 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18297 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18298 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18299 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18300 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18301 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18302 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18303 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18304 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18305 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18306 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18307 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18308 CHECK_EQ(false, error->BooleanValue());
18309 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18310 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18311 CHECK(c->GetDisplayName()->IsUndefined());
18312 CHECK(d->GetDisplayName()->IsUndefined());
18313 CHECK(e->GetDisplayName()->IsUndefined());
18314 CHECK(f->GetDisplayName()->IsUndefined());
18315 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18319 THREADED_TEST(ScriptLineNumber) {
18321 v8::HandleScope scope(env->GetIsolate());
18322 v8::ScriptOrigin origin =
18323 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18324 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18325 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18326 v8::Script::Compile(script, &origin)->Run();
18327 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18328 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18329 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18330 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18331 CHECK_EQ(0, f->GetScriptLineNumber());
18332 CHECK_EQ(2, g->GetScriptLineNumber());
18336 THREADED_TEST(ScriptColumnNumber) {
18338 v8::Isolate* isolate = env->GetIsolate();
18339 v8::HandleScope scope(isolate);
18340 v8::ScriptOrigin origin =
18341 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18342 v8::Integer::New(isolate, 3),
18343 v8::Integer::New(isolate, 2));
18344 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18345 isolate, "function foo() {}\n\n function bar() {}");
18346 v8::Script::Compile(script, &origin)->Run();
18347 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18348 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18349 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18350 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18351 CHECK_EQ(14, foo->GetScriptColumnNumber());
18352 CHECK_EQ(17, bar->GetScriptColumnNumber());
18356 THREADED_TEST(FunctionIsBuiltin) {
18358 v8::Isolate* isolate = env->GetIsolate();
18359 v8::HandleScope scope(isolate);
18360 v8::Local<v8::Function> f;
18361 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18362 CHECK(f->IsBuiltin());
18363 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18364 CHECK(f->IsBuiltin());
18365 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18366 CHECK(f->IsBuiltin());
18367 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18368 CHECK(f->IsBuiltin());
18369 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18370 CHECK(!f->IsBuiltin());
18374 THREADED_TEST(FunctionGetScriptId) {
18376 v8::Isolate* isolate = env->GetIsolate();
18377 v8::HandleScope scope(isolate);
18378 v8::ScriptOrigin origin =
18379 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18380 v8::Integer::New(isolate, 3),
18381 v8::Integer::New(isolate, 2));
18382 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18383 isolate, "function foo() {}\n\n function bar() {}");
18384 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18386 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18387 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18388 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18389 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18390 CHECK_EQ(script->GetId(), foo->ScriptId());
18391 CHECK_EQ(script->GetId(), bar->ScriptId());
18395 THREADED_TEST(FunctionGetBoundFunction) {
18397 v8::HandleScope scope(env->GetIsolate());
18398 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18399 env->GetIsolate(), "test"));
18400 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18402 "var a = new Object();\n"
18404 "function f () { return this.x };\n"
18405 "var g = f.bind(a);\n"
18407 v8::Script::Compile(script, &origin)->Run();
18408 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18409 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18410 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18411 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18412 CHECK(g->GetBoundFunction()->IsFunction());
18413 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18414 g->GetBoundFunction());
18415 CHECK_EQ(f->GetName(), original_function->GetName());
18416 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18417 CHECK_EQ(f->GetScriptColumnNumber(),
18418 original_function->GetScriptColumnNumber());
18422 static void GetterWhichReturns42(
18423 Local<String> name,
18424 const v8::PropertyCallbackInfo<v8::Value>& info) {
18425 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18426 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18427 info.GetReturnValue().Set(v8_num(42));
18431 static void SetterWhichSetsYOnThisTo23(
18432 Local<String> name,
18433 Local<Value> value,
18434 const v8::PropertyCallbackInfo<void>& info) {
18435 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18436 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18437 info.This()->Set(v8_str("y"), v8_num(23));
18441 void FooGetInterceptor(Local<String> name,
18442 const v8::PropertyCallbackInfo<v8::Value>& info) {
18443 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18444 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18445 if (!name->Equals(v8_str("foo"))) return;
18446 info.GetReturnValue().Set(v8_num(42));
18450 void FooSetInterceptor(Local<String> name,
18451 Local<Value> value,
18452 const v8::PropertyCallbackInfo<v8::Value>& info) {
18453 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18454 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18455 if (!name->Equals(v8_str("foo"))) return;
18456 info.This()->Set(v8_str("y"), v8_num(23));
18457 info.GetReturnValue().Set(v8_num(23));
18461 TEST(SetterOnConstructorPrototype) {
18462 v8::Isolate* isolate = CcTest::isolate();
18463 v8::HandleScope scope(isolate);
18464 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18465 templ->SetAccessor(v8_str("x"),
18466 GetterWhichReturns42,
18467 SetterWhichSetsYOnThisTo23);
18468 LocalContext context;
18469 context->Global()->Set(v8_str("P"), templ->NewInstance());
18470 CompileRun("function C1() {"
18473 "C1.prototype = P;"
18477 "C2.prototype = { };"
18478 "C2.prototype.__proto__ = P;");
18480 v8::Local<v8::Script> script;
18481 script = v8::Script::Compile(v8_str("new C1();"));
18482 for (int i = 0; i < 10; i++) {
18483 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18484 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18485 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18488 script = v8::Script::Compile(v8_str("new C2();"));
18489 for (int i = 0; i < 10; i++) {
18490 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18491 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18492 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18497 static void NamedPropertyGetterWhichReturns42(
18498 Local<String> name,
18499 const v8::PropertyCallbackInfo<v8::Value>& info) {
18500 info.GetReturnValue().Set(v8_num(42));
18504 static void NamedPropertySetterWhichSetsYOnThisTo23(
18505 Local<String> name,
18506 Local<Value> value,
18507 const v8::PropertyCallbackInfo<v8::Value>& info) {
18508 if (name->Equals(v8_str("x"))) {
18509 info.This()->Set(v8_str("y"), v8_num(23));
18514 THREADED_TEST(InterceptorOnConstructorPrototype) {
18515 v8::Isolate* isolate = CcTest::isolate();
18516 v8::HandleScope scope(isolate);
18517 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18518 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18519 NamedPropertySetterWhichSetsYOnThisTo23);
18520 LocalContext context;
18521 context->Global()->Set(v8_str("P"), templ->NewInstance());
18522 CompileRun("function C1() {"
18525 "C1.prototype = P;"
18529 "C2.prototype = { };"
18530 "C2.prototype.__proto__ = P;");
18532 v8::Local<v8::Script> script;
18533 script = v8::Script::Compile(v8_str("new C1();"));
18534 for (int i = 0; i < 10; i++) {
18535 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18536 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18537 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18540 script = v8::Script::Compile(v8_str("new C2();"));
18541 for (int i = 0; i < 10; i++) {
18542 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18543 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18544 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18550 const char* source = "function C1() {"
18553 "C1.prototype = P;";
18555 LocalContext context;
18556 v8::Isolate* isolate = context->GetIsolate();
18557 v8::HandleScope scope(isolate);
18558 v8::Local<v8::Script> script;
18560 // Use a simple object as prototype.
18561 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18562 prototype->Set(v8_str("y"), v8_num(42));
18563 context->Global()->Set(v8_str("P"), prototype);
18565 // This compile will add the code to the compilation cache.
18566 CompileRun(source);
18568 script = v8::Script::Compile(v8_str("new C1();"));
18569 // Allow enough iterations for the inobject slack tracking logic
18570 // to finalize instance size and install the fast construct stub.
18571 for (int i = 0; i < 256; i++) {
18572 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18573 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18574 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18577 // Use an API object with accessors as prototype.
18578 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18579 templ->SetAccessor(v8_str("x"),
18580 GetterWhichReturns42,
18581 SetterWhichSetsYOnThisTo23);
18582 context->Global()->Set(v8_str("P"), templ->NewInstance());
18584 // This compile will get the code from the compilation cache.
18585 CompileRun(source);
18587 script = v8::Script::Compile(v8_str("new C1();"));
18588 for (int i = 0; i < 10; i++) {
18589 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18590 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18591 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18595 v8::Isolate* gc_callbacks_isolate = NULL;
18596 int prologue_call_count = 0;
18597 int epilogue_call_count = 0;
18598 int prologue_call_count_second = 0;
18599 int epilogue_call_count_second = 0;
18601 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18602 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18603 ++prologue_call_count;
18607 void PrologueCallback(v8::Isolate* isolate,
18609 v8::GCCallbackFlags flags) {
18610 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18611 CHECK_EQ(gc_callbacks_isolate, isolate);
18612 ++prologue_call_count;
18616 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18617 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18618 ++epilogue_call_count;
18622 void EpilogueCallback(v8::Isolate* isolate,
18624 v8::GCCallbackFlags flags) {
18625 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18626 CHECK_EQ(gc_callbacks_isolate, isolate);
18627 ++epilogue_call_count;
18631 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18632 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18633 ++prologue_call_count_second;
18637 void PrologueCallbackSecond(v8::Isolate* isolate,
18639 v8::GCCallbackFlags flags) {
18640 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18641 CHECK_EQ(gc_callbacks_isolate, isolate);
18642 ++prologue_call_count_second;
18646 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18647 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18648 ++epilogue_call_count_second;
18652 void EpilogueCallbackSecond(v8::Isolate* isolate,
18654 v8::GCCallbackFlags flags) {
18655 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18656 CHECK_EQ(gc_callbacks_isolate, isolate);
18657 ++epilogue_call_count_second;
18661 TEST(GCCallbacksOld) {
18662 LocalContext context;
18664 v8::V8::AddGCPrologueCallback(PrologueCallback);
18665 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18666 CHECK_EQ(0, prologue_call_count);
18667 CHECK_EQ(0, epilogue_call_count);
18668 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18669 CHECK_EQ(1, prologue_call_count);
18670 CHECK_EQ(1, epilogue_call_count);
18671 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18672 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18673 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18674 CHECK_EQ(2, prologue_call_count);
18675 CHECK_EQ(2, epilogue_call_count);
18676 CHECK_EQ(1, prologue_call_count_second);
18677 CHECK_EQ(1, epilogue_call_count_second);
18678 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18679 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18680 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18681 CHECK_EQ(2, prologue_call_count);
18682 CHECK_EQ(2, epilogue_call_count);
18683 CHECK_EQ(2, prologue_call_count_second);
18684 CHECK_EQ(2, epilogue_call_count_second);
18685 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18686 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18687 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18688 CHECK_EQ(2, prologue_call_count);
18689 CHECK_EQ(2, epilogue_call_count);
18690 CHECK_EQ(2, prologue_call_count_second);
18691 CHECK_EQ(2, epilogue_call_count_second);
18695 TEST(GCCallbacks) {
18696 LocalContext context;
18697 v8::Isolate* isolate = context->GetIsolate();
18698 gc_callbacks_isolate = isolate;
18699 isolate->AddGCPrologueCallback(PrologueCallback);
18700 isolate->AddGCEpilogueCallback(EpilogueCallback);
18701 CHECK_EQ(0, prologue_call_count);
18702 CHECK_EQ(0, epilogue_call_count);
18703 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18704 CHECK_EQ(1, prologue_call_count);
18705 CHECK_EQ(1, epilogue_call_count);
18706 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18707 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18708 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18709 CHECK_EQ(2, prologue_call_count);
18710 CHECK_EQ(2, epilogue_call_count);
18711 CHECK_EQ(1, prologue_call_count_second);
18712 CHECK_EQ(1, epilogue_call_count_second);
18713 isolate->RemoveGCPrologueCallback(PrologueCallback);
18714 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18715 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18716 CHECK_EQ(2, prologue_call_count);
18717 CHECK_EQ(2, epilogue_call_count);
18718 CHECK_EQ(2, prologue_call_count_second);
18719 CHECK_EQ(2, epilogue_call_count_second);
18720 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18721 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18723 CHECK_EQ(2, prologue_call_count);
18724 CHECK_EQ(2, epilogue_call_count);
18725 CHECK_EQ(2, prologue_call_count_second);
18726 CHECK_EQ(2, epilogue_call_count_second);
18730 THREADED_TEST(AddToJSFunctionResultCache) {
18731 i::FLAG_stress_compaction = false;
18732 i::FLAG_allow_natives_syntax = true;
18733 v8::HandleScope scope(CcTest::isolate());
18735 LocalContext context;
18741 " var r0 = %_GetFromCache(0, key0);"
18742 " var r1 = %_GetFromCache(0, key1);"
18743 " var r0_ = %_GetFromCache(0, key0);"
18745 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18746 " var r1_ = %_GetFromCache(0, key1);"
18748 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18749 " return 'PASSED';"
18751 CcTest::heap()->ClearJSFunctionResultCaches();
18752 ExpectString(code, "PASSED");
18756 THREADED_TEST(FillJSFunctionResultCache) {
18757 i::FLAG_allow_natives_syntax = true;
18758 LocalContext context;
18759 v8::HandleScope scope(context->GetIsolate());
18764 " var r = %_GetFromCache(0, k);"
18765 " for (var i = 0; i < 16; i++) {"
18766 " %_GetFromCache(0, 'a' + i);"
18768 " if (r === %_GetFromCache(0, k))"
18769 " return 'FAILED: k0CacheSize is too small';"
18770 " return 'PASSED';"
18772 CcTest::heap()->ClearJSFunctionResultCaches();
18773 ExpectString(code, "PASSED");
18777 THREADED_TEST(RoundRobinGetFromCache) {
18778 i::FLAG_allow_natives_syntax = true;
18779 LocalContext context;
18780 v8::HandleScope scope(context->GetIsolate());
18785 " for (var i = 0; i < 16; i++) keys.push(i);"
18786 " var values = [];"
18787 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18788 " for (var i = 0; i < 16; i++) {"
18789 " var v = %_GetFromCache(0, keys[i]);"
18790 " if (v.toString() !== values[i].toString())"
18791 " return 'Wrong value for ' + "
18792 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18794 " return 'PASSED';"
18796 CcTest::heap()->ClearJSFunctionResultCaches();
18797 ExpectString(code, "PASSED");
18801 THREADED_TEST(ReverseGetFromCache) {
18802 i::FLAG_allow_natives_syntax = true;
18803 LocalContext context;
18804 v8::HandleScope scope(context->GetIsolate());
18809 " for (var i = 0; i < 16; i++) keys.push(i);"
18810 " var values = [];"
18811 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18812 " for (var i = 15; i >= 16; i--) {"
18813 " var v = %_GetFromCache(0, keys[i]);"
18814 " if (v !== values[i])"
18815 " return 'Wrong value for ' + "
18816 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18818 " return 'PASSED';"
18820 CcTest::heap()->ClearJSFunctionResultCaches();
18821 ExpectString(code, "PASSED");
18825 THREADED_TEST(TestEviction) {
18826 i::FLAG_allow_natives_syntax = true;
18827 LocalContext context;
18828 v8::HandleScope scope(context->GetIsolate());
18832 " for (var i = 0; i < 2*16; i++) {"
18833 " %_GetFromCache(0, 'a' + i);"
18835 " return 'PASSED';"
18837 CcTest::heap()->ClearJSFunctionResultCaches();
18838 ExpectString(code, "PASSED");
18842 THREADED_TEST(TwoByteStringInAsciiCons) {
18843 // See Chromium issue 47824.
18844 LocalContext context;
18845 v8::HandleScope scope(context->GetIsolate());
18847 const char* init_code =
18848 "var str1 = 'abelspendabel';"
18849 "var str2 = str1 + str1 + str1;"
18851 Local<Value> result = CompileRun(init_code);
18853 Local<Value> indexof = CompileRun("str2.indexOf('els')");
18854 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18856 CHECK(result->IsString());
18857 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18858 int length = string->length();
18859 CHECK(string->IsOneByteRepresentation());
18861 FlattenString(string);
18862 i::Handle<i::String> flat_string = FlattenGetString(string);
18864 CHECK(string->IsOneByteRepresentation());
18865 CHECK(flat_string->IsOneByteRepresentation());
18867 // Create external resource.
18868 uint16_t* uc16_buffer = new uint16_t[length + 1];
18870 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18871 uc16_buffer[length] = 0;
18873 TestResource resource(uc16_buffer);
18875 flat_string->MakeExternal(&resource);
18877 CHECK(flat_string->IsTwoByteRepresentation());
18879 // If the cons string has been short-circuited, skip the following checks.
18880 if (!string.is_identical_to(flat_string)) {
18881 // At this point, we should have a Cons string which is flat and ASCII,
18882 // with a first half that is a two-byte string (although it only contains
18883 // ASCII characters). This is a valid sequence of steps, and it can happen
18885 CHECK(string->IsOneByteRepresentation());
18886 i::ConsString* cons = i::ConsString::cast(*string);
18887 CHECK_EQ(0, cons->second()->length());
18888 CHECK(cons->first()->IsTwoByteRepresentation());
18891 // Check that some string operations work.
18894 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18895 CHECK_EQ(6, reresult->Int32Value());
18898 reresult = CompileRun("str2.match(/abe./g).length;");
18899 CHECK_EQ(6, reresult->Int32Value());
18901 reresult = CompileRun("str2.search(/bel/g);");
18902 CHECK_EQ(1, reresult->Int32Value());
18904 reresult = CompileRun("str2.search(/be./g);");
18905 CHECK_EQ(1, reresult->Int32Value());
18907 ExpectTrue("/bel/g.test(str2);");
18909 ExpectTrue("/be./g.test(str2);");
18911 reresult = CompileRun("/bel/g.exec(str2);");
18912 CHECK(!reresult->IsNull());
18914 reresult = CompileRun("/be./g.exec(str2);");
18915 CHECK(!reresult->IsNull());
18917 ExpectString("str2.substring(2, 10);", "elspenda");
18919 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18921 ExpectString("str2.charAt(2);", "e");
18923 ExpectObject("str2.indexOf('els');", indexof);
18925 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18927 reresult = CompileRun("str2.charCodeAt(2);");
18928 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18932 TEST(ContainsOnlyOneByte) {
18933 v8::V8::Initialize();
18934 v8::Isolate* isolate = CcTest::isolate();
18935 v8::HandleScope scope(isolate);
18936 // Make a buffer long enough that it won't automatically be converted.
18937 const int length = 512;
18938 // Ensure word aligned assignment.
18939 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18940 i::SmartArrayPointer<uintptr_t>
18941 aligned_contents(new uintptr_t[aligned_length]);
18942 uint16_t* string_contents =
18943 reinterpret_cast<uint16_t*>(aligned_contents.get());
18944 // Set to contain only one byte.
18945 for (int i = 0; i < length-1; i++) {
18946 string_contents[i] = 0x41;
18948 string_contents[length-1] = 0;
18950 Handle<String> string;
18951 string = String::NewExternal(isolate, new TestResource(string_contents));
18952 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18953 // Counter example.
18954 string = String::NewFromTwoByte(isolate, string_contents);
18955 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18956 // Test left right and balanced cons strings.
18957 Handle<String> base = String::NewFromUtf8(isolate, "a");
18958 Handle<String> left = base;
18959 Handle<String> right = base;
18960 for (int i = 0; i < 1000; i++) {
18961 left = String::Concat(base, left);
18962 right = String::Concat(right, base);
18964 Handle<String> balanced = String::Concat(left, base);
18965 balanced = String::Concat(balanced, right);
18966 Handle<String> cons_strings[] = {left, balanced, right};
18967 Handle<String> two_byte =
18968 String::NewExternal(isolate, new TestResource(string_contents));
18969 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18970 // Base assumptions.
18971 string = cons_strings[i];
18972 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18973 // Test left and right concatentation.
18974 string = String::Concat(two_byte, cons_strings[i]);
18975 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18976 string = String::Concat(cons_strings[i], two_byte);
18977 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18979 // Set bits in different positions
18980 // for strings of different lengths and alignments.
18981 for (int alignment = 0; alignment < 7; alignment++) {
18982 for (int size = 2; alignment + size < length; size *= 2) {
18983 int zero_offset = size + alignment;
18984 string_contents[zero_offset] = 0;
18985 for (int i = 0; i < size; i++) {
18986 int shift = 8 + (i % 7);
18987 string_contents[alignment + i] = 1 << shift;
18988 string = String::NewExternal(
18989 isolate, new TestResource(string_contents + alignment));
18990 CHECK_EQ(size, string->Length());
18991 CHECK(!string->ContainsOnlyOneByte());
18992 string_contents[alignment + i] = 0x41;
18994 string_contents[zero_offset] = 0x41;
19000 // Failed access check callback that performs a GC on each invocation.
19001 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19002 v8::AccessType type,
19003 Local<v8::Value> data) {
19004 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19008 TEST(GCInFailedAccessCheckCallback) {
19009 // Install a failed access check callback that performs a GC on each
19010 // invocation. Then force the callback to be called from va
19012 v8::V8::Initialize();
19013 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19015 v8::Isolate* isolate = CcTest::isolate();
19016 v8::HandleScope scope(isolate);
19018 // Create an ObjectTemplate for global objects and install access
19019 // check callbacks that will block access.
19020 v8::Handle<v8::ObjectTemplate> global_template =
19021 v8::ObjectTemplate::New(isolate);
19022 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19023 IndexedGetAccessBlocker,
19024 v8::Handle<v8::Value>(),
19027 // Create a context and set an x property on it's global object.
19028 LocalContext context0(NULL, global_template);
19029 context0->Global()->Set(v8_str("x"), v8_num(42));
19030 v8::Handle<v8::Object> global0 = context0->Global();
19032 // Create a context with a different security token so that the
19033 // failed access check callback will be called on each access.
19034 LocalContext context1(NULL, global_template);
19035 context1->Global()->Set(v8_str("other"), global0);
19037 // Get property with failed access check.
19038 ExpectUndefined("other.x");
19040 // Get element with failed access check.
19041 ExpectUndefined("other[0]");
19043 // Set property with failed access check.
19044 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19045 CHECK(result->IsObject());
19047 // Set element with failed access check.
19048 result = CompileRun("other[0] = new Object()");
19049 CHECK(result->IsObject());
19051 // Get property attribute with failed access check.
19052 ExpectFalse("\'x\' in other");
19054 // Get property attribute for element with failed access check.
19055 ExpectFalse("0 in other");
19057 // Delete property.
19058 ExpectFalse("delete other.x");
19061 CHECK_EQ(false, global0->Delete(0));
19065 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19067 // Define JavaScript accessor.
19068 ExpectUndefined("Object.prototype.__defineGetter__.call("
19069 " other, \'x\', function() { return 42; })");
19072 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19075 // HasLocalElement.
19076 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19078 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19079 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19080 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19082 // Reset the failed access check callback so it does not influence
19083 // the other tests.
19084 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19088 TEST(IsolateNewDispose) {
19089 v8::Isolate* current_isolate = CcTest::isolate();
19090 v8::Isolate* isolate = v8::Isolate::New();
19091 CHECK(isolate != NULL);
19092 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19093 CHECK(current_isolate != isolate);
19094 CHECK(current_isolate == CcTest::isolate());
19096 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19097 last_location = last_message = NULL;
19098 isolate->Dispose();
19099 CHECK_EQ(last_location, NULL);
19100 CHECK_EQ(last_message, NULL);
19104 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19105 v8::Isolate* isolate = v8::Isolate::New();
19108 v8::HandleScope scope(isolate);
19109 LocalContext context(isolate);
19110 // Run something in this isolate.
19111 ExpectTrue("true");
19112 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19113 last_location = last_message = NULL;
19114 // Still entered, should fail.
19115 isolate->Dispose();
19116 CHECK_NE(last_location, NULL);
19117 CHECK_NE(last_message, NULL);
19121 TEST(RunTwoIsolatesOnSingleThread) {
19123 v8::Isolate* isolate1 = v8::Isolate::New();
19125 v8::Persistent<v8::Context> context1;
19127 v8::HandleScope scope(isolate1);
19128 context1.Reset(isolate1, Context::New(isolate1));
19132 v8::HandleScope scope(isolate1);
19133 v8::Local<v8::Context> context =
19134 v8::Local<v8::Context>::New(isolate1, context1);
19135 v8::Context::Scope context_scope(context);
19136 // Run something in new isolate.
19137 CompileRun("var foo = 'isolate 1';");
19138 ExpectString("function f() { return foo; }; f()", "isolate 1");
19142 v8::Isolate* isolate2 = v8::Isolate::New();
19143 v8::Persistent<v8::Context> context2;
19146 v8::Isolate::Scope iscope(isolate2);
19147 v8::HandleScope scope(isolate2);
19148 context2.Reset(isolate2, Context::New(isolate2));
19149 v8::Local<v8::Context> context =
19150 v8::Local<v8::Context>::New(isolate2, context2);
19151 v8::Context::Scope context_scope(context);
19153 // Run something in new isolate.
19154 CompileRun("var foo = 'isolate 2';");
19155 ExpectString("function f() { return foo; }; f()", "isolate 2");
19159 v8::HandleScope scope(isolate1);
19160 v8::Local<v8::Context> context =
19161 v8::Local<v8::Context>::New(isolate1, context1);
19162 v8::Context::Scope context_scope(context);
19163 // Now again in isolate 1
19164 ExpectString("function f() { return foo; }; f()", "isolate 1");
19169 // Run some stuff in default isolate.
19170 v8::Persistent<v8::Context> context_default;
19172 v8::Isolate* isolate = CcTest::isolate();
19173 v8::Isolate::Scope iscope(isolate);
19174 v8::HandleScope scope(isolate);
19175 context_default.Reset(isolate, Context::New(isolate));
19179 v8::HandleScope scope(CcTest::isolate());
19180 v8::Local<v8::Context> context =
19181 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19182 v8::Context::Scope context_scope(context);
19183 // Variables in other isolates should be not available, verify there
19184 // is an exception.
19185 ExpectTrue("function f() {"
19193 "var isDefaultIsolate = true;"
19200 v8::Isolate::Scope iscope(isolate2);
19201 v8::HandleScope scope(isolate2);
19202 v8::Local<v8::Context> context =
19203 v8::Local<v8::Context>::New(isolate2, context2);
19204 v8::Context::Scope context_scope(context);
19205 ExpectString("function f() { return foo; }; f()", "isolate 2");
19209 v8::HandleScope scope(v8::Isolate::GetCurrent());
19210 v8::Local<v8::Context> context =
19211 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19212 v8::Context::Scope context_scope(context);
19213 ExpectString("function f() { return foo; }; f()", "isolate 1");
19217 v8::Isolate::Scope iscope(isolate2);
19224 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19225 last_location = last_message = NULL;
19227 isolate1->Dispose();
19228 CHECK_EQ(last_location, NULL);
19229 CHECK_EQ(last_message, NULL);
19231 isolate2->Dispose();
19232 CHECK_EQ(last_location, NULL);
19233 CHECK_EQ(last_message, NULL);
19235 // Check that default isolate still runs.
19237 v8::HandleScope scope(CcTest::isolate());
19238 v8::Local<v8::Context> context =
19239 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19240 v8::Context::Scope context_scope(context);
19241 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19246 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19247 v8::Isolate::Scope isolate_scope(isolate);
19248 v8::HandleScope scope(isolate);
19249 LocalContext context(isolate);
19250 i::ScopedVector<char> code(1024);
19251 i::OS::SNPrintF(code, "function fib(n) {"
19252 " if (n <= 2) return 1;"
19253 " return fib(n-1) + fib(n-2);"
19256 Local<Value> value = CompileRun(code.start());
19257 CHECK(value->IsNumber());
19258 return static_cast<int>(value->NumberValue());
19261 class IsolateThread : public v8::internal::Thread {
19263 IsolateThread(v8::Isolate* isolate, int fib_limit)
19264 : Thread("IsolateThread"),
19266 fib_limit_(fib_limit),
19270 result_ = CalcFibonacci(isolate_, fib_limit_);
19273 int result() { return result_; }
19276 v8::Isolate* isolate_;
19282 TEST(MultipleIsolatesOnIndividualThreads) {
19283 v8::Isolate* isolate1 = v8::Isolate::New();
19284 v8::Isolate* isolate2 = v8::Isolate::New();
19286 IsolateThread thread1(isolate1, 21);
19287 IsolateThread thread2(isolate2, 12);
19289 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19293 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19294 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19299 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19300 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19301 CHECK_EQ(result1, 10946);
19302 CHECK_EQ(result2, 144);
19303 CHECK_EQ(result1, thread1.result());
19304 CHECK_EQ(result2, thread2.result());
19306 isolate1->Dispose();
19307 isolate2->Dispose();
19311 TEST(IsolateDifferentContexts) {
19312 v8::Isolate* isolate = v8::Isolate::New();
19313 Local<v8::Context> context;
19315 v8::Isolate::Scope isolate_scope(isolate);
19316 v8::HandleScope handle_scope(isolate);
19317 context = v8::Context::New(isolate);
19318 v8::Context::Scope context_scope(context);
19319 Local<Value> v = CompileRun("2");
19320 CHECK(v->IsNumber());
19321 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19324 v8::Isolate::Scope isolate_scope(isolate);
19325 v8::HandleScope handle_scope(isolate);
19326 context = v8::Context::New(isolate);
19327 v8::Context::Scope context_scope(context);
19328 Local<Value> v = CompileRun("22");
19329 CHECK(v->IsNumber());
19330 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19334 class InitDefaultIsolateThread : public v8::internal::Thread {
19338 SetResourceConstraints,
19340 SetCounterFunction,
19341 SetCreateHistogramFunction,
19342 SetAddHistogramSampleFunction
19345 explicit InitDefaultIsolateThread(TestCase testCase)
19346 : Thread("InitDefaultIsolateThread"),
19347 testCase_(testCase),
19351 v8::Isolate* isolate = v8::Isolate::New();
19353 switch (testCase_) {
19355 v8::V8::IgnoreOutOfMemoryException();
19358 case SetResourceConstraints: {
19359 static const int K = 1024;
19360 v8::ResourceConstraints constraints;
19361 constraints.set_max_young_space_size(256 * K);
19362 constraints.set_max_old_space_size(4 * K * K);
19363 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19367 case SetFatalHandler:
19368 v8::V8::SetFatalErrorHandler(NULL);
19371 case SetCounterFunction:
19372 v8::V8::SetCounterFunction(NULL);
19375 case SetCreateHistogramFunction:
19376 v8::V8::SetCreateHistogramFunction(NULL);
19379 case SetAddHistogramSampleFunction:
19380 v8::V8::SetAddHistogramSampleFunction(NULL);
19384 isolate->Dispose();
19388 bool result() { return result_; }
19391 TestCase testCase_;
19396 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19397 InitDefaultIsolateThread thread(testCase);
19400 CHECK_EQ(thread.result(), true);
19404 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19405 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
19409 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19410 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19414 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19415 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19419 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19420 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19424 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19425 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19429 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
19430 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19434 TEST(StringCheckMultipleContexts) {
19436 "(function() { return \"a\".charAt(0); })()";
19439 // Run the code twice in the first context to initialize the call IC.
19440 LocalContext context1;
19441 v8::HandleScope scope(context1->GetIsolate());
19442 ExpectString(code, "a");
19443 ExpectString(code, "a");
19447 // Change the String.prototype in the second context and check
19448 // that the right function gets called.
19449 LocalContext context2;
19450 v8::HandleScope scope(context2->GetIsolate());
19451 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19452 ExpectString(code, "not a");
19457 TEST(NumberCheckMultipleContexts) {
19459 "(function() { return (42).toString(); })()";
19462 // Run the code twice in the first context to initialize the call IC.
19463 LocalContext context1;
19464 v8::HandleScope scope(context1->GetIsolate());
19465 ExpectString(code, "42");
19466 ExpectString(code, "42");
19470 // Change the Number.prototype in the second context and check
19471 // that the right function gets called.
19472 LocalContext context2;
19473 v8::HandleScope scope(context2->GetIsolate());
19474 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19475 ExpectString(code, "not 42");
19480 TEST(BooleanCheckMultipleContexts) {
19482 "(function() { return true.toString(); })()";
19485 // Run the code twice in the first context to initialize the call IC.
19486 LocalContext context1;
19487 v8::HandleScope scope(context1->GetIsolate());
19488 ExpectString(code, "true");
19489 ExpectString(code, "true");
19493 // Change the Boolean.prototype in the second context and check
19494 // that the right function gets called.
19495 LocalContext context2;
19496 v8::HandleScope scope(context2->GetIsolate());
19497 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19498 ExpectString(code, "");
19503 TEST(DontDeleteCellLoadIC) {
19504 const char* function_code =
19505 "function readCell() { while (true) { return cell; } }";
19508 // Run the code twice in the first context to initialize the load
19509 // IC for a don't delete cell.
19510 LocalContext context1;
19511 v8::HandleScope scope(context1->GetIsolate());
19512 CompileRun("var cell = \"first\";");
19513 ExpectBoolean("delete cell", false);
19514 CompileRun(function_code);
19515 ExpectString("readCell()", "first");
19516 ExpectString("readCell()", "first");
19520 // Use a deletable cell in the second context.
19521 LocalContext context2;
19522 v8::HandleScope scope(context2->GetIsolate());
19523 CompileRun("cell = \"second\";");
19524 CompileRun(function_code);
19525 ExpectString("readCell()", "second");
19526 ExpectBoolean("delete cell", true);
19527 ExpectString("(function() {"
19529 " return readCell();"
19531 " return e.toString();"
19534 "ReferenceError: cell is not defined");
19535 CompileRun("cell = \"new_second\";");
19536 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19537 ExpectString("readCell()", "new_second");
19538 ExpectString("readCell()", "new_second");
19543 TEST(DontDeleteCellLoadICForceDelete) {
19544 const char* function_code =
19545 "function readCell() { while (true) { return cell; } }";
19547 // Run the code twice to initialize the load IC for a don't delete
19549 LocalContext context;
19550 v8::HandleScope scope(context->GetIsolate());
19551 CompileRun("var cell = \"value\";");
19552 ExpectBoolean("delete cell", false);
19553 CompileRun(function_code);
19554 ExpectString("readCell()", "value");
19555 ExpectString("readCell()", "value");
19557 // Delete the cell using the API and check the inlined code works
19559 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19560 ExpectString("(function() {"
19562 " return readCell();"
19564 " return e.toString();"
19567 "ReferenceError: cell is not defined");
19571 TEST(DontDeleteCellLoadICAPI) {
19572 const char* function_code =
19573 "function readCell() { while (true) { return cell; } }";
19575 // Run the code twice to initialize the load IC for a don't delete
19576 // cell created using the API.
19577 LocalContext context;
19578 v8::HandleScope scope(context->GetIsolate());
19579 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19580 ExpectBoolean("delete cell", false);
19581 CompileRun(function_code);
19582 ExpectString("readCell()", "value");
19583 ExpectString("readCell()", "value");
19585 // Delete the cell using the API and check the inlined code works
19587 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19588 ExpectString("(function() {"
19590 " return readCell();"
19592 " return e.toString();"
19595 "ReferenceError: cell is not defined");
19599 class Visitor42 : public v8::PersistentHandleVisitor {
19601 explicit Visitor42(v8::Persistent<v8::Object>* object)
19602 : counter_(0), object_(object) { }
19604 virtual void VisitPersistentHandle(Persistent<Value>* value,
19605 uint16_t class_id) {
19606 if (class_id != 42) return;
19607 CHECK_EQ(42, value->WrapperClassId());
19608 v8::Isolate* isolate = CcTest::isolate();
19609 v8::HandleScope handle_scope(isolate);
19610 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19611 v8::Handle<v8::Value> object =
19612 v8::Local<v8::Object>::New(isolate, *object_);
19613 CHECK(handle->IsObject());
19614 CHECK_EQ(Handle<Object>::Cast(handle), object);
19619 v8::Persistent<v8::Object>* object_;
19623 TEST(PersistentHandleVisitor) {
19624 LocalContext context;
19625 v8::Isolate* isolate = context->GetIsolate();
19626 v8::HandleScope scope(isolate);
19627 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19628 CHECK_EQ(0, object.WrapperClassId());
19629 object.SetWrapperClassId(42);
19630 CHECK_EQ(42, object.WrapperClassId());
19632 Visitor42 visitor(&object);
19633 v8::V8::VisitHandlesWithClassIds(&visitor);
19634 CHECK_EQ(1, visitor.counter_);
19640 TEST(WrapperClassId) {
19641 LocalContext context;
19642 v8::Isolate* isolate = context->GetIsolate();
19643 v8::HandleScope scope(isolate);
19644 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19645 CHECK_EQ(0, object.WrapperClassId());
19646 object.SetWrapperClassId(65535);
19647 CHECK_EQ(65535, object.WrapperClassId());
19652 TEST(PersistentHandleInNewSpaceVisitor) {
19653 LocalContext context;
19654 v8::Isolate* isolate = context->GetIsolate();
19655 v8::HandleScope scope(isolate);
19656 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19657 CHECK_EQ(0, object1.WrapperClassId());
19658 object1.SetWrapperClassId(42);
19659 CHECK_EQ(42, object1.WrapperClassId());
19661 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19663 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19664 CHECK_EQ(0, object2.WrapperClassId());
19665 object2.SetWrapperClassId(42);
19666 CHECK_EQ(42, object2.WrapperClassId());
19668 Visitor42 visitor(&object2);
19669 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19670 CHECK_EQ(1, visitor.counter_);
19678 LocalContext context;
19679 v8::HandleScope scope(context->GetIsolate());
19681 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19682 CHECK(re->IsRegExp());
19683 CHECK(re->GetSource()->Equals(v8_str("foo")));
19684 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19686 re = v8::RegExp::New(v8_str("bar"),
19687 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19688 v8::RegExp::kGlobal));
19689 CHECK(re->IsRegExp());
19690 CHECK(re->GetSource()->Equals(v8_str("bar")));
19691 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19692 static_cast<int>(re->GetFlags()));
19694 re = v8::RegExp::New(v8_str("baz"),
19695 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19696 v8::RegExp::kMultiline));
19697 CHECK(re->IsRegExp());
19698 CHECK(re->GetSource()->Equals(v8_str("baz")));
19699 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19700 static_cast<int>(re->GetFlags()));
19702 re = CompileRun("/quux/").As<v8::RegExp>();
19703 CHECK(re->IsRegExp());
19704 CHECK(re->GetSource()->Equals(v8_str("quux")));
19705 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19707 re = CompileRun("/quux/gm").As<v8::RegExp>();
19708 CHECK(re->IsRegExp());
19709 CHECK(re->GetSource()->Equals(v8_str("quux")));
19710 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19711 static_cast<int>(re->GetFlags()));
19713 // Override the RegExp constructor and check the API constructor
19715 CompileRun("RegExp = function() {}");
19717 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19718 CHECK(re->IsRegExp());
19719 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19720 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19722 re = v8::RegExp::New(v8_str("foobarbaz"),
19723 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19724 v8::RegExp::kMultiline));
19725 CHECK(re->IsRegExp());
19726 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19727 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19728 static_cast<int>(re->GetFlags()));
19730 context->Global()->Set(v8_str("re"), re);
19731 ExpectTrue("re.test('FoobarbaZ')");
19733 // RegExps are objects on which you can set properties.
19734 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19735 v8::Handle<v8::Value> value(CompileRun("re.property"));
19736 CHECK_EQ(32, value->Int32Value());
19738 v8::TryCatch try_catch;
19739 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19740 CHECK(re.IsEmpty());
19741 CHECK(try_catch.HasCaught());
19742 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19743 ExpectTrue("ex instanceof SyntaxError");
19747 THREADED_TEST(Equals) {
19748 LocalContext localContext;
19749 v8::HandleScope handleScope(localContext->GetIsolate());
19751 v8::Handle<v8::Object> globalProxy = localContext->Global();
19752 v8::Handle<Value> global = globalProxy->GetPrototype();
19754 CHECK(global->StrictEquals(global));
19755 CHECK(!global->StrictEquals(globalProxy));
19756 CHECK(!globalProxy->StrictEquals(global));
19757 CHECK(globalProxy->StrictEquals(globalProxy));
19759 CHECK(global->Equals(global));
19760 CHECK(!global->Equals(globalProxy));
19761 CHECK(!globalProxy->Equals(global));
19762 CHECK(globalProxy->Equals(globalProxy));
19766 static void Getter(v8::Local<v8::String> property,
19767 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19768 info.GetReturnValue().Set(v8_str("42!"));
19772 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19773 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19774 result->Set(0, v8_str("universalAnswer"));
19775 info.GetReturnValue().Set(result);
19779 TEST(NamedEnumeratorAndForIn) {
19780 LocalContext context;
19781 v8::Isolate* isolate = context->GetIsolate();
19782 v8::HandleScope handle_scope(isolate);
19783 v8::Context::Scope context_scope(context.local());
19785 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19786 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19787 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19788 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19789 "var result = []; for (var k in o) result.push(k); result"));
19790 CHECK_EQ(1, result->Length());
19791 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19795 TEST(DefinePropertyPostDetach) {
19796 LocalContext context;
19797 v8::HandleScope scope(context->GetIsolate());
19798 v8::Handle<v8::Object> proxy = context->Global();
19799 v8::Handle<v8::Function> define_property =
19800 CompileRun("(function() {"
19801 " Object.defineProperty("
19804 " { configurable: true, enumerable: true, value: 3 });"
19805 "})").As<Function>();
19806 context->DetachGlobal();
19807 define_property->Call(proxy, 0, NULL);
19811 static void InstallContextId(v8::Handle<Context> context, int id) {
19812 Context::Scope scope(context);
19813 CompileRun("Object.prototype").As<Object>()->
19814 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19818 static void CheckContextId(v8::Handle<Object> object, int expected) {
19819 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19823 THREADED_TEST(CreationContext) {
19824 v8::Isolate* isolate = CcTest::isolate();
19825 HandleScope handle_scope(isolate);
19826 Handle<Context> context1 = Context::New(isolate);
19827 InstallContextId(context1, 1);
19828 Handle<Context> context2 = Context::New(isolate);
19829 InstallContextId(context2, 2);
19830 Handle<Context> context3 = Context::New(isolate);
19831 InstallContextId(context3, 3);
19833 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19835 Local<Object> object1;
19836 Local<Function> func1;
19838 Context::Scope scope(context1);
19839 object1 = Object::New(isolate);
19840 func1 = tmpl->GetFunction();
19843 Local<Object> object2;
19844 Local<Function> func2;
19846 Context::Scope scope(context2);
19847 object2 = Object::New(isolate);
19848 func2 = tmpl->GetFunction();
19851 Local<Object> instance1;
19852 Local<Object> instance2;
19855 Context::Scope scope(context3);
19856 instance1 = func1->NewInstance();
19857 instance2 = func2->NewInstance();
19860 CHECK(object1->CreationContext() == context1);
19861 CheckContextId(object1, 1);
19862 CHECK(func1->CreationContext() == context1);
19863 CheckContextId(func1, 1);
19864 CHECK(instance1->CreationContext() == context1);
19865 CheckContextId(instance1, 1);
19866 CHECK(object2->CreationContext() == context2);
19867 CheckContextId(object2, 2);
19868 CHECK(func2->CreationContext() == context2);
19869 CheckContextId(func2, 2);
19870 CHECK(instance2->CreationContext() == context2);
19871 CheckContextId(instance2, 2);
19874 Context::Scope scope(context1);
19875 CHECK(object1->CreationContext() == context1);
19876 CheckContextId(object1, 1);
19877 CHECK(func1->CreationContext() == context1);
19878 CheckContextId(func1, 1);
19879 CHECK(instance1->CreationContext() == context1);
19880 CheckContextId(instance1, 1);
19881 CHECK(object2->CreationContext() == context2);
19882 CheckContextId(object2, 2);
19883 CHECK(func2->CreationContext() == context2);
19884 CheckContextId(func2, 2);
19885 CHECK(instance2->CreationContext() == context2);
19886 CheckContextId(instance2, 2);
19890 Context::Scope scope(context2);
19891 CHECK(object1->CreationContext() == context1);
19892 CheckContextId(object1, 1);
19893 CHECK(func1->CreationContext() == context1);
19894 CheckContextId(func1, 1);
19895 CHECK(instance1->CreationContext() == context1);
19896 CheckContextId(instance1, 1);
19897 CHECK(object2->CreationContext() == context2);
19898 CheckContextId(object2, 2);
19899 CHECK(func2->CreationContext() == context2);
19900 CheckContextId(func2, 2);
19901 CHECK(instance2->CreationContext() == context2);
19902 CheckContextId(instance2, 2);
19907 THREADED_TEST(CreationContextOfJsFunction) {
19908 HandleScope handle_scope(CcTest::isolate());
19909 Handle<Context> context = Context::New(CcTest::isolate());
19910 InstallContextId(context, 1);
19912 Local<Object> function;
19914 Context::Scope scope(context);
19915 function = CompileRun("function foo() {}; foo").As<Object>();
19918 CHECK(function->CreationContext() == context);
19919 CheckContextId(function, 1);
19923 void HasOwnPropertyIndexedPropertyGetter(
19925 const v8::PropertyCallbackInfo<v8::Value>& info) {
19926 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19930 void HasOwnPropertyNamedPropertyGetter(
19931 Local<String> property,
19932 const v8::PropertyCallbackInfo<v8::Value>& info) {
19933 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19937 void HasOwnPropertyIndexedPropertyQuery(
19938 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19939 if (index == 42) info.GetReturnValue().Set(1);
19943 void HasOwnPropertyNamedPropertyQuery(
19944 Local<String> property,
19945 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19946 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19950 void HasOwnPropertyNamedPropertyQuery2(
19951 Local<String> property,
19952 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19953 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19957 void HasOwnPropertyAccessorGetter(
19958 Local<String> property,
19959 const v8::PropertyCallbackInfo<v8::Value>& info) {
19960 info.GetReturnValue().Set(v8_str("yes"));
19964 TEST(HasOwnProperty) {
19966 v8::Isolate* isolate = env->GetIsolate();
19967 v8::HandleScope scope(isolate);
19968 { // Check normal properties and defined getters.
19969 Handle<Value> value = CompileRun(
19972 " this.__defineGetter__('baz', function() { return 1; });"
19974 "function Bar() { "
19976 " this.__defineGetter__('bla', function() { return 2; });"
19978 "Bar.prototype = new Foo();"
19980 CHECK(value->IsObject());
19981 Handle<Object> object = value->ToObject();
19982 CHECK(object->Has(v8_str("foo")));
19983 CHECK(!object->HasOwnProperty(v8_str("foo")));
19984 CHECK(object->HasOwnProperty(v8_str("bar")));
19985 CHECK(object->Has(v8_str("baz")));
19986 CHECK(!object->HasOwnProperty(v8_str("baz")));
19987 CHECK(object->HasOwnProperty(v8_str("bla")));
19989 { // Check named getter interceptors.
19990 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19991 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19992 Handle<Object> instance = templ->NewInstance();
19993 CHECK(!instance->HasOwnProperty(v8_str("42")));
19994 CHECK(instance->HasOwnProperty(v8_str("foo")));
19995 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19997 { // Check indexed getter interceptors.
19998 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19999 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20000 Handle<Object> instance = templ->NewInstance();
20001 CHECK(instance->HasOwnProperty(v8_str("42")));
20002 CHECK(!instance->HasOwnProperty(v8_str("43")));
20003 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20005 { // Check named query interceptors.
20006 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20007 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20008 Handle<Object> instance = templ->NewInstance();
20009 CHECK(instance->HasOwnProperty(v8_str("foo")));
20010 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20012 { // Check indexed query interceptors.
20013 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20014 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20015 Handle<Object> instance = templ->NewInstance();
20016 CHECK(instance->HasOwnProperty(v8_str("42")));
20017 CHECK(!instance->HasOwnProperty(v8_str("41")));
20019 { // Check callbacks.
20020 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20021 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20022 Handle<Object> instance = templ->NewInstance();
20023 CHECK(instance->HasOwnProperty(v8_str("foo")));
20024 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20026 { // Check that query wins on disagreement.
20027 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20028 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20030 HasOwnPropertyNamedPropertyQuery2);
20031 Handle<Object> instance = templ->NewInstance();
20032 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20033 CHECK(instance->HasOwnProperty(v8_str("bar")));
20038 TEST(IndexedInterceptorWithStringProto) {
20039 v8::Isolate* isolate = CcTest::isolate();
20040 v8::HandleScope scope(isolate);
20041 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20042 templ->SetIndexedPropertyHandler(NULL,
20044 HasOwnPropertyIndexedPropertyQuery);
20045 LocalContext context;
20046 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20047 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20048 // These should be intercepted.
20049 CHECK(CompileRun("42 in obj")->BooleanValue());
20050 CHECK(CompileRun("'42' in obj")->BooleanValue());
20051 // These should fall through to the String prototype.
20052 CHECK(CompileRun("0 in obj")->BooleanValue());
20053 CHECK(CompileRun("'0' in obj")->BooleanValue());
20054 // And these should both fail.
20055 CHECK(!CompileRun("32 in obj")->BooleanValue());
20056 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20060 void CheckCodeGenerationAllowed() {
20061 Handle<Value> result = CompileRun("eval('42')");
20062 CHECK_EQ(42, result->Int32Value());
20063 result = CompileRun("(function(e) { return e('42'); })(eval)");
20064 CHECK_EQ(42, result->Int32Value());
20065 result = CompileRun("var f = new Function('return 42'); f()");
20066 CHECK_EQ(42, result->Int32Value());
20070 void CheckCodeGenerationDisallowed() {
20071 TryCatch try_catch;
20073 Handle<Value> result = CompileRun("eval('42')");
20074 CHECK(result.IsEmpty());
20075 CHECK(try_catch.HasCaught());
20078 result = CompileRun("(function(e) { return e('42'); })(eval)");
20079 CHECK(result.IsEmpty());
20080 CHECK(try_catch.HasCaught());
20083 result = CompileRun("var f = new Function('return 42'); f()");
20084 CHECK(result.IsEmpty());
20085 CHECK(try_catch.HasCaught());
20089 bool CodeGenerationAllowed(Local<Context> context) {
20090 ApiTestFuzzer::Fuzz();
20095 bool CodeGenerationDisallowed(Local<Context> context) {
20096 ApiTestFuzzer::Fuzz();
20101 THREADED_TEST(AllowCodeGenFromStrings) {
20102 LocalContext context;
20103 v8::HandleScope scope(context->GetIsolate());
20105 // eval and the Function constructor allowed by default.
20106 CHECK(context->IsCodeGenerationFromStringsAllowed());
20107 CheckCodeGenerationAllowed();
20109 // Disallow eval and the Function constructor.
20110 context->AllowCodeGenerationFromStrings(false);
20111 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20112 CheckCodeGenerationDisallowed();
20115 context->AllowCodeGenerationFromStrings(true);
20116 CheckCodeGenerationAllowed();
20118 // Disallow but setting a global callback that will allow the calls.
20119 context->AllowCodeGenerationFromStrings(false);
20120 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20121 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20122 CheckCodeGenerationAllowed();
20124 // Set a callback that disallows the code generation.
20125 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20126 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20127 CheckCodeGenerationDisallowed();
20131 TEST(SetErrorMessageForCodeGenFromStrings) {
20132 LocalContext context;
20133 v8::HandleScope scope(context->GetIsolate());
20134 TryCatch try_catch;
20136 Handle<String> message = v8_str("Message") ;
20137 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20138 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20139 context->AllowCodeGenerationFromStrings(false);
20140 context->SetErrorMessageForCodeGenerationFromStrings(message);
20141 Handle<Value> result = CompileRun("eval('42')");
20142 CHECK(result.IsEmpty());
20143 CHECK(try_catch.HasCaught());
20144 Handle<String> actual_message = try_catch.Message()->Get();
20145 CHECK(expected_message->Equals(actual_message));
20149 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20153 THREADED_TEST(CallAPIFunctionOnNonObject) {
20154 LocalContext context;
20155 v8::Isolate* isolate = context->GetIsolate();
20156 v8::HandleScope scope(isolate);
20157 Handle<FunctionTemplate> templ =
20158 v8::FunctionTemplate::New(isolate, NonObjectThis);
20159 Handle<Function> function = templ->GetFunction();
20160 context->Global()->Set(v8_str("f"), function);
20161 TryCatch try_catch;
20162 CompileRun("f.call(2)");
20166 // Regression test for issue 1470.
20167 THREADED_TEST(ReadOnlyIndexedProperties) {
20168 v8::Isolate* isolate = CcTest::isolate();
20169 v8::HandleScope scope(isolate);
20170 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20172 LocalContext context;
20173 Local<v8::Object> obj = templ->NewInstance();
20174 context->Global()->Set(v8_str("obj"), obj);
20175 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20176 obj->Set(v8_str("1"), v8_str("foobar"));
20177 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20178 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20179 obj->Set(v8_num(2), v8_str("foobar"));
20180 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20182 // Test non-smi case.
20183 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20184 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20185 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20189 THREADED_TEST(Regress1516) {
20190 LocalContext context;
20191 v8::HandleScope scope(context->GetIsolate());
20193 { v8::HandleScope temp_scope(context->GetIsolate());
20194 CompileRun("({'a': 0})");
20198 { i::MapCache* map_cache =
20199 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20200 elements = map_cache->NumberOfElements();
20201 CHECK_LE(1, elements);
20204 CcTest::heap()->CollectAllGarbage(
20205 i::Heap::kAbortIncrementalMarkingMask);
20206 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20207 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20208 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20209 CHECK_GT(elements, map_cache->NumberOfElements());
20215 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20217 v8::AccessType type,
20218 Local<Value> data) {
20219 // Only block read access to __proto__.
20220 if (type == v8::ACCESS_GET &&
20221 name->IsString() &&
20222 name->ToString()->Length() == 9 &&
20223 name->ToString()->Utf8Length() == 9) {
20225 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20226 return strncmp(buffer, "__proto__", 9) != 0;
20233 THREADED_TEST(Regress93759) {
20234 v8::Isolate* isolate = CcTest::isolate();
20235 HandleScope scope(isolate);
20237 // Template for object with security check.
20238 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20239 // We don't do indexing, so any callback can be used for that.
20240 no_proto_template->SetAccessCheckCallbacks(
20241 BlockProtoNamedSecurityTestCallback,
20242 IndexedSecurityTestCallback);
20244 // Templates for objects with hidden prototypes and possibly security check.
20245 Local<FunctionTemplate> hidden_proto_template =
20246 v8::FunctionTemplate::New(isolate);
20247 hidden_proto_template->SetHiddenPrototype(true);
20249 Local<FunctionTemplate> protected_hidden_proto_template =
20250 v8::FunctionTemplate::New(isolate);
20251 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20252 BlockProtoNamedSecurityTestCallback,
20253 IndexedSecurityTestCallback);
20254 protected_hidden_proto_template->SetHiddenPrototype(true);
20256 // Context for "foreign" objects used in test.
20257 Local<Context> context = v8::Context::New(isolate);
20260 // Plain object, no security check.
20261 Local<Object> simple_object = Object::New(isolate);
20263 // Object with explicit security check.
20264 Local<Object> protected_object =
20265 no_proto_template->NewInstance();
20267 // JSGlobalProxy object, always have security check.
20268 Local<Object> proxy_object =
20271 // Global object, the prototype of proxy_object. No security checks.
20272 Local<Object> global_object =
20273 proxy_object->GetPrototype()->ToObject();
20275 // Hidden prototype without security check.
20276 Local<Object> hidden_prototype =
20277 hidden_proto_template->GetFunction()->NewInstance();
20278 Local<Object> object_with_hidden =
20279 Object::New(isolate);
20280 object_with_hidden->SetPrototype(hidden_prototype);
20282 // Hidden prototype with security check on the hidden prototype.
20283 Local<Object> protected_hidden_prototype =
20284 protected_hidden_proto_template->GetFunction()->NewInstance();
20285 Local<Object> object_with_protected_hidden =
20286 Object::New(isolate);
20287 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20291 // Template for object for second context. Values to test are put on it as
20293 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20294 global_template->Set(v8_str("simple"), simple_object);
20295 global_template->Set(v8_str("protected"), protected_object);
20296 global_template->Set(v8_str("global"), global_object);
20297 global_template->Set(v8_str("proxy"), proxy_object);
20298 global_template->Set(v8_str("hidden"), object_with_hidden);
20299 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20301 LocalContext context2(NULL, global_template);
20303 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20304 CHECK(result1->Equals(simple_object->GetPrototype()));
20306 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20307 CHECK(result2->Equals(Undefined(isolate)));
20309 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20310 CHECK(result3->Equals(global_object->GetPrototype()));
20312 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20313 CHECK(result4->Equals(Undefined(isolate)));
20315 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20316 CHECK(result5->Equals(
20317 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20319 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20320 CHECK(result6->Equals(Undefined(isolate)));
20324 THREADED_TEST(Regress125988) {
20325 v8::HandleScope scope(CcTest::isolate());
20326 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20327 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20329 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20330 CompileRun("var a = new Object();"
20331 "var b = new Intercept();"
20332 "var c = new Object();"
20336 "for (var i = 0; i < 3; i++) c.x;");
20337 ExpectBoolean("c.hasOwnProperty('x')", false);
20338 ExpectInt32("c.x", 23);
20339 CompileRun("a.y = 42;"
20340 "for (var i = 0; i < 3; i++) c.x;");
20341 ExpectBoolean("c.hasOwnProperty('x')", false);
20342 ExpectInt32("c.x", 23);
20343 ExpectBoolean("c.hasOwnProperty('y')", false);
20344 ExpectInt32("c.y", 42);
20348 static void TestReceiver(Local<Value> expected_result,
20349 Local<Value> expected_receiver,
20350 const char* code) {
20351 Local<Value> result = CompileRun(code);
20352 CHECK(result->IsObject());
20353 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20354 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20358 THREADED_TEST(ForeignFunctionReceiver) {
20359 v8::Isolate* isolate = CcTest::isolate();
20360 HandleScope scope(isolate);
20362 // Create two contexts with different "id" properties ('i' and 'o').
20363 // Call a function both from its own context and from a the foreign
20364 // context, and see what "this" is bound to (returning both "this"
20365 // and "this.id" for comparison).
20367 Local<Context> foreign_context = v8::Context::New(isolate);
20368 foreign_context->Enter();
20369 Local<Value> foreign_function =
20370 CompileRun("function func() { return { 0: this.id, "
20372 " toString: function() { "
20379 CHECK(foreign_function->IsFunction());
20380 foreign_context->Exit();
20382 LocalContext context;
20384 Local<String> password = v8_str("Password");
20385 // Don't get hit by security checks when accessing foreign_context's
20386 // global receiver (aka. global proxy).
20387 context->SetSecurityToken(password);
20388 foreign_context->SetSecurityToken(password);
20390 Local<String> i = v8_str("i");
20391 Local<String> o = v8_str("o");
20392 Local<String> id = v8_str("id");
20394 CompileRun("function ownfunc() { return { 0: this.id, "
20396 " toString: function() { "
20403 context->Global()->Set(v8_str("func"), foreign_function);
20405 // Sanity check the contexts.
20406 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20407 CHECK(o->Equals(context->Global()->Get(id)));
20409 // Checking local function's receiver.
20410 // Calling function using its call/apply methods.
20411 TestReceiver(o, context->Global(), "ownfunc.call()");
20412 TestReceiver(o, context->Global(), "ownfunc.apply()");
20413 // Making calls through built-in functions.
20414 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20415 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20416 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20417 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20418 // Calling with environment record as base.
20419 TestReceiver(o, context->Global(), "ownfunc()");
20420 // Calling with no base.
20421 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20423 // Checking foreign function return value.
20424 // Calling function using its call/apply methods.
20425 TestReceiver(i, foreign_context->Global(), "func.call()");
20426 TestReceiver(i, foreign_context->Global(), "func.apply()");
20427 // Calling function using another context's call/apply methods.
20428 TestReceiver(i, foreign_context->Global(),
20429 "Function.prototype.call.call(func)");
20430 TestReceiver(i, foreign_context->Global(),
20431 "Function.prototype.call.apply(func)");
20432 TestReceiver(i, foreign_context->Global(),
20433 "Function.prototype.apply.call(func)");
20434 TestReceiver(i, foreign_context->Global(),
20435 "Function.prototype.apply.apply(func)");
20436 // Making calls through built-in functions.
20437 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20438 // ToString(func()) is func()[0], i.e., the returned this.id.
20439 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20440 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20441 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20443 // Calling with environment record as base.
20444 TestReceiver(i, foreign_context->Global(), "func()");
20445 // Calling with no base.
20446 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20450 uint8_t callback_fired = 0;
20453 void CallCompletedCallback1() {
20454 i::OS::Print("Firing callback 1.\n");
20455 callback_fired ^= 1; // Toggle first bit.
20459 void CallCompletedCallback2() {
20460 i::OS::Print("Firing callback 2.\n");
20461 callback_fired ^= 2; // Toggle second bit.
20465 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20466 int32_t level = args[0]->Int32Value();
20469 i::OS::Print("Entering recursion level %d.\n", level);
20471 i::Vector<char> script_vector(script, sizeof(script));
20472 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20473 CompileRun(script_vector.start());
20474 i::OS::Print("Leaving recursion level %d.\n", level);
20475 CHECK_EQ(0, callback_fired);
20477 i::OS::Print("Recursion ends.\n");
20478 CHECK_EQ(0, callback_fired);
20483 TEST(CallCompletedCallback) {
20485 v8::HandleScope scope(env->GetIsolate());
20486 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20487 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20488 env->Global()->Set(v8_str("recursion"),
20489 recursive_runtime->GetFunction());
20490 // Adding the same callback a second time has no effect.
20491 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20492 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20493 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20494 i::OS::Print("--- Script (1) ---\n");
20495 Local<Script> script = v8::Script::Compile(
20496 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20498 CHECK_EQ(3, callback_fired);
20500 i::OS::Print("\n--- Script (2) ---\n");
20501 callback_fired = 0;
20502 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20504 CHECK_EQ(2, callback_fired);
20506 i::OS::Print("\n--- Function ---\n");
20507 callback_fired = 0;
20508 Local<Function> recursive_function =
20509 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20510 v8::Handle<Value> args[] = { v8_num(0) };
20511 recursive_function->Call(env->Global(), 1, args);
20512 CHECK_EQ(2, callback_fired);
20516 void CallCompletedCallbackNoException() {
20517 v8::HandleScope scope(CcTest::isolate());
20518 CompileRun("1+1;");
20522 void CallCompletedCallbackException() {
20523 v8::HandleScope scope(CcTest::isolate());
20524 CompileRun("throw 'second exception';");
20528 TEST(CallCompletedCallbackOneException) {
20530 v8::HandleScope scope(env->GetIsolate());
20531 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20532 CompileRun("throw 'exception';");
20536 TEST(CallCompletedCallbackTwoExceptions) {
20538 v8::HandleScope scope(env->GetIsolate());
20539 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20540 CompileRun("throw 'first exception';");
20544 static int probes_counter = 0;
20545 static int misses_counter = 0;
20546 static int updates_counter = 0;
20549 static int* LookupCounter(const char* name) {
20550 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20551 return &probes_counter;
20552 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20553 return &misses_counter;
20554 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20555 return &updates_counter;
20561 static const char* kMegamorphicTestProgram =
20562 "function ClassA() { };"
20563 "function ClassB() { };"
20564 "ClassA.prototype.foo = function() { };"
20565 "ClassB.prototype.foo = function() { };"
20566 "function fooify(obj) { obj.foo(); };"
20567 "var a = new ClassA();"
20568 "var b = new ClassB();"
20569 "for (var i = 0; i < 10000; i++) {"
20575 static void StubCacheHelper(bool primary) {
20576 V8::SetCounterFunction(LookupCounter);
20577 USE(kMegamorphicTestProgram);
20579 i::FLAG_native_code_counters = true;
20581 i::FLAG_test_primary_stub_cache = true;
20583 i::FLAG_test_secondary_stub_cache = true;
20585 i::FLAG_crankshaft = false;
20587 v8::HandleScope scope(env->GetIsolate());
20588 int initial_probes = probes_counter;
20589 int initial_misses = misses_counter;
20590 int initial_updates = updates_counter;
20591 CompileRun(kMegamorphicTestProgram);
20592 int probes = probes_counter - initial_probes;
20593 int misses = misses_counter - initial_misses;
20594 int updates = updates_counter - initial_updates;
20595 CHECK_LT(updates, 10);
20596 CHECK_LT(misses, 10);
20597 CHECK_GE(probes, 10000);
20602 TEST(SecondaryStubCache) {
20603 StubCacheHelper(true);
20607 TEST(PrimaryStubCache) {
20608 StubCacheHelper(false);
20612 static int cow_arrays_created_runtime = 0;
20615 static int* LookupCounterCOWArrays(const char* name) {
20616 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20617 return &cow_arrays_created_runtime;
20623 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20624 V8::SetCounterFunction(LookupCounterCOWArrays);
20626 i::FLAG_native_code_counters = true;
20628 v8::HandleScope scope(env->GetIsolate());
20629 int initial_cow_arrays = cow_arrays_created_runtime;
20630 CompileRun("var o = [1, 2, 3];");
20631 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20632 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20633 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20634 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20635 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20640 TEST(StaticGetters) {
20641 LocalContext context;
20642 i::Factory* factory = CcTest::i_isolate()->factory();
20643 v8::Isolate* isolate = CcTest::isolate();
20644 v8::HandleScope scope(isolate);
20645 i::Handle<i::Object> undefined_value = factory->undefined_value();
20646 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20647 i::Handle<i::Object> null_value = factory->null_value();
20648 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20649 i::Handle<i::Object> true_value = factory->true_value();
20650 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20651 i::Handle<i::Object> false_value = factory->false_value();
20652 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20656 UNINITIALIZED_TEST(IsolateEmbedderData) {
20657 CcTest::DisableAutomaticDispose();
20658 v8::Isolate* isolate = v8::Isolate::New();
20660 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20661 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20662 CHECK_EQ(NULL, isolate->GetData(slot));
20663 CHECK_EQ(NULL, i_isolate->GetData(slot));
20665 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20666 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20667 isolate->SetData(slot, data);
20669 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20670 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20671 CHECK_EQ(data, isolate->GetData(slot));
20672 CHECK_EQ(data, i_isolate->GetData(slot));
20674 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20675 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20676 isolate->SetData(slot, data);
20678 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20679 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20680 CHECK_EQ(data, isolate->GetData(slot));
20681 CHECK_EQ(data, i_isolate->GetData(slot));
20684 isolate->Dispose();
20688 TEST(StringEmpty) {
20689 LocalContext context;
20690 i::Factory* factory = CcTest::i_isolate()->factory();
20691 v8::Isolate* isolate = CcTest::isolate();
20692 v8::HandleScope scope(isolate);
20693 i::Handle<i::Object> empty_string = factory->empty_string();
20694 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20698 static int instance_checked_getter_count = 0;
20699 static void InstanceCheckedGetter(
20700 Local<String> name,
20701 const v8::PropertyCallbackInfo<v8::Value>& info) {
20702 CHECK_EQ(name, v8_str("foo"));
20703 instance_checked_getter_count++;
20704 info.GetReturnValue().Set(v8_num(11));
20708 static int instance_checked_setter_count = 0;
20709 static void InstanceCheckedSetter(Local<String> name,
20710 Local<Value> value,
20711 const v8::PropertyCallbackInfo<void>& info) {
20712 CHECK_EQ(name, v8_str("foo"));
20713 CHECK_EQ(value, v8_num(23));
20714 instance_checked_setter_count++;
20718 static void CheckInstanceCheckedResult(int getters,
20720 bool expects_callbacks,
20721 TryCatch* try_catch) {
20722 if (expects_callbacks) {
20723 CHECK(!try_catch->HasCaught());
20724 CHECK_EQ(getters, instance_checked_getter_count);
20725 CHECK_EQ(setters, instance_checked_setter_count);
20727 CHECK(try_catch->HasCaught());
20728 CHECK_EQ(0, instance_checked_getter_count);
20729 CHECK_EQ(0, instance_checked_setter_count);
20731 try_catch->Reset();
20735 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20736 instance_checked_getter_count = 0;
20737 instance_checked_setter_count = 0;
20738 TryCatch try_catch;
20740 // Test path through generic runtime code.
20741 CompileRun("obj.foo");
20742 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20743 CompileRun("obj.foo = 23");
20744 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20746 // Test path through generated LoadIC and StoredIC.
20747 CompileRun("function test_get(o) { o.foo; }"
20749 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20750 CompileRun("test_get(obj);");
20751 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20752 CompileRun("test_get(obj);");
20753 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20754 CompileRun("function test_set(o) { o.foo = 23; }"
20756 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20757 CompileRun("test_set(obj);");
20758 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20759 CompileRun("test_set(obj);");
20760 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20762 // Test path through optimized code.
20763 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20765 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20766 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20768 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20770 // Cleanup so that closures start out fresh in next check.
20771 CompileRun("%DeoptimizeFunction(test_get);"
20772 "%ClearFunctionTypeFeedback(test_get);"
20773 "%DeoptimizeFunction(test_set);"
20774 "%ClearFunctionTypeFeedback(test_set);");
20778 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20779 v8::internal::FLAG_allow_natives_syntax = true;
20780 LocalContext context;
20781 v8::HandleScope scope(context->GetIsolate());
20783 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20784 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20785 inst->SetAccessor(v8_str("foo"),
20786 InstanceCheckedGetter, InstanceCheckedSetter,
20790 v8::AccessorSignature::New(context->GetIsolate(), templ));
20791 context->Global()->Set(v8_str("f"), templ->GetFunction());
20793 printf("Testing positive ...\n");
20794 CompileRun("var obj = new f();");
20795 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20796 CheckInstanceCheckedAccessors(true);
20798 printf("Testing negative ...\n");
20799 CompileRun("var obj = {};"
20800 "obj.__proto__ = new f();");
20801 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20802 CheckInstanceCheckedAccessors(false);
20806 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20807 v8::internal::FLAG_allow_natives_syntax = true;
20808 LocalContext context;
20809 v8::HandleScope scope(context->GetIsolate());
20811 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20812 Local<ObjectTemplate> inst = templ->InstanceTemplate();
20813 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20814 inst->SetAccessor(v8_str("foo"),
20815 InstanceCheckedGetter, InstanceCheckedSetter,
20819 v8::AccessorSignature::New(context->GetIsolate(), templ));
20820 context->Global()->Set(v8_str("f"), templ->GetFunction());
20822 printf("Testing positive ...\n");
20823 CompileRun("var obj = new f();");
20824 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20825 CheckInstanceCheckedAccessors(true);
20827 printf("Testing negative ...\n");
20828 CompileRun("var obj = {};"
20829 "obj.__proto__ = new f();");
20830 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20831 CheckInstanceCheckedAccessors(false);
20835 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20836 v8::internal::FLAG_allow_natives_syntax = true;
20837 LocalContext context;
20838 v8::HandleScope scope(context->GetIsolate());
20840 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20841 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20842 proto->SetAccessor(v8_str("foo"),
20843 InstanceCheckedGetter, InstanceCheckedSetter,
20847 v8::AccessorSignature::New(context->GetIsolate(), templ));
20848 context->Global()->Set(v8_str("f"), templ->GetFunction());
20850 printf("Testing positive ...\n");
20851 CompileRun("var obj = new f();");
20852 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20853 CheckInstanceCheckedAccessors(true);
20855 printf("Testing negative ...\n");
20856 CompileRun("var obj = {};"
20857 "obj.__proto__ = new f();");
20858 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20859 CheckInstanceCheckedAccessors(false);
20861 printf("Testing positive with modified prototype chain ...\n");
20862 CompileRun("var obj = new f();"
20864 "pro.__proto__ = obj.__proto__;"
20865 "obj.__proto__ = pro;");
20866 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20867 CheckInstanceCheckedAccessors(true);
20871 TEST(TryFinallyMessage) {
20872 LocalContext context;
20873 v8::HandleScope scope(context->GetIsolate());
20875 // Test that the original error message is not lost if there is a
20876 // recursive call into Javascript is done in the finally block, e.g. to
20877 // initialize an IC. (crbug.com/129171)
20878 TryCatch try_catch;
20879 const char* trigger_ic =
20881 " throw new Error('test'); \n"
20884 " x++; \n" // Trigger an IC initialization here.
20886 CompileRun(trigger_ic);
20887 CHECK(try_catch.HasCaught());
20888 Local<Message> message = try_catch.Message();
20889 CHECK(!message.IsEmpty());
20890 CHECK_EQ(2, message->GetLineNumber());
20894 // Test that the original exception message is indeed overwritten if
20895 // a new error is thrown in the finally block.
20896 TryCatch try_catch;
20897 const char* throw_again =
20899 " throw new Error('test'); \n"
20903 " throw new Error('again'); \n" // This is the new uncaught error.
20905 CompileRun(throw_again);
20906 CHECK(try_catch.HasCaught());
20907 Local<Message> message = try_catch.Message();
20908 CHECK(!message.IsEmpty());
20909 CHECK_EQ(6, message->GetLineNumber());
20914 static void Helper137002(bool do_store,
20916 bool remove_accessor,
20917 bool interceptor) {
20918 LocalContext context;
20919 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
20921 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20923 templ->SetAccessor(v8_str("foo"),
20924 GetterWhichReturns42,
20925 SetterWhichSetsYOnThisTo23);
20927 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20929 // Turn monomorphic on slow object with native accessor, then turn
20930 // polymorphic, finally optimize to create negative lookup and fail.
20931 CompileRun(do_store ?
20932 "function f(x) { x.foo = void 0; }" :
20933 "function f(x) { return x.foo; }");
20934 CompileRun("obj.y = void 0;");
20935 if (!interceptor) {
20936 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20938 CompileRun("obj.__proto__ = null;"
20939 "f(obj); f(obj); f(obj);");
20941 CompileRun("f({});");
20943 CompileRun("obj.y = void 0;"
20944 "%OptimizeFunctionOnNextCall(f);");
20945 if (remove_accessor) {
20946 CompileRun("delete obj.foo;");
20948 CompileRun("var result = f(obj);");
20950 CompileRun("result = obj.y;");
20952 if (remove_accessor && !interceptor) {
20953 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20955 CHECK_EQ(do_store ? 23 : 42,
20956 context->Global()->Get(v8_str("result"))->Int32Value());
20961 THREADED_TEST(Regress137002a) {
20962 i::FLAG_allow_natives_syntax = true;
20963 i::FLAG_compilation_cache = false;
20964 v8::HandleScope scope(CcTest::isolate());
20965 for (int i = 0; i < 16; i++) {
20966 Helper137002(i & 8, i & 4, i & 2, i & 1);
20971 THREADED_TEST(Regress137002b) {
20972 i::FLAG_allow_natives_syntax = true;
20973 LocalContext context;
20974 v8::Isolate* isolate = context->GetIsolate();
20975 v8::HandleScope scope(isolate);
20976 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20977 templ->SetAccessor(v8_str("foo"),
20978 GetterWhichReturns42,
20979 SetterWhichSetsYOnThisTo23);
20980 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20982 // Turn monomorphic on slow object with native accessor, then just
20983 // delete the property and fail.
20984 CompileRun("function load(x) { return x.foo; }"
20985 "function store(x) { x.foo = void 0; }"
20986 "function keyed_load(x, key) { return x[key]; }"
20987 // Second version of function has a different source (add void 0)
20988 // so that it does not share code with the first version. This
20989 // ensures that the ICs are monomorphic.
20990 "function load2(x) { void 0; return x.foo; }"
20991 "function store2(x) { void 0; x.foo = void 0; }"
20992 "function keyed_load2(x, key) { void 0; return x[key]; }"
20995 "obj.__proto__ = null;"
20997 "subobj.y = void 0;"
20998 "subobj.__proto__ = obj;"
20999 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21001 // Make the ICs monomorphic.
21002 "load(obj); load(obj);"
21003 "load2(subobj); load2(subobj);"
21004 "store(obj); store(obj);"
21005 "store2(subobj); store2(subobj);"
21006 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21007 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21009 // Actually test the shiny new ICs and better not crash. This
21010 // serves as a regression test for issue 142088 as well.
21015 "keyed_load(obj, 'foo');"
21016 "keyed_load2(subobj, 'foo');"
21018 // Delete the accessor. It better not be called any more now.
21021 "subobj.y = void 0;"
21023 "var load_result = load(obj);"
21024 "var load_result2 = load2(subobj);"
21025 "var keyed_load_result = keyed_load(obj, 'foo');"
21026 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21029 "var y_from_obj = obj.y;"
21030 "var y_from_subobj = subobj.y;");
21031 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21032 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21033 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21034 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21035 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21036 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21040 THREADED_TEST(Regress142088) {
21041 i::FLAG_allow_natives_syntax = true;
21042 LocalContext context;
21043 v8::Isolate* isolate = context->GetIsolate();
21044 v8::HandleScope scope(isolate);
21045 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21046 templ->SetAccessor(v8_str("foo"),
21047 GetterWhichReturns42,
21048 SetterWhichSetsYOnThisTo23);
21049 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21051 CompileRun("function load(x) { return x.foo; }"
21052 "var o = Object.create(obj);"
21053 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21054 "load(o); load(o); load(o); load(o);");
21058 THREADED_TEST(Regress137496) {
21059 i::FLAG_expose_gc = true;
21060 LocalContext context;
21061 v8::HandleScope scope(context->GetIsolate());
21063 // Compile a try-finally clause where the finally block causes a GC
21064 // while there still is a message pending for external reporting.
21065 TryCatch try_catch;
21066 try_catch.SetVerbose(true);
21067 CompileRun("try { throw new Error(); } finally { gc(); }");
21068 CHECK(try_catch.HasCaught());
21072 THREADED_TEST(Regress149912) {
21073 LocalContext context;
21074 v8::HandleScope scope(context->GetIsolate());
21075 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21076 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21077 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21078 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21082 THREADED_TEST(Regress157124) {
21083 LocalContext context;
21084 v8::Isolate* isolate = context->GetIsolate();
21085 v8::HandleScope scope(isolate);
21086 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21087 Local<Object> obj = templ->NewInstance();
21088 obj->GetIdentityHash();
21089 obj->DeleteHiddenValue(v8_str("Bug"));
21093 THREADED_TEST(Regress2535) {
21094 i::FLAG_harmony_collections = true;
21095 LocalContext context;
21096 v8::HandleScope scope(context->GetIsolate());
21097 Local<Value> set_value = CompileRun("new Set();");
21098 Local<Object> set_object(Local<Object>::Cast(set_value));
21099 CHECK_EQ(0, set_object->InternalFieldCount());
21100 Local<Value> map_value = CompileRun("new Map();");
21101 Local<Object> map_object(Local<Object>::Cast(map_value));
21102 CHECK_EQ(0, map_object->InternalFieldCount());
21106 THREADED_TEST(Regress2746) {
21107 LocalContext context;
21108 v8::Isolate* isolate = context->GetIsolate();
21109 v8::HandleScope scope(isolate);
21110 Local<Object> obj = Object::New(isolate);
21111 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21112 obj->SetHiddenValue(key, v8::Undefined(isolate));
21113 Local<Value> value = obj->GetHiddenValue(key);
21114 CHECK(!value.IsEmpty());
21115 CHECK(value->IsUndefined());
21119 THREADED_TEST(Regress260106) {
21120 LocalContext context;
21121 v8::Isolate* isolate = context->GetIsolate();
21122 v8::HandleScope scope(isolate);
21123 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21125 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21126 Local<Function> function = templ->GetFunction();
21127 CHECK(!function.IsEmpty());
21128 CHECK(function->IsFunction());
21132 THREADED_TEST(JSONParseObject) {
21133 LocalContext context;
21134 HandleScope scope(context->GetIsolate());
21135 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21136 Handle<Object> global = context->Global();
21137 global->Set(v8_str("obj"), obj);
21138 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21142 THREADED_TEST(JSONParseNumber) {
21143 LocalContext context;
21144 HandleScope scope(context->GetIsolate());
21145 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21146 Handle<Object> global = context->Global();
21147 global->Set(v8_str("obj"), obj);
21148 ExpectString("JSON.stringify(obj)", "42");
21153 class ThreadInterruptTest {
21155 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21156 ~ThreadInterruptTest() {}
21159 InterruptThread i_thread(this);
21163 CHECK_EQ(kExpectedValue, sem_value_);
21167 static const int kExpectedValue = 1;
21169 class InterruptThread : public i::Thread {
21171 explicit InterruptThread(ThreadInterruptTest* test)
21172 : Thread("InterruptThread"), test_(test) {}
21174 virtual void Run() {
21175 struct sigaction action;
21177 // Ensure that we'll enter waiting condition
21180 // Setup signal handler
21181 memset(&action, 0, sizeof(action));
21182 action.sa_handler = SignalHandler;
21183 sigaction(SIGCHLD, &action, NULL);
21186 kill(getpid(), SIGCHLD);
21188 // Ensure that if wait has returned because of error
21191 // Set value and signal semaphore
21192 test_->sem_value_ = 1;
21193 test_->sem_.Signal();
21196 static void SignalHandler(int signal) {
21200 ThreadInterruptTest* test_;
21204 volatile int sem_value_;
21208 THREADED_TEST(SemaphoreInterruption) {
21209 ThreadInterruptTest().RunTest();
21213 #endif // V8_OS_POSIX
21216 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21218 v8::AccessType type,
21219 Local<Value> data) {
21220 i::PrintF("Named access blocked.\n");
21225 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21227 v8::AccessType type,
21228 Local<Value> data) {
21229 i::PrintF("Indexed access blocked.\n");
21234 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21239 TEST(JSONStringifyAccessCheck) {
21240 v8::V8::Initialize();
21241 v8::Isolate* isolate = CcTest::isolate();
21242 v8::HandleScope scope(isolate);
21244 // Create an ObjectTemplate for global objects and install access
21245 // check callbacks that will block access.
21246 v8::Handle<v8::ObjectTemplate> global_template =
21247 v8::ObjectTemplate::New(isolate);
21248 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21249 IndexAccessAlwaysBlocked);
21251 // Create a context and set an x property on it's global object.
21252 LocalContext context0(NULL, global_template);
21253 v8::Handle<v8::Object> global0 = context0->Global();
21254 global0->Set(v8_str("x"), v8_num(42));
21255 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21257 for (int i = 0; i < 2; i++) {
21259 // Install a toJSON function on the second run.
21260 v8::Handle<v8::FunctionTemplate> toJSON =
21261 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21263 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21265 // Create a context with a different security token so that the
21266 // failed access check callback will be called on each access.
21267 LocalContext context1(NULL, global_template);
21268 context1->Global()->Set(v8_str("other"), global0);
21270 ExpectString("JSON.stringify(other)", "{}");
21271 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21272 "{\"a\":{},\"b\":[\"c\"]}");
21273 ExpectString("JSON.stringify([other, 'b', 'c'])",
21274 "[{},\"b\",\"c\"]");
21276 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21277 array->Set(0, v8_str("a"));
21278 array->Set(1, v8_str("b"));
21279 context1->Global()->Set(v8_str("array"), array);
21280 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21281 array->TurnOnAccessCheck();
21282 ExpectString("JSON.stringify(array)", "[]");
21283 ExpectString("JSON.stringify([array])", "[[]]");
21284 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21289 bool access_check_fail_thrown = false;
21290 bool catch_callback_called = false;
21293 // Failed access check callback that performs a GC on each invocation.
21294 void FailedAccessCheckThrows(Local<v8::Object> target,
21295 v8::AccessType type,
21296 Local<v8::Value> data) {
21297 access_check_fail_thrown = true;
21298 i::PrintF("Access check failed. Error thrown.\n");
21299 CcTest::isolate()->ThrowException(
21300 v8::Exception::Error(v8_str("cross context")));
21304 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21305 for (int i = 0; i < args.Length(); i++) {
21306 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21308 catch_callback_called = true;
21312 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21313 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21317 void CheckCorrectThrow(const char* script) {
21318 // Test that the script, when wrapped into a try-catch, triggers the catch
21319 // clause due to failed access check throwing an exception.
21320 // The subsequent try-catch should run without any exception.
21321 access_check_fail_thrown = false;
21322 catch_callback_called = false;
21323 i::ScopedVector<char> source(1024);
21324 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21325 CompileRun(source.start());
21326 CHECK(access_check_fail_thrown);
21327 CHECK(catch_callback_called);
21329 access_check_fail_thrown = false;
21330 catch_callback_called = false;
21331 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21332 CHECK(!access_check_fail_thrown);
21333 CHECK(!catch_callback_called);
21337 TEST(AccessCheckThrows) {
21338 i::FLAG_allow_natives_syntax = true;
21339 v8::V8::Initialize();
21340 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21341 v8::Isolate* isolate = CcTest::isolate();
21342 v8::HandleScope scope(isolate);
21344 // Create an ObjectTemplate for global objects and install access
21345 // check callbacks that will block access.
21346 v8::Handle<v8::ObjectTemplate> global_template =
21347 v8::ObjectTemplate::New(isolate);
21348 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21349 IndexAccessAlwaysBlocked);
21351 // Create a context and set an x property on it's global object.
21352 LocalContext context0(NULL, global_template);
21353 context0->Global()->Set(v8_str("x"), v8_num(42));
21354 v8::Handle<v8::Object> global0 = context0->Global();
21356 // Create a context with a different security token so that the
21357 // failed access check callback will be called on each access.
21358 LocalContext context1(NULL, global_template);
21359 context1->Global()->Set(v8_str("other"), global0);
21361 v8::Handle<v8::FunctionTemplate> catcher_fun =
21362 v8::FunctionTemplate::New(isolate, CatcherCallback);
21363 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21365 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21366 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21367 context1->Global()->Set(v8_str("has_own_property"),
21368 has_own_property_fun->GetFunction());
21370 { v8::TryCatch try_catch;
21371 access_check_fail_thrown = false;
21372 CompileRun("other.x;");
21373 CHECK(access_check_fail_thrown);
21374 CHECK(try_catch.HasCaught());
21377 CheckCorrectThrow("other.x");
21378 CheckCorrectThrow("other[1]");
21379 CheckCorrectThrow("JSON.stringify(other)");
21380 CheckCorrectThrow("has_own_property(other, 'x')");
21381 CheckCorrectThrow("%GetProperty(other, 'x')");
21382 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21383 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21384 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21385 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21386 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21387 CheckCorrectThrow("%HasProperty(other, 'x')");
21388 CheckCorrectThrow("%HasElement(other, 1)");
21389 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21390 CheckCorrectThrow("%GetPropertyNames(other)");
21391 // PROPERTY_ATTRIBUTES_NONE = 0
21392 CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21393 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21394 "other, 'x', null, null, 1)");
21396 // Reset the failed access check callback so it does not influence
21397 // the other tests.
21398 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21402 THREADED_TEST(Regress256330) {
21403 i::FLAG_allow_natives_syntax = true;
21404 LocalContext context;
21405 v8::HandleScope scope(context->GetIsolate());
21406 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21407 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21408 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21409 CompileRun("\"use strict\"; var o = new Bug;"
21410 "function f(o) { o.x = 10; };"
21411 "f(o); f(o); f(o);"
21412 "%OptimizeFunctionOnNextCall(f);"
21414 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21418 THREADED_TEST(CrankshaftInterceptorSetter) {
21419 i::FLAG_allow_natives_syntax = true;
21420 v8::HandleScope scope(CcTest::isolate());
21421 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21422 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21424 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21425 CompileRun("var obj = new Obj;"
21426 // Initialize fields to avoid transitions later.
21428 "obj.accessor_age = 42;"
21429 "function setter(i) { this.accessor_age = i; };"
21430 "function getter() { return this.accessor_age; };"
21431 "function setAge(i) { obj.age = i; };"
21432 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21436 "%OptimizeFunctionOnNextCall(setAge);"
21438 // All stores went through the interceptor.
21439 ExpectInt32("obj.interceptor_age", 4);
21440 ExpectInt32("obj.accessor_age", 42);
21444 THREADED_TEST(CrankshaftInterceptorGetter) {
21445 i::FLAG_allow_natives_syntax = true;
21446 v8::HandleScope scope(CcTest::isolate());
21447 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21448 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21450 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21451 CompileRun("var obj = new Obj;"
21452 // Initialize fields to avoid transitions later.
21454 "obj.accessor_age = 42;"
21455 "function getter() { return this.accessor_age; };"
21456 "function getAge() { return obj.interceptor_age; };"
21457 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21461 "%OptimizeFunctionOnNextCall(getAge);");
21462 // Access through interceptor.
21463 ExpectInt32("getAge()", 1);
21467 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21468 i::FLAG_allow_natives_syntax = true;
21469 v8::HandleScope scope(CcTest::isolate());
21470 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21471 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21473 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21474 CompileRun("var obj = new Obj;"
21475 "obj.__proto__.interceptor_age = 42;"
21477 "function getAge() { return obj.interceptor_age; };");
21478 ExpectInt32("getAge();", 100);
21479 ExpectInt32("getAge();", 100);
21480 ExpectInt32("getAge();", 100);
21481 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21482 // Access through interceptor.
21483 ExpectInt32("getAge();", 100);
21487 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21488 i::FLAG_allow_natives_syntax = true;
21489 v8::HandleScope scope(CcTest::isolate());
21490 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21491 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21493 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21494 CompileRun("var obj = new Obj;"
21495 "obj.age = 100000;"
21496 "function setAge(i) { obj.age = i };"
21500 "%OptimizeFunctionOnNextCall(setAge);"
21502 ExpectInt32("obj.age", 100000);
21503 ExpectInt32("obj.interceptor_age", 103);
21507 class RequestInterruptTestBase {
21509 RequestInterruptTestBase()
21511 isolate_(env_->GetIsolate()),
21514 should_continue_(true) {
21517 virtual ~RequestInterruptTestBase() { }
21519 virtual void TestBody() = 0;
21522 InterruptThread i_thread(this);
21525 v8::HandleScope handle_scope(isolate_);
21529 isolate_->ClearInterrupt();
21531 // Verify we arrived here because interruptor was called
21532 // not due to a bug causing us to exit the loop too early.
21533 CHECK(!should_continue());
21536 void WakeUpInterruptor() {
21540 bool should_continue() const { return should_continue_; }
21542 bool ShouldContinue() {
21544 if (--warmup_ == 0) {
21545 WakeUpInterruptor();
21549 return should_continue_;
21553 static void ShouldContinueCallback(
21554 const v8::FunctionCallbackInfo<Value>& info) {
21555 RequestInterruptTestBase* test =
21556 reinterpret_cast<RequestInterruptTestBase*>(
21557 info.Data().As<v8::External>()->Value());
21558 info.GetReturnValue().Set(test->ShouldContinue());
21561 class InterruptThread : public i::Thread {
21563 explicit InterruptThread(RequestInterruptTestBase* test)
21564 : Thread("RequestInterruptTest"), test_(test) {}
21566 virtual void Run() {
21567 test_->sem_.Wait();
21568 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21571 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21572 reinterpret_cast<RequestInterruptTestBase*>(data)->
21573 should_continue_ = false;
21577 RequestInterruptTestBase* test_;
21581 v8::Isolate* isolate_;
21584 bool should_continue_;
21588 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21590 virtual void TestBody() {
21591 Local<Function> func = Function::New(
21592 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21593 env_->Global()->Set(v8_str("ShouldContinue"), func);
21595 CompileRun("while (ShouldContinue()) { }");
21600 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21602 virtual void TestBody() {
21603 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21604 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21605 proto->Set(v8_str("shouldContinue"), Function::New(
21606 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21607 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21609 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21614 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21616 virtual void TestBody() {
21617 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21618 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21619 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21620 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21621 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21623 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21628 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21630 virtual void TestBody() {
21631 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21632 t->InstanceTemplate()->SetNativeDataProperty(
21633 v8_str("shouldContinue"),
21634 &ShouldContinueNativeGetter,
21636 v8::External::New(isolate_, this));
21637 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21639 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21643 static void ShouldContinueNativeGetter(
21644 Local<String> property,
21645 const v8::PropertyCallbackInfo<v8::Value>& info) {
21646 RequestInterruptTestBase* test =
21647 reinterpret_cast<RequestInterruptTestBase*>(
21648 info.Data().As<v8::External>()->Value());
21649 info.GetReturnValue().Set(test->ShouldContinue());
21654 class RequestInterruptTestWithMethodCallAndInterceptor
21655 : public RequestInterruptTestBase {
21657 virtual void TestBody() {
21658 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21659 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21660 proto->Set(v8_str("shouldContinue"), Function::New(
21661 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21662 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21663 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21665 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21667 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21671 static void EmptyInterceptor(
21672 Local<String> property,
21673 const v8::PropertyCallbackInfo<v8::Value>& info) {
21678 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21680 virtual void TestBody() {
21681 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21683 WakeUpInterruptorCallback,
21684 v8::External::New(isolate_, this)));
21686 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21688 ShouldContinueCallback,
21689 v8::External::New(isolate_, this)));
21691 i::FLAG_allow_natives_syntax = true;
21692 CompileRun("function loopish(o) {"
21694 " while (o.abs(1) > 0) {"
21695 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21697 " if (--pre === 0) WakeUpInterruptor(o === Math);"
21702 "var obj = {abs: function () { return i-- }, x: null};"
21705 "%OptimizeFunctionOnNextCall(loopish);"
21708 i::FLAG_allow_natives_syntax = false;
21712 static void WakeUpInterruptorCallback(
21713 const v8::FunctionCallbackInfo<Value>& info) {
21714 if (!info[0]->BooleanValue()) return;
21716 RequestInterruptTestBase* test =
21717 reinterpret_cast<RequestInterruptTestBase*>(
21718 info.Data().As<v8::External>()->Value());
21719 test->WakeUpInterruptor();
21722 static void ShouldContinueCallback(
21723 const v8::FunctionCallbackInfo<Value>& info) {
21724 RequestInterruptTestBase* test =
21725 reinterpret_cast<RequestInterruptTestBase*>(
21726 info.Data().As<v8::External>()->Value());
21727 info.GetReturnValue().Set(test->should_continue());
21732 TEST(RequestInterruptTestWithFunctionCall) {
21733 RequestInterruptTestWithFunctionCall().RunTest();
21737 TEST(RequestInterruptTestWithMethodCall) {
21738 RequestInterruptTestWithMethodCall().RunTest();
21742 TEST(RequestInterruptTestWithAccessor) {
21743 RequestInterruptTestWithAccessor().RunTest();
21747 TEST(RequestInterruptTestWithNativeAccessor) {
21748 RequestInterruptTestWithNativeAccessor().RunTest();
21752 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21753 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21757 TEST(RequestInterruptTestWithMathAbs) {
21758 RequestInterruptTestWithMathAbs().RunTest();
21762 static Local<Value> function_new_expected_env;
21763 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21764 CHECK_EQ(function_new_expected_env, info.Data());
21765 info.GetReturnValue().Set(17);
21769 THREADED_TEST(FunctionNew) {
21771 v8::Isolate* isolate = env->GetIsolate();
21772 v8::HandleScope scope(isolate);
21773 Local<Object> data = v8::Object::New(isolate);
21774 function_new_expected_env = data;
21775 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21776 env->Global()->Set(v8_str("func"), func);
21777 Local<Value> result = CompileRun("func();");
21778 CHECK_EQ(v8::Integer::New(isolate, 17), result);
21779 // Verify function not cached
21780 int serial_number =
21781 i::Smi::cast(v8::Utils::OpenHandle(*func)
21782 ->shared()->get_api_func_data()->serial_number())->value();
21783 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21784 i::Object* elm = i_isolate->native_context()->function_cache()
21785 ->GetElementNoExceptionThrown(i_isolate, serial_number);
21786 CHECK(elm->IsUndefined());
21787 // Verify that each Function::New creates a new function instance
21788 Local<Object> data2 = v8::Object::New(isolate);
21789 function_new_expected_env = data2;
21790 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21791 CHECK(!func2->IsNull());
21792 CHECK_NE(func, func2);
21793 env->Global()->Set(v8_str("func2"), func2);
21794 Local<Value> result2 = CompileRun("func2();");
21795 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21799 TEST(EscapeableHandleScope) {
21800 HandleScope outer_scope(CcTest::isolate());
21801 LocalContext context;
21802 const int runs = 10;
21803 Local<String> values[runs];
21804 for (int i = 0; i < runs; i++) {
21805 v8::EscapableHandleScope inner_scope(CcTest::isolate());
21806 Local<String> value;
21807 if (i != 0) value = v8_str("escape value");
21808 values[i] = inner_scope.Escape(value);
21810 for (int i = 0; i < runs; i++) {
21811 Local<String> expected;
21813 CHECK_EQ(v8_str("escape value"), values[i]);
21815 CHECK(values[i].IsEmpty());
21821 static void SetterWhichExpectsThisAndHolderToDiffer(
21822 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21823 CHECK(info.Holder() != info.This());
21827 TEST(Regress239669) {
21828 LocalContext context;
21829 v8::Isolate* isolate = context->GetIsolate();
21830 v8::HandleScope scope(isolate);
21831 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21832 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21833 context->Global()->Set(v8_str("P"), templ->NewInstance());
21838 "C1.prototype = P;"
21839 "for (var i = 0; i < 4; i++ ) {"