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 = v8::String::New("my_profile1");
92 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
94 cpu_profiler->StartCpuProfiling(profile_name);
96 cpu_profiler->DeleteAllCpuProfiles();
100 static void ExpectString(const char* code, const char* expected) {
101 Local<Value> result = CompileRun(code);
102 CHECK(result->IsString());
103 String::Utf8Value utf8(result);
104 CHECK_EQ(expected, *utf8);
108 static void ExpectInt32(const char* code, int expected) {
109 Local<Value> result = CompileRun(code);
110 CHECK(result->IsInt32());
111 CHECK_EQ(expected, result->Int32Value());
115 static void ExpectBoolean(const char* code, bool expected) {
116 Local<Value> result = CompileRun(code);
117 CHECK(result->IsBoolean());
118 CHECK_EQ(expected, result->BooleanValue());
122 static void ExpectTrue(const char* code) {
123 ExpectBoolean(code, true);
127 static void ExpectFalse(const char* code) {
128 ExpectBoolean(code, false);
132 static void ExpectObject(const char* code, Local<Value> expected) {
133 Local<Value> result = CompileRun(code);
134 CHECK(result->Equals(expected));
138 static void ExpectUndefined(const char* code) {
139 Local<Value> result = CompileRun(code);
140 CHECK(result->IsUndefined());
144 static int signature_callback_count;
145 static Local<Value> signature_expected_receiver;
146 static void IncrementingSignatureCallback(
147 const v8::FunctionCallbackInfo<v8::Value>& args) {
148 ApiTestFuzzer::Fuzz();
149 signature_callback_count++;
150 CHECK_EQ(signature_expected_receiver, args.Holder());
151 CHECK_EQ(signature_expected_receiver, args.This());
152 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
153 for (int i = 0; i < args.Length(); i++)
154 result->Set(v8::Integer::New(i), args[i]);
155 args.GetReturnValue().Set(result);
159 static void SignatureCallback(
160 const v8::FunctionCallbackInfo<v8::Value>& args) {
161 ApiTestFuzzer::Fuzz();
162 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
163 for (int i = 0; i < args.Length(); i++) {
164 result->Set(v8::Integer::New(i), args[i]);
166 args.GetReturnValue().Set(result);
170 // Tests that call v8::V8::Dispose() cannot be threaded.
171 TEST(InitializeAndDisposeOnce) {
172 CHECK(v8::V8::Initialize());
173 CHECK(v8::V8::Dispose());
177 // Tests that call v8::V8::Dispose() cannot be threaded.
178 TEST(InitializeAndDisposeMultiple) {
179 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
180 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
181 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
182 // TODO(mstarzinger): This should fail gracefully instead of asserting.
183 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
184 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
188 THREADED_TEST(Handles) {
189 v8::HandleScope scope(CcTest::isolate());
190 Local<Context> local_env;
193 local_env = env.local();
196 // Local context should still be live.
197 CHECK(!local_env.IsEmpty());
200 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
201 CHECK(!undef.IsEmpty());
202 CHECK(undef->IsUndefined());
204 const char* c_source = "1 + 2 + 3";
205 Local<String> source = String::New(c_source);
206 Local<Script> script = Script::Compile(source);
207 CHECK_EQ(6, script->Run()->Int32Value());
213 THREADED_TEST(IsolateOfContext) {
214 v8::HandleScope scope(CcTest::isolate());
215 v8::Handle<Context> env = Context::New(CcTest::isolate());
217 CHECK(!env->InContext());
218 CHECK(env->GetIsolate() == CcTest::isolate());
220 CHECK(env->InContext());
221 CHECK(env->GetIsolate() == CcTest::isolate());
223 CHECK(!env->InContext());
224 CHECK(env->GetIsolate() == CcTest::isolate());
228 static void TestSignature(const char* loop_js, Local<Value> receiver) {
229 i::ScopedVector<char> source(200);
230 i::OS::SNPrintF(source,
231 "for (var i = 0; i < 10; i++) {"
235 signature_callback_count = 0;
236 signature_expected_receiver = receiver;
237 bool expected_to_throw = receiver.IsEmpty();
238 v8::TryCatch try_catch;
239 CompileRun(source.start());
240 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
241 if (!expected_to_throw) {
242 CHECK_EQ(10, signature_callback_count);
244 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
245 try_catch.Exception()->ToString());
250 THREADED_TEST(ReceiverSignature) {
252 v8::HandleScope scope(env->GetIsolate());
254 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
255 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
256 v8::Handle<v8::FunctionTemplate> callback_sig =
257 v8::FunctionTemplate::New(
258 IncrementingSignatureCallback, Local<Value>(), sig);
259 v8::Handle<v8::FunctionTemplate> callback =
260 v8::FunctionTemplate::New(IncrementingSignatureCallback);
261 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
262 sub_fun->Inherit(fun);
263 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
264 // Install properties.
265 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
266 fun_proto->Set(v8_str("prop_sig"), callback_sig);
267 fun_proto->Set(v8_str("prop"), callback);
268 fun_proto->SetAccessorProperty(
269 v8_str("accessor_sig"), callback_sig, callback_sig);
270 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
271 // Instantiate templates.
272 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
273 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
274 // Setup global variables.
275 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
276 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
277 env->Global()->Set(v8_str("fun_instance"), fun_instance);
278 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
280 "var accessor_sig_key = 'accessor_sig';"
281 "var accessor_key = 'accessor';"
282 "var prop_sig_key = 'prop_sig';"
283 "var prop_key = 'prop';"
285 "function copy_props(obj) {"
286 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
287 " var source = Fun.prototype;"
288 " for (var i in keys) {"
289 " var key = keys[i];"
290 " var desc = Object.getOwnPropertyDescriptor(source, key);"
291 " Object.defineProperty(obj, key, desc);"
297 "var unrel = new UnrelFun();"
298 "copy_props(unrel);");
299 // Test with and without ICs
300 const char* test_objects[] = {
301 "fun_instance", "sub_fun_instance", "obj", "unrel" };
302 unsigned bad_signature_start_offset = 2;
303 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
304 i::ScopedVector<char> source(200);
306 source, "var test_object = %s; test_object", test_objects[i]);
307 Local<Value> test_object = CompileRun(source.start());
308 TestSignature("test_object.prop();", test_object);
309 TestSignature("test_object.accessor;", test_object);
310 TestSignature("test_object[accessor_key];", test_object);
311 TestSignature("test_object.accessor = 1;", test_object);
312 TestSignature("test_object[accessor_key] = 1;", test_object);
313 if (i >= bad_signature_start_offset) test_object = Local<Value>();
314 TestSignature("test_object.prop_sig();", test_object);
315 TestSignature("test_object.accessor_sig;", test_object);
316 TestSignature("test_object[accessor_sig_key];", test_object);
317 TestSignature("test_object.accessor_sig = 1;", test_object);
318 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
323 THREADED_TEST(ArgumentSignature) {
325 v8::HandleScope scope(env->GetIsolate());
326 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
327 cons->SetClassName(v8_str("Cons"));
328 v8::Handle<v8::Signature> sig =
329 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
330 v8::Handle<v8::FunctionTemplate> fun =
331 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
332 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
333 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
335 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
336 CHECK(value1->IsTrue());
338 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
339 CHECK(value2->IsTrue());
341 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
342 CHECK(value3->IsTrue());
344 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
345 cons1->SetClassName(v8_str("Cons1"));
346 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
347 cons2->SetClassName(v8_str("Cons2"));
348 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
349 cons3->SetClassName(v8_str("Cons3"));
351 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
352 v8::Handle<v8::Signature> wsig =
353 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
354 v8::Handle<v8::FunctionTemplate> fun2 =
355 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
357 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
358 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
359 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
360 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
361 v8::Handle<Value> value4 = CompileRun(
362 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
363 "'[object Cons1],[object Cons2],[object Cons3]'");
364 CHECK(value4->IsTrue());
366 v8::Handle<Value> value5 = CompileRun(
367 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
368 CHECK(value5->IsTrue());
370 v8::Handle<Value> value6 = CompileRun(
371 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
372 CHECK(value6->IsTrue());
374 v8::Handle<Value> value7 = CompileRun(
375 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
376 "'[object Cons1],[object Cons2],[object Cons3],d';");
377 CHECK(value7->IsTrue());
379 v8::Handle<Value> value8 = CompileRun(
380 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
381 CHECK(value8->IsTrue());
385 THREADED_TEST(HulIgennem) {
387 v8::Isolate* isolate = env->GetIsolate();
388 v8::HandleScope scope(isolate);
389 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
390 Local<String> undef_str = undef->ToString();
391 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
392 undef_str->WriteUtf8(value);
393 CHECK_EQ(0, strcmp(value, "undefined"));
394 i::DeleteArray(value);
398 THREADED_TEST(Access) {
400 v8::Isolate* isolate = env->GetIsolate();
401 v8::HandleScope scope(isolate);
402 Local<v8::Object> obj = v8::Object::New();
403 Local<Value> foo_before = obj->Get(v8_str("foo"));
404 CHECK(foo_before->IsUndefined());
405 Local<String> bar_str = v8_str("bar");
406 obj->Set(v8_str("foo"), bar_str);
407 Local<Value> foo_after = obj->Get(v8_str("foo"));
408 CHECK(!foo_after->IsUndefined());
409 CHECK(foo_after->IsString());
410 CHECK_EQ(bar_str, foo_after);
414 THREADED_TEST(AccessElement) {
416 v8::HandleScope scope(env->GetIsolate());
417 Local<v8::Object> obj = v8::Object::New();
418 Local<Value> before = obj->Get(1);
419 CHECK(before->IsUndefined());
420 Local<String> bar_str = v8_str("bar");
421 obj->Set(1, bar_str);
422 Local<Value> after = obj->Get(1);
423 CHECK(!after->IsUndefined());
424 CHECK(after->IsString());
425 CHECK_EQ(bar_str, after);
427 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
428 CHECK_EQ(v8_str("a"), value->Get(0));
429 CHECK_EQ(v8_str("b"), value->Get(1));
433 THREADED_TEST(Script) {
435 v8::HandleScope scope(env->GetIsolate());
436 const char* c_source = "1 + 2 + 3";
437 Local<String> source = String::New(c_source);
438 Local<Script> script = Script::Compile(source);
439 CHECK_EQ(6, script->Run()->Int32Value());
443 static uint16_t* AsciiToTwoByteString(const char* source) {
444 int array_length = i::StrLength(source) + 1;
445 uint16_t* converted = i::NewArray<uint16_t>(array_length);
446 for (int i = 0; i < array_length; i++) converted[i] = source[i];
451 class TestResource: public String::ExternalStringResource {
453 explicit TestResource(uint16_t* data, int* counter = NULL)
454 : data_(data), length_(0), counter_(counter) {
455 while (data[length_]) ++length_;
459 i::DeleteArray(data_);
460 if (counter_ != NULL) ++*counter_;
463 const uint16_t* data() const {
467 size_t length() const {
477 class TestAsciiResource: public String::ExternalAsciiStringResource {
479 explicit TestAsciiResource(const char* data, int* counter = NULL)
480 : data_(data), length_(strlen(data)), counter_(counter) { }
482 ~TestAsciiResource() {
483 i::DeleteArray(data_);
484 if (counter_ != NULL) ++*counter_;
487 const char* data() const {
491 size_t length() const {
501 THREADED_TEST(ScriptUsingStringResource) {
502 int dispose_count = 0;
503 const char* c_source = "1 + 2 * 3";
504 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
507 v8::HandleScope scope(env->GetIsolate());
508 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
509 Local<String> source = String::NewExternal(resource);
510 Local<Script> script = Script::Compile(source);
511 Local<Value> value = script->Run();
512 CHECK(value->IsNumber());
513 CHECK_EQ(7, value->Int32Value());
514 CHECK(source->IsExternal());
516 static_cast<TestResource*>(source->GetExternalStringResource()));
517 String::Encoding encoding = String::UNKNOWN_ENCODING;
518 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
519 source->GetExternalStringResourceBase(&encoding));
520 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
521 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
522 CHECK_EQ(0, dispose_count);
524 CcTest::i_isolate()->compilation_cache()->Clear();
525 CcTest::heap()->CollectAllAvailableGarbage();
526 CHECK_EQ(1, dispose_count);
530 THREADED_TEST(ScriptUsingAsciiStringResource) {
531 int dispose_count = 0;
532 const char* c_source = "1 + 2 * 3";
535 v8::HandleScope scope(env->GetIsolate());
536 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
538 Local<String> source = String::NewExternal(resource);
539 CHECK(source->IsExternalAscii());
540 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
541 source->GetExternalAsciiStringResource());
542 String::Encoding encoding = String::UNKNOWN_ENCODING;
543 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
544 source->GetExternalStringResourceBase(&encoding));
545 CHECK_EQ(String::ASCII_ENCODING, encoding);
546 Local<Script> script = Script::Compile(source);
547 Local<Value> value = script->Run();
548 CHECK(value->IsNumber());
549 CHECK_EQ(7, value->Int32Value());
550 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
551 CHECK_EQ(0, dispose_count);
553 CcTest::i_isolate()->compilation_cache()->Clear();
554 CcTest::heap()->CollectAllAvailableGarbage();
555 CHECK_EQ(1, dispose_count);
559 THREADED_TEST(ScriptMakingExternalString) {
560 int dispose_count = 0;
561 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
564 v8::HandleScope scope(env->GetIsolate());
565 Local<String> source = String::New(two_byte_source);
566 // Trigger GCs so that the newly allocated string moves to old gen.
567 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
569 CHECK_EQ(source->IsExternal(), false);
570 CHECK_EQ(source->IsExternalAscii(), false);
571 String::Encoding encoding = String::UNKNOWN_ENCODING;
572 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
573 CHECK_EQ(String::ASCII_ENCODING, encoding);
574 bool success = source->MakeExternal(new TestResource(two_byte_source,
577 Local<Script> script = Script::Compile(source);
578 Local<Value> value = script->Run();
579 CHECK(value->IsNumber());
580 CHECK_EQ(7, value->Int32Value());
581 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
582 CHECK_EQ(0, dispose_count);
584 CcTest::i_isolate()->compilation_cache()->Clear();
585 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
586 CHECK_EQ(1, dispose_count);
590 THREADED_TEST(ScriptMakingExternalAsciiString) {
591 int dispose_count = 0;
592 const char* c_source = "1 + 2 * 3";
595 v8::HandleScope scope(env->GetIsolate());
596 Local<String> source = v8_str(c_source);
597 // Trigger GCs so that the newly allocated string moves to old gen.
598 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
599 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
600 bool success = source->MakeExternal(
601 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
603 Local<Script> script = Script::Compile(source);
604 Local<Value> value = script->Run();
605 CHECK(value->IsNumber());
606 CHECK_EQ(7, value->Int32Value());
607 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
608 CHECK_EQ(0, dispose_count);
610 CcTest::i_isolate()->compilation_cache()->Clear();
611 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
612 CHECK_EQ(1, dispose_count);
616 TEST(MakingExternalStringConditions) {
618 v8::HandleScope scope(env->GetIsolate());
620 // Free some space in the new space so that we can check freshness.
621 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
622 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
624 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
625 Local<String> small_string = String::New(two_byte_string);
626 i::DeleteArray(two_byte_string);
628 // We should refuse to externalize newly created small string.
629 CHECK(!small_string->CanMakeExternal());
630 // Trigger GCs so that the newly allocated string moves to old gen.
631 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
632 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
633 // Old space strings should be accepted.
634 CHECK(small_string->CanMakeExternal());
636 two_byte_string = AsciiToTwoByteString("small string 2");
637 small_string = String::New(two_byte_string);
638 i::DeleteArray(two_byte_string);
640 // We should refuse externalizing newly created small string.
641 CHECK(!small_string->CanMakeExternal());
642 for (int i = 0; i < 100; i++) {
643 String::Value value(small_string);
645 // Frequently used strings should be accepted.
646 CHECK(small_string->CanMakeExternal());
648 const int buf_size = 10 * 1024;
649 char* buf = i::NewArray<char>(buf_size);
650 memset(buf, 'a', buf_size);
651 buf[buf_size - 1] = '\0';
653 two_byte_string = AsciiToTwoByteString(buf);
654 Local<String> large_string = String::New(two_byte_string);
656 i::DeleteArray(two_byte_string);
657 // Large strings should be immediately accepted.
658 CHECK(large_string->CanMakeExternal());
662 TEST(MakingExternalAsciiStringConditions) {
664 v8::HandleScope scope(env->GetIsolate());
666 // Free some space in the new space so that we can check freshness.
667 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
668 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
670 Local<String> small_string = String::New("s1");
671 // We should refuse to externalize newly created small string.
672 CHECK(!small_string->CanMakeExternal());
673 // Trigger GCs so that the newly allocated string moves to old gen.
674 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
675 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
676 // Old space strings should be accepted.
677 CHECK(small_string->CanMakeExternal());
679 small_string = String::New("small string 2");
680 // We should refuse externalizing newly created small string.
681 CHECK(!small_string->CanMakeExternal());
682 for (int i = 0; i < 100; i++) {
683 String::Value value(small_string);
685 // Frequently used strings should be accepted.
686 CHECK(small_string->CanMakeExternal());
688 const int buf_size = 10 * 1024;
689 char* buf = i::NewArray<char>(buf_size);
690 memset(buf, 'a', buf_size);
691 buf[buf_size - 1] = '\0';
692 Local<String> large_string = String::New(buf);
694 // Large strings should be immediately accepted.
695 CHECK(large_string->CanMakeExternal());
699 TEST(MakingExternalUnalignedAsciiString) {
701 v8::HandleScope scope(env->GetIsolate());
703 CompileRun("function cons(a, b) { return a + b; }"
704 "function slice(a) { return a.substring(1); }");
705 // Create a cons string that will land in old pointer space.
706 Local<String> cons = Local<String>::Cast(CompileRun(
707 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
708 // Create a sliced string that will land in old pointer space.
709 Local<String> slice = Local<String>::Cast(CompileRun(
710 "slice('abcdefghijklmnopqrstuvwxyz');"));
712 // Trigger GCs so that the newly allocated string moves to old gen.
713 SimulateFullSpace(CcTest::heap()->old_pointer_space());
714 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
717 // Turn into external string with unaligned resource data.
718 int dispose_count = 0;
719 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
720 bool success = cons->MakeExternal(
721 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
723 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
724 success = slice->MakeExternal(
725 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
728 // Trigger GCs and force evacuation.
729 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
730 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
734 THREADED_TEST(UsingExternalString) {
735 i::Factory* factory = CcTest::i_isolate()->factory();
737 v8::HandleScope scope(CcTest::isolate());
738 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
739 Local<String> string =
740 String::NewExternal(new TestResource(two_byte_string));
741 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
742 // Trigger GCs so that the newly allocated string moves to old gen.
743 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
744 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
745 i::Handle<i::String> isymbol =
746 factory->InternalizedStringFromString(istring);
747 CHECK(isymbol->IsInternalizedString());
749 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
754 THREADED_TEST(UsingExternalAsciiString) {
755 i::Factory* factory = CcTest::i_isolate()->factory();
757 v8::HandleScope scope(CcTest::isolate());
758 const char* one_byte_string = "test string";
759 Local<String> string = String::NewExternal(
760 new TestAsciiResource(i::StrDup(one_byte_string)));
761 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762 // Trigger GCs so that the newly allocated string moves to old gen.
763 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
764 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
765 i::Handle<i::String> isymbol =
766 factory->InternalizedStringFromString(istring);
767 CHECK(isymbol->IsInternalizedString());
769 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
774 THREADED_TEST(ScavengeExternalString) {
775 i::FLAG_stress_compaction = false;
776 i::FLAG_gc_global = false;
777 int dispose_count = 0;
778 bool in_new_space = false;
780 v8::HandleScope scope(CcTest::isolate());
781 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
782 Local<String> string =
783 String::NewExternal(new TestResource(two_byte_string,
785 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
786 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
787 in_new_space = CcTest::heap()->InNewSpace(*istring);
788 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
789 CHECK_EQ(0, dispose_count);
791 CcTest::heap()->CollectGarbage(
792 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
793 CHECK_EQ(1, dispose_count);
797 THREADED_TEST(ScavengeExternalAsciiString) {
798 i::FLAG_stress_compaction = false;
799 i::FLAG_gc_global = false;
800 int dispose_count = 0;
801 bool in_new_space = false;
803 v8::HandleScope scope(CcTest::isolate());
804 const char* one_byte_string = "test string";
805 Local<String> string = String::NewExternal(
806 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
807 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
808 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
809 in_new_space = CcTest::heap()->InNewSpace(*istring);
810 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
811 CHECK_EQ(0, dispose_count);
813 CcTest::heap()->CollectGarbage(
814 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
815 CHECK_EQ(1, dispose_count);
819 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
821 // Only used by non-threaded tests, so it can use static fields.
822 static int dispose_calls;
823 static int dispose_count;
825 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
826 : TestAsciiResource(data, &dispose_count),
827 dispose_(dispose) { }
831 if (dispose_) delete this;
838 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
839 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
842 TEST(ExternalStringWithDisposeHandling) {
843 const char* c_source = "1 + 2 * 3";
845 // Use a stack allocated external string resource allocated object.
846 TestAsciiResourceWithDisposeControl::dispose_count = 0;
847 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
848 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
851 v8::HandleScope scope(env->GetIsolate());
852 Local<String> source = String::NewExternal(&res_stack);
853 Local<Script> script = Script::Compile(source);
854 Local<Value> value = script->Run();
855 CHECK(value->IsNumber());
856 CHECK_EQ(7, value->Int32Value());
857 CcTest::heap()->CollectAllAvailableGarbage();
858 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
860 CcTest::i_isolate()->compilation_cache()->Clear();
861 CcTest::heap()->CollectAllAvailableGarbage();
862 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
863 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
865 // Use a heap allocated external string resource allocated object.
866 TestAsciiResourceWithDisposeControl::dispose_count = 0;
867 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868 TestAsciiResource* res_heap =
869 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
872 v8::HandleScope scope(env->GetIsolate());
873 Local<String> source = String::NewExternal(res_heap);
874 Local<Script> script = Script::Compile(source);
875 Local<Value> value = script->Run();
876 CHECK(value->IsNumber());
877 CHECK_EQ(7, value->Int32Value());
878 CcTest::heap()->CollectAllAvailableGarbage();
879 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
881 CcTest::i_isolate()->compilation_cache()->Clear();
882 CcTest::heap()->CollectAllAvailableGarbage();
883 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
884 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
888 THREADED_TEST(StringConcat) {
891 v8::HandleScope scope(env->GetIsolate());
892 const char* one_byte_string_1 = "function a_times_t";
893 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
894 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
895 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
896 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
897 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
898 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
899 Local<String> left = v8_str(one_byte_string_1);
901 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
902 Local<String> right = String::New(two_byte_source);
903 i::DeleteArray(two_byte_source);
905 Local<String> source = String::Concat(left, right);
906 right = String::NewExternal(
907 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
908 source = String::Concat(source, right);
909 right = String::NewExternal(
910 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
911 source = String::Concat(source, right);
912 right = v8_str(one_byte_string_2);
913 source = String::Concat(source, right);
915 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
916 right = String::New(two_byte_source);
917 i::DeleteArray(two_byte_source);
919 source = String::Concat(source, right);
920 right = String::NewExternal(
921 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
922 source = String::Concat(source, right);
923 Local<Script> script = Script::Compile(source);
924 Local<Value> value = script->Run();
925 CHECK(value->IsNumber());
926 CHECK_EQ(68, value->Int32Value());
928 CcTest::i_isolate()->compilation_cache()->Clear();
929 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
930 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
934 THREADED_TEST(GlobalProperties) {
936 v8::HandleScope scope(env->GetIsolate());
937 v8::Handle<v8::Object> global = env->Global();
938 global->Set(v8_str("pi"), v8_num(3.1415926));
939 Local<Value> pi = global->Get(v8_str("pi"));
940 CHECK_EQ(3.1415926, pi->NumberValue());
945 static void CheckReturnValue(const T& t, i::Address callback) {
946 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
947 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
948 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
949 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
950 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
952 bool is_runtime = (*o)->IsTheHole();
954 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
955 rv.Set(v8::Handle<v8::Object>());
956 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
957 CHECK_EQ(is_runtime, (*o)->IsTheHole());
959 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
960 // If CPU profiler is active check that when API callback is invoked
961 // VMState is set to EXTERNAL.
962 if (isolate->cpu_profiler()->is_profiling()) {
963 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
964 CHECK(isolate->external_callback_scope());
965 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
970 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
971 i::Address callback) {
972 ApiTestFuzzer::Fuzz();
973 CheckReturnValue(info, callback);
974 info.GetReturnValue().Set(v8_str("bad value"));
975 info.GetReturnValue().Set(v8_num(102));
979 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
980 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
984 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
985 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
988 static void construct_callback(
989 const v8::FunctionCallbackInfo<Value>& info) {
990 ApiTestFuzzer::Fuzz();
991 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
992 info.This()->Set(v8_str("x"), v8_num(1));
993 info.This()->Set(v8_str("y"), v8_num(2));
994 info.GetReturnValue().Set(v8_str("bad value"));
995 info.GetReturnValue().Set(info.This());
999 static void Return239Callback(
1000 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1001 ApiTestFuzzer::Fuzz();
1002 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1003 info.GetReturnValue().Set(v8_str("bad value"));
1004 info.GetReturnValue().Set(v8_num(239));
1008 template<typename Handler>
1009 static void TestFunctionTemplateInitializer(Handler handler,
1010 Handler handler_2) {
1011 // Test constructor calls.
1014 v8::HandleScope scope(env->GetIsolate());
1016 Local<v8::FunctionTemplate> fun_templ =
1017 v8::FunctionTemplate::New(handler);
1018 Local<Function> fun = fun_templ->GetFunction();
1019 env->Global()->Set(v8_str("obj"), fun);
1020 Local<Script> script = v8_compile("obj()");
1021 for (int i = 0; i < 30; i++) {
1022 CHECK_EQ(102, script->Run()->Int32Value());
1025 // Use SetCallHandler to initialize a function template, should work like
1026 // the previous one.
1029 v8::HandleScope scope(env->GetIsolate());
1031 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1032 fun_templ->SetCallHandler(handler_2);
1033 Local<Function> fun = fun_templ->GetFunction();
1034 env->Global()->Set(v8_str("obj"), fun);
1035 Local<Script> script = v8_compile("obj()");
1036 for (int i = 0; i < 30; i++) {
1037 CHECK_EQ(102, script->Run()->Int32Value());
1043 template<typename Constructor, typename Accessor>
1044 static void TestFunctionTemplateAccessor(Constructor constructor,
1045 Accessor accessor) {
1047 v8::HandleScope scope(env->GetIsolate());
1049 Local<v8::FunctionTemplate> fun_templ =
1050 v8::FunctionTemplate::New(constructor);
1051 fun_templ->SetClassName(v8_str("funky"));
1052 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1053 Local<Function> fun = fun_templ->GetFunction();
1054 env->Global()->Set(v8_str("obj"), fun);
1055 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1056 CHECK_EQ(v8_str("[object funky]"), result);
1057 CompileRun("var obj_instance = new obj();");
1058 Local<Script> script;
1059 script = v8_compile("obj_instance.x");
1060 for (int i = 0; i < 30; i++) {
1061 CHECK_EQ(1, script->Run()->Int32Value());
1063 script = v8_compile("obj_instance.m");
1064 for (int i = 0; i < 30; i++) {
1065 CHECK_EQ(239, script->Run()->Int32Value());
1070 THREADED_PROFILED_TEST(FunctionTemplate) {
1071 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1072 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1076 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1077 ApiTestFuzzer::Fuzz();
1078 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1079 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1083 template<typename Callback>
1084 static void TestSimpleCallback(Callback callback) {
1086 v8::HandleScope scope(env->GetIsolate());
1088 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1089 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1090 v8::Local<v8::Object> object = object_template->NewInstance();
1091 (*env)->Global()->Set(v8_str("callback_object"), object);
1092 v8::Handle<v8::Script> script;
1093 script = v8_compile("callback_object.callback(17)");
1094 for (int i = 0; i < 30; i++) {
1095 CHECK_EQ(51424, script->Run()->Int32Value());
1097 script = v8_compile("callback_object.callback(17, 24)");
1098 for (int i = 0; i < 30; i++) {
1099 CHECK_EQ(51425, script->Run()->Int32Value());
1104 THREADED_PROFILED_TEST(SimpleCallback) {
1105 TestSimpleCallback(SimpleCallback);
1109 template<typename T>
1110 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1112 // constant return values
1113 static int32_t fast_return_value_int32 = 471;
1114 static uint32_t fast_return_value_uint32 = 571;
1115 static const double kFastReturnValueDouble = 2.7;
1116 // variable return values
1117 static bool fast_return_value_bool = false;
1118 enum ReturnValueOddball {
1120 kUndefinedReturnValue,
1121 kEmptyStringReturnValue
1123 static ReturnValueOddball fast_return_value_void;
1124 static bool fast_return_value_object_is_empty = false;
1126 // Helper function to avoid compiler error: insufficient contextual information
1127 // to determine type when applying FUNCTION_ADDR to a template function.
1128 static i::Address address_of(v8::FunctionCallback callback) {
1129 return FUNCTION_ADDR(callback);
1133 void FastReturnValueCallback<int32_t>(
1134 const v8::FunctionCallbackInfo<v8::Value>& info) {
1135 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1136 info.GetReturnValue().Set(fast_return_value_int32);
1140 void FastReturnValueCallback<uint32_t>(
1141 const v8::FunctionCallbackInfo<v8::Value>& info) {
1142 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1143 info.GetReturnValue().Set(fast_return_value_uint32);
1147 void FastReturnValueCallback<double>(
1148 const v8::FunctionCallbackInfo<v8::Value>& info) {
1149 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1150 info.GetReturnValue().Set(kFastReturnValueDouble);
1154 void FastReturnValueCallback<bool>(
1155 const v8::FunctionCallbackInfo<v8::Value>& info) {
1156 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1157 info.GetReturnValue().Set(fast_return_value_bool);
1161 void FastReturnValueCallback<void>(
1162 const v8::FunctionCallbackInfo<v8::Value>& info) {
1163 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1164 switch (fast_return_value_void) {
1165 case kNullReturnValue:
1166 info.GetReturnValue().SetNull();
1168 case kUndefinedReturnValue:
1169 info.GetReturnValue().SetUndefined();
1171 case kEmptyStringReturnValue:
1172 info.GetReturnValue().SetEmptyString();
1178 void FastReturnValueCallback<Object>(
1179 const v8::FunctionCallbackInfo<v8::Value>& info) {
1180 v8::Handle<v8::Object> object;
1181 if (!fast_return_value_object_is_empty) object = Object::New();
1182 info.GetReturnValue().Set(object);
1185 template<typename T>
1186 Handle<Value> TestFastReturnValues() {
1188 v8::HandleScope scope(env->GetIsolate());
1189 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1190 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1191 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1192 v8::Local<v8::Object> object = object_template->NewInstance();
1193 (*env)->Global()->Set(v8_str("callback_object"), object);
1194 return scope.Close(CompileRun("callback_object.callback()"));
1198 THREADED_PROFILED_TEST(FastReturnValues) {
1200 v8::HandleScope scope(CcTest::isolate());
1201 v8::Handle<v8::Value> value;
1202 // check int32_t and uint32_t
1203 int32_t int_values[] = {
1205 i::Smi::kMinValue, i::Smi::kMaxValue
1207 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1208 for (int modifier = -1; modifier <= 1; modifier++) {
1209 int int_value = int_values[i] + modifier;
1211 fast_return_value_int32 = int_value;
1212 value = TestFastReturnValues<int32_t>();
1213 CHECK(value->IsInt32());
1214 CHECK(fast_return_value_int32 == value->Int32Value());
1216 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1217 value = TestFastReturnValues<uint32_t>();
1218 CHECK(value->IsUint32());
1219 CHECK(fast_return_value_uint32 == value->Uint32Value());
1223 value = TestFastReturnValues<double>();
1224 CHECK(value->IsNumber());
1225 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1226 // check bool values
1227 for (int i = 0; i < 2; i++) {
1228 fast_return_value_bool = i == 0;
1229 value = TestFastReturnValues<bool>();
1230 CHECK(value->IsBoolean());
1231 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1234 ReturnValueOddball oddballs[] = {
1236 kUndefinedReturnValue,
1237 kEmptyStringReturnValue
1239 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1240 fast_return_value_void = oddballs[i];
1241 value = TestFastReturnValues<void>();
1242 switch (fast_return_value_void) {
1243 case kNullReturnValue:
1244 CHECK(value->IsNull());
1246 case kUndefinedReturnValue:
1247 CHECK(value->IsUndefined());
1249 case kEmptyStringReturnValue:
1250 CHECK(value->IsString());
1251 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1256 fast_return_value_object_is_empty = false;
1257 value = TestFastReturnValues<Object>();
1258 CHECK(value->IsObject());
1259 fast_return_value_object_is_empty = true;
1260 value = TestFastReturnValues<Object>();
1261 CHECK(value->IsUndefined());
1265 THREADED_TEST(FunctionTemplateSetLength) {
1267 v8::HandleScope scope(env->GetIsolate());
1269 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
1270 handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
1271 Local<Function> fun = fun_templ->GetFunction();
1272 env->Global()->Set(v8_str("obj"), fun);
1273 Local<Script> script = v8_compile("obj.length");
1274 CHECK_EQ(23, script->Run()->Int32Value());
1277 Local<v8::FunctionTemplate> fun_templ =
1278 v8::FunctionTemplate::New(handle_callback);
1279 fun_templ->SetLength(22);
1280 Local<Function> fun = fun_templ->GetFunction();
1281 env->Global()->Set(v8_str("obj"), fun);
1282 Local<Script> script = v8_compile("obj.length");
1283 CHECK_EQ(22, script->Run()->Int32Value());
1286 // Without setting length it defaults to 0.
1287 Local<v8::FunctionTemplate> fun_templ =
1288 v8::FunctionTemplate::New(handle_callback);
1289 Local<Function> fun = fun_templ->GetFunction();
1290 env->Global()->Set(v8_str("obj"), fun);
1291 Local<Script> script = v8_compile("obj.length");
1292 CHECK_EQ(0, script->Run()->Int32Value());
1297 static void* expected_ptr;
1298 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1299 void* ptr = v8::External::Cast(*args.Data())->Value();
1300 CHECK_EQ(expected_ptr, ptr);
1301 args.GetReturnValue().Set(true);
1305 static void TestExternalPointerWrapping() {
1307 v8::HandleScope scope(env->GetIsolate());
1309 v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
1311 v8::Handle<v8::Object> obj = v8::Object::New();
1312 obj->Set(v8_str("func"),
1313 v8::FunctionTemplate::New(callback, data)->GetFunction());
1314 env->Global()->Set(v8_str("obj"), obj);
1317 "function foo() {\n"
1318 " for (var i = 0; i < 13; i++) obj.func();\n"
1320 "foo(), true")->BooleanValue());
1324 THREADED_TEST(ExternalWrap) {
1325 // Check heap allocated object.
1328 TestExternalPointerWrapping();
1331 // Check stack allocated object.
1333 expected_ptr = &foo;
1334 TestExternalPointerWrapping();
1336 // Check not aligned addresses.
1338 char* s = new char[n];
1339 for (int i = 0; i < n; i++) {
1340 expected_ptr = s + i;
1341 TestExternalPointerWrapping();
1346 // Check several invalid addresses.
1347 expected_ptr = reinterpret_cast<void*>(1);
1348 TestExternalPointerWrapping();
1350 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1351 TestExternalPointerWrapping();
1353 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1354 TestExternalPointerWrapping();
1356 #if defined(V8_HOST_ARCH_X64)
1357 // Check a value with a leading 1 bit in x64 Smi encoding.
1358 expected_ptr = reinterpret_cast<void*>(0x400000000);
1359 TestExternalPointerWrapping();
1361 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1362 TestExternalPointerWrapping();
1364 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1365 TestExternalPointerWrapping();
1370 THREADED_TEST(FindInstanceInPrototypeChain) {
1372 v8::HandleScope scope(env->GetIsolate());
1374 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
1375 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
1376 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
1377 derived->Inherit(base);
1379 Local<v8::Function> base_function = base->GetFunction();
1380 Local<v8::Function> derived_function = derived->GetFunction();
1381 Local<v8::Function> other_function = other->GetFunction();
1383 Local<v8::Object> base_instance = base_function->NewInstance();
1384 Local<v8::Object> derived_instance = derived_function->NewInstance();
1385 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1386 Local<v8::Object> other_instance = other_function->NewInstance();
1387 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1388 other_instance->Set(v8_str("__proto__"), derived_instance2);
1390 // base_instance is only an instance of base.
1391 CHECK_EQ(base_instance,
1392 base_instance->FindInstanceInPrototypeChain(base));
1393 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1394 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1396 // derived_instance is an instance of base and derived.
1397 CHECK_EQ(derived_instance,
1398 derived_instance->FindInstanceInPrototypeChain(base));
1399 CHECK_EQ(derived_instance,
1400 derived_instance->FindInstanceInPrototypeChain(derived));
1401 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1403 // other_instance is an instance of other and its immediate
1404 // prototype derived_instance2 is an instance of base and derived.
1405 // Note, derived_instance is an instance of base and derived too,
1406 // but it comes after derived_instance2 in the prototype chain of
1408 CHECK_EQ(derived_instance2,
1409 other_instance->FindInstanceInPrototypeChain(base));
1410 CHECK_EQ(derived_instance2,
1411 other_instance->FindInstanceInPrototypeChain(derived));
1412 CHECK_EQ(other_instance,
1413 other_instance->FindInstanceInPrototypeChain(other));
1417 THREADED_TEST(TinyInteger) {
1419 v8::HandleScope scope(env->GetIsolate());
1420 v8::Isolate* isolate = CcTest::isolate();
1422 int32_t value = 239;
1423 Local<v8::Integer> value_obj = v8::Integer::New(value);
1424 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1426 value_obj = v8::Integer::New(value, isolate);
1427 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1431 THREADED_TEST(BigSmiInteger) {
1433 v8::HandleScope scope(env->GetIsolate());
1434 v8::Isolate* isolate = CcTest::isolate();
1436 int32_t value = i::Smi::kMaxValue;
1437 // We cannot add one to a Smi::kMaxValue without wrapping.
1438 if (i::SmiValuesAre31Bits()) {
1439 CHECK(i::Smi::IsValid(value));
1440 CHECK(!i::Smi::IsValid(value + 1));
1442 Local<v8::Integer> value_obj = v8::Integer::New(value);
1443 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1445 value_obj = v8::Integer::New(value, isolate);
1446 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1451 THREADED_TEST(BigInteger) {
1453 v8::HandleScope scope(env->GetIsolate());
1454 v8::Isolate* isolate = CcTest::isolate();
1456 // We cannot add one to a Smi::kMaxValue without wrapping.
1457 if (i::SmiValuesAre31Bits()) {
1458 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1459 // The code will not be run in that case, due to the "if" guard.
1461 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1462 CHECK(value > i::Smi::kMaxValue);
1463 CHECK(!i::Smi::IsValid(value));
1465 Local<v8::Integer> value_obj = v8::Integer::New(value);
1466 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1468 value_obj = v8::Integer::New(value, isolate);
1469 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1474 THREADED_TEST(TinyUnsignedInteger) {
1476 v8::HandleScope scope(env->GetIsolate());
1477 v8::Isolate* isolate = CcTest::isolate();
1479 uint32_t value = 239;
1481 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1482 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1484 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1485 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1489 THREADED_TEST(BigUnsignedSmiInteger) {
1491 v8::HandleScope scope(env->GetIsolate());
1492 v8::Isolate* isolate = CcTest::isolate();
1494 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1495 CHECK(i::Smi::IsValid(value));
1496 CHECK(!i::Smi::IsValid(value + 1));
1498 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1499 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1501 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1502 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1506 THREADED_TEST(BigUnsignedInteger) {
1508 v8::HandleScope scope(env->GetIsolate());
1509 v8::Isolate* isolate = CcTest::isolate();
1511 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1512 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1513 CHECK(!i::Smi::IsValid(value));
1515 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1516 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1518 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1519 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1523 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1525 v8::HandleScope scope(env->GetIsolate());
1526 v8::Isolate* isolate = CcTest::isolate();
1528 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1529 uint32_t value = INT32_MAX_AS_UINT + 1;
1530 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1532 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1533 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1535 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1536 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1540 THREADED_TEST(IsNativeError) {
1542 v8::HandleScope scope(env->GetIsolate());
1543 v8::Handle<Value> syntax_error = CompileRun(
1544 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1545 CHECK(syntax_error->IsNativeError());
1546 v8::Handle<Value> not_error = CompileRun("{a:42}");
1547 CHECK(!not_error->IsNativeError());
1548 v8::Handle<Value> not_object = CompileRun("42");
1549 CHECK(!not_object->IsNativeError());
1553 THREADED_TEST(StringObject) {
1555 v8::HandleScope scope(env->GetIsolate());
1556 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1557 CHECK(boxed_string->IsStringObject());
1558 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1559 CHECK(!unboxed_string->IsStringObject());
1560 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1561 CHECK(!boxed_not_string->IsStringObject());
1562 v8::Handle<Value> not_object = CompileRun("0");
1563 CHECK(!not_object->IsStringObject());
1564 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1565 CHECK(!as_boxed.IsEmpty());
1566 Local<v8::String> the_string = as_boxed->ValueOf();
1567 CHECK(!the_string.IsEmpty());
1568 ExpectObject("\"test\"", the_string);
1569 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1570 CHECK(new_boxed_string->IsStringObject());
1571 as_boxed = new_boxed_string.As<v8::StringObject>();
1572 the_string = as_boxed->ValueOf();
1573 CHECK(!the_string.IsEmpty());
1574 ExpectObject("\"test\"", the_string);
1578 THREADED_TEST(NumberObject) {
1580 v8::HandleScope scope(env->GetIsolate());
1581 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1582 CHECK(boxed_number->IsNumberObject());
1583 v8::Handle<Value> unboxed_number = CompileRun("42");
1584 CHECK(!unboxed_number->IsNumberObject());
1585 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1586 CHECK(!boxed_not_number->IsNumberObject());
1587 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1588 CHECK(!as_boxed.IsEmpty());
1589 double the_number = as_boxed->ValueOf();
1590 CHECK_EQ(42.0, the_number);
1591 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1592 CHECK(new_boxed_number->IsNumberObject());
1593 as_boxed = new_boxed_number.As<v8::NumberObject>();
1594 the_number = as_boxed->ValueOf();
1595 CHECK_EQ(43.0, the_number);
1599 THREADED_TEST(BooleanObject) {
1601 v8::HandleScope scope(env->GetIsolate());
1602 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1603 CHECK(boxed_boolean->IsBooleanObject());
1604 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1605 CHECK(!unboxed_boolean->IsBooleanObject());
1606 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1607 CHECK(!boxed_not_boolean->IsBooleanObject());
1608 v8::Handle<v8::BooleanObject> as_boxed =
1609 boxed_boolean.As<v8::BooleanObject>();
1610 CHECK(!as_boxed.IsEmpty());
1611 bool the_boolean = as_boxed->ValueOf();
1612 CHECK_EQ(true, the_boolean);
1613 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1614 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1615 CHECK(boxed_true->IsBooleanObject());
1616 CHECK(boxed_false->IsBooleanObject());
1617 as_boxed = boxed_true.As<v8::BooleanObject>();
1618 CHECK_EQ(true, as_boxed->ValueOf());
1619 as_boxed = boxed_false.As<v8::BooleanObject>();
1620 CHECK_EQ(false, as_boxed->ValueOf());
1624 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1626 v8::HandleScope scope(env->GetIsolate());
1628 Local<Value> primitive_false = Boolean::New(false);
1629 CHECK(primitive_false->IsBoolean());
1630 CHECK(!primitive_false->IsBooleanObject());
1631 CHECK(!primitive_false->BooleanValue());
1632 CHECK(!primitive_false->IsTrue());
1633 CHECK(primitive_false->IsFalse());
1635 Local<Value> false_value = BooleanObject::New(false);
1636 CHECK(!false_value->IsBoolean());
1637 CHECK(false_value->IsBooleanObject());
1638 CHECK(false_value->BooleanValue());
1639 CHECK(!false_value->IsTrue());
1640 CHECK(!false_value->IsFalse());
1642 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1643 CHECK(!false_boolean_object->IsBoolean());
1644 CHECK(false_boolean_object->IsBooleanObject());
1645 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1646 // CHECK(false_boolean_object->BooleanValue());
1647 CHECK(!false_boolean_object->ValueOf());
1648 CHECK(!false_boolean_object->IsTrue());
1649 CHECK(!false_boolean_object->IsFalse());
1651 Local<Value> primitive_true = Boolean::New(true);
1652 CHECK(primitive_true->IsBoolean());
1653 CHECK(!primitive_true->IsBooleanObject());
1654 CHECK(primitive_true->BooleanValue());
1655 CHECK(primitive_true->IsTrue());
1656 CHECK(!primitive_true->IsFalse());
1658 Local<Value> true_value = BooleanObject::New(true);
1659 CHECK(!true_value->IsBoolean());
1660 CHECK(true_value->IsBooleanObject());
1661 CHECK(true_value->BooleanValue());
1662 CHECK(!true_value->IsTrue());
1663 CHECK(!true_value->IsFalse());
1665 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1666 CHECK(!true_boolean_object->IsBoolean());
1667 CHECK(true_boolean_object->IsBooleanObject());
1668 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1669 // CHECK(true_boolean_object->BooleanValue());
1670 CHECK(true_boolean_object->ValueOf());
1671 CHECK(!true_boolean_object->IsTrue());
1672 CHECK(!true_boolean_object->IsFalse());
1676 THREADED_TEST(Number) {
1678 v8::HandleScope scope(env->GetIsolate());
1679 double PI = 3.1415926;
1680 Local<v8::Number> pi_obj = v8::Number::New(PI);
1681 CHECK_EQ(PI, pi_obj->NumberValue());
1685 THREADED_TEST(ToNumber) {
1687 v8::Isolate* isolate = CcTest::isolate();
1688 v8::HandleScope scope(isolate);
1689 Local<String> str = v8_str("3.1415926");
1690 CHECK_EQ(3.1415926, str->NumberValue());
1691 v8::Handle<v8::Boolean> t = v8::True(isolate);
1692 CHECK_EQ(1.0, t->NumberValue());
1693 v8::Handle<v8::Boolean> f = v8::False(isolate);
1694 CHECK_EQ(0.0, f->NumberValue());
1698 THREADED_TEST(Date) {
1700 v8::HandleScope scope(env->GetIsolate());
1701 double PI = 3.1415926;
1702 Local<Value> date = v8::Date::New(PI);
1703 CHECK_EQ(3.0, date->NumberValue());
1704 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1705 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1709 THREADED_TEST(Boolean) {
1711 v8::HandleScope scope(env->GetIsolate());
1712 v8::Handle<v8::Boolean> t = v8::True(CcTest::isolate());
1714 v8::Handle<v8::Boolean> f = v8::False(CcTest::isolate());
1716 v8::Handle<v8::Primitive> u = v8::Undefined(CcTest::isolate());
1717 CHECK(!u->BooleanValue());
1718 v8::Handle<v8::Primitive> n = v8::Null(CcTest::isolate());
1719 CHECK(!n->BooleanValue());
1720 v8::Handle<String> str1 = v8_str("");
1721 CHECK(!str1->BooleanValue());
1722 v8::Handle<String> str2 = v8_str("x");
1723 CHECK(str2->BooleanValue());
1724 CHECK(!v8::Number::New(0)->BooleanValue());
1725 CHECK(v8::Number::New(-1)->BooleanValue());
1726 CHECK(v8::Number::New(1)->BooleanValue());
1727 CHECK(v8::Number::New(42)->BooleanValue());
1728 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1732 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1733 ApiTestFuzzer::Fuzz();
1734 args.GetReturnValue().Set(v8_num(13.4));
1738 static void GetM(Local<String> name,
1739 const v8::PropertyCallbackInfo<v8::Value>& info) {
1740 ApiTestFuzzer::Fuzz();
1741 info.GetReturnValue().Set(v8_num(876));
1745 THREADED_TEST(GlobalPrototype) {
1746 v8::HandleScope scope(CcTest::isolate());
1747 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1748 func_templ->PrototypeTemplate()->Set(
1750 v8::FunctionTemplate::New(DummyCallHandler));
1751 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1752 templ->Set("x", v8_num(200));
1753 templ->SetAccessor(v8_str("m"), GetM);
1754 LocalContext env(0, templ);
1755 v8::Handle<Script> script(v8_compile("dummy()"));
1756 v8::Handle<Value> result(script->Run());
1757 CHECK_EQ(13.4, result->NumberValue());
1758 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1759 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1763 THREADED_TEST(ObjectTemplate) {
1764 v8::HandleScope scope(CcTest::isolate());
1765 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1766 templ1->Set("x", v8_num(10));
1767 templ1->Set("y", v8_num(13));
1769 Local<v8::Object> instance1 = templ1->NewInstance();
1770 env->Global()->Set(v8_str("p"), instance1);
1771 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1772 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1773 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1774 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1775 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1776 templ2->Set("a", v8_num(12));
1777 templ2->Set("b", templ1);
1778 Local<v8::Object> instance2 = templ2->NewInstance();
1779 env->Global()->Set(v8_str("q"), instance2);
1780 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1781 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1782 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1783 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1787 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1788 ApiTestFuzzer::Fuzz();
1789 args.GetReturnValue().Set(v8_num(17.2));
1793 static void GetKnurd(Local<String> property,
1794 const v8::PropertyCallbackInfo<v8::Value>& info) {
1795 ApiTestFuzzer::Fuzz();
1796 info.GetReturnValue().Set(v8_num(15.2));
1800 THREADED_TEST(DescriptorInheritance) {
1801 v8::HandleScope scope(CcTest::isolate());
1802 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1803 super->PrototypeTemplate()->Set("flabby",
1804 v8::FunctionTemplate::New(GetFlabby));
1805 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1807 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1809 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1810 base1->Inherit(super);
1811 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1813 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1814 base2->Inherit(super);
1815 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1819 env->Global()->Set(v8_str("s"), super->GetFunction());
1820 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1821 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1823 // Checks right __proto__ chain.
1824 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1825 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1827 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1829 // Instance accessor should not be visible on function object or its prototype
1830 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1831 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1832 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1834 env->Global()->Set(v8_str("obj"),
1835 base1->GetFunction()->NewInstance());
1836 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1837 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1838 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1839 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1840 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1842 env->Global()->Set(v8_str("obj2"),
1843 base2->GetFunction()->NewInstance());
1844 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1845 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1846 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1847 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1848 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1850 // base1 and base2 cannot cross reference to each's prototype
1851 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1852 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1856 int echo_named_call_count;
1859 static void EchoNamedProperty(Local<String> name,
1860 const v8::PropertyCallbackInfo<v8::Value>& info) {
1861 ApiTestFuzzer::Fuzz();
1862 CHECK_EQ(v8_str("data"), info.Data());
1863 echo_named_call_count++;
1864 info.GetReturnValue().Set(name);
1868 // Helper functions for Interceptor/Accessor interaction tests
1870 void SimpleAccessorGetter(Local<String> name,
1871 const v8::PropertyCallbackInfo<v8::Value>& info) {
1872 Handle<Object> self = info.This();
1873 info.GetReturnValue().Set(
1874 self->Get(String::Concat(v8_str("accessor_"), name)));
1877 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1878 const v8::PropertyCallbackInfo<void>& info) {
1879 Handle<Object> self = info.This();
1880 self->Set(String::Concat(v8_str("accessor_"), name), value);
1883 void EmptyInterceptorGetter(Local<String> name,
1884 const v8::PropertyCallbackInfo<v8::Value>& info) {
1887 void EmptyInterceptorSetter(Local<String> name,
1889 const v8::PropertyCallbackInfo<v8::Value>& info) {
1892 void InterceptorGetter(Local<String> name,
1893 const v8::PropertyCallbackInfo<v8::Value>& info) {
1894 // Intercept names that start with 'interceptor_'.
1895 String::Utf8Value utf8(name);
1896 char* name_str = *utf8;
1897 char prefix[] = "interceptor_";
1899 for (i = 0; name_str[i] && prefix[i]; ++i) {
1900 if (name_str[i] != prefix[i]) return;
1902 Handle<Object> self = info.This();
1903 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1906 void InterceptorSetter(Local<String> name,
1908 const v8::PropertyCallbackInfo<v8::Value>& info) {
1909 // Intercept accesses that set certain integer values, for which the name does
1910 // not start with 'accessor_'.
1911 String::Utf8Value utf8(name);
1912 char* name_str = *utf8;
1913 char prefix[] = "accessor_";
1915 for (i = 0; name_str[i] && prefix[i]; ++i) {
1916 if (name_str[i] != prefix[i]) break;
1918 if (!prefix[i]) return;
1920 if (value->IsInt32() && value->Int32Value() < 10000) {
1921 Handle<Object> self = info.This();
1922 self->SetHiddenValue(name, value);
1923 info.GetReturnValue().Set(value);
1927 void AddAccessor(Handle<FunctionTemplate> templ,
1928 Handle<String> name,
1929 v8::AccessorGetterCallback getter,
1930 v8::AccessorSetterCallback setter) {
1931 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1934 void AddInterceptor(Handle<FunctionTemplate> templ,
1935 v8::NamedPropertyGetterCallback getter,
1936 v8::NamedPropertySetterCallback setter) {
1937 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1941 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1942 v8::HandleScope scope(CcTest::isolate());
1943 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1944 Handle<FunctionTemplate> child = FunctionTemplate::New();
1945 child->Inherit(parent);
1946 AddAccessor(parent, v8_str("age"),
1947 SimpleAccessorGetter, SimpleAccessorSetter);
1948 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1950 env->Global()->Set(v8_str("Child"), child->GetFunction());
1951 CompileRun("var child = new Child;"
1953 ExpectBoolean("child.hasOwnProperty('age')", false);
1954 ExpectInt32("child.age", 10);
1955 ExpectInt32("child.accessor_age", 10);
1959 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1960 v8::HandleScope scope(CcTest::isolate());
1961 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1962 Handle<FunctionTemplate> child = FunctionTemplate::New();
1963 child->Inherit(parent);
1964 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1966 env->Global()->Set(v8_str("Child"), child->GetFunction());
1967 CompileRun("var child = new Child;"
1968 "var parent = child.__proto__;"
1969 "Object.defineProperty(parent, 'age', "
1970 " {get: function(){ return this.accessor_age; }, "
1971 " set: function(v){ this.accessor_age = v; }, "
1972 " enumerable: true, configurable: true});"
1974 ExpectBoolean("child.hasOwnProperty('age')", false);
1975 ExpectInt32("child.age", 10);
1976 ExpectInt32("child.accessor_age", 10);
1980 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1981 v8::HandleScope scope(CcTest::isolate());
1982 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1983 Handle<FunctionTemplate> child = FunctionTemplate::New();
1984 child->Inherit(parent);
1985 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1987 env->Global()->Set(v8_str("Child"), child->GetFunction());
1988 CompileRun("var child = new Child;"
1989 "var parent = child.__proto__;"
1990 "parent.name = 'Alice';");
1991 ExpectBoolean("child.hasOwnProperty('name')", false);
1992 ExpectString("child.name", "Alice");
1993 CompileRun("child.name = 'Bob';");
1994 ExpectString("child.name", "Bob");
1995 ExpectBoolean("child.hasOwnProperty('name')", true);
1996 ExpectString("parent.name", "Alice");
2000 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2001 v8::HandleScope scope(CcTest::isolate());
2002 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2003 AddAccessor(templ, v8_str("age"),
2004 SimpleAccessorGetter, SimpleAccessorSetter);
2005 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2007 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2008 CompileRun("var obj = new Obj;"
2009 "function setAge(i){ obj.age = i; };"
2010 "for(var i = 0; i <= 10000; i++) setAge(i);");
2011 // All i < 10000 go to the interceptor.
2012 ExpectInt32("obj.interceptor_age", 9999);
2013 // The last i goes to the accessor.
2014 ExpectInt32("obj.accessor_age", 10000);
2018 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2019 v8::HandleScope scope(CcTest::isolate());
2020 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2021 AddAccessor(templ, v8_str("age"),
2022 SimpleAccessorGetter, SimpleAccessorSetter);
2023 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2025 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2026 CompileRun("var obj = new Obj;"
2027 "function setAge(i){ obj.age = i; };"
2028 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2029 // All i >= 10000 go to the accessor.
2030 ExpectInt32("obj.accessor_age", 10000);
2031 // The last i goes to the interceptor.
2032 ExpectInt32("obj.interceptor_age", 9999);
2036 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2037 v8::HandleScope scope(CcTest::isolate());
2038 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2039 Handle<FunctionTemplate> child = FunctionTemplate::New();
2040 child->Inherit(parent);
2041 AddAccessor(parent, v8_str("age"),
2042 SimpleAccessorGetter, SimpleAccessorSetter);
2043 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2045 env->Global()->Set(v8_str("Child"), child->GetFunction());
2046 CompileRun("var child = new Child;"
2047 "function setAge(i){ child.age = i; };"
2048 "for(var i = 0; i <= 10000; i++) setAge(i);");
2049 // All i < 10000 go to the interceptor.
2050 ExpectInt32("child.interceptor_age", 9999);
2051 // The last i goes to the accessor.
2052 ExpectInt32("child.accessor_age", 10000);
2056 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2057 v8::HandleScope scope(CcTest::isolate());
2058 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2059 Handle<FunctionTemplate> child = FunctionTemplate::New();
2060 child->Inherit(parent);
2061 AddAccessor(parent, v8_str("age"),
2062 SimpleAccessorGetter, SimpleAccessorSetter);
2063 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2065 env->Global()->Set(v8_str("Child"), child->GetFunction());
2066 CompileRun("var child = new Child;"
2067 "function setAge(i){ child.age = i; };"
2068 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2069 // All i >= 10000 go to the accessor.
2070 ExpectInt32("child.accessor_age", 10000);
2071 // The last i goes to the interceptor.
2072 ExpectInt32("child.interceptor_age", 9999);
2076 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2077 v8::HandleScope scope(CcTest::isolate());
2078 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2079 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2081 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2082 CompileRun("var obj = new Obj;"
2083 "function setter(i) { this.accessor_age = i; };"
2084 "function getter() { return this.accessor_age; };"
2085 "function setAge(i) { obj.age = i; };"
2086 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2087 "for(var i = 0; i <= 10000; i++) setAge(i);");
2088 // All i < 10000 go to the interceptor.
2089 ExpectInt32("obj.interceptor_age", 9999);
2090 // The last i goes to the JavaScript accessor.
2091 ExpectInt32("obj.accessor_age", 10000);
2092 // The installed JavaScript getter is still intact.
2093 // This last part is a regression test for issue 1651 and relies on the fact
2094 // that both interceptor and accessor are being installed on the same object.
2095 ExpectInt32("obj.age", 10000);
2096 ExpectBoolean("obj.hasOwnProperty('age')", true);
2097 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2101 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2102 v8::HandleScope scope(CcTest::isolate());
2103 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2104 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2106 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2107 CompileRun("var obj = new Obj;"
2108 "function setter(i) { this.accessor_age = i; };"
2109 "function getter() { return this.accessor_age; };"
2110 "function setAge(i) { obj.age = i; };"
2111 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2112 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2113 // All i >= 10000 go to the accessor.
2114 ExpectInt32("obj.accessor_age", 10000);
2115 // The last i goes to the interceptor.
2116 ExpectInt32("obj.interceptor_age", 9999);
2117 // The installed JavaScript getter is still intact.
2118 // This last part is a regression test for issue 1651 and relies on the fact
2119 // that both interceptor and accessor are being installed on the same object.
2120 ExpectInt32("obj.age", 10000);
2121 ExpectBoolean("obj.hasOwnProperty('age')", true);
2122 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2126 THREADED_TEST(SwitchFromInterceptorToProperty) {
2127 v8::HandleScope scope(CcTest::isolate());
2128 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2129 Handle<FunctionTemplate> child = FunctionTemplate::New();
2130 child->Inherit(parent);
2131 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2133 env->Global()->Set(v8_str("Child"), child->GetFunction());
2134 CompileRun("var child = new Child;"
2135 "function setAge(i){ child.age = i; };"
2136 "for(var i = 0; i <= 10000; i++) setAge(i);");
2137 // All i < 10000 go to the interceptor.
2138 ExpectInt32("child.interceptor_age", 9999);
2139 // The last i goes to child's own property.
2140 ExpectInt32("child.age", 10000);
2144 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2145 v8::HandleScope scope(CcTest::isolate());
2146 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2147 Handle<FunctionTemplate> child = FunctionTemplate::New();
2148 child->Inherit(parent);
2149 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2151 env->Global()->Set(v8_str("Child"), child->GetFunction());
2152 CompileRun("var child = new Child;"
2153 "function setAge(i){ child.age = i; };"
2154 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2155 // All i >= 10000 go to child's own property.
2156 ExpectInt32("child.age", 10000);
2157 // The last i goes to the interceptor.
2158 ExpectInt32("child.interceptor_age", 9999);
2162 THREADED_TEST(NamedPropertyHandlerGetter) {
2163 echo_named_call_count = 0;
2164 v8::HandleScope scope(CcTest::isolate());
2165 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2166 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2170 env->Global()->Set(v8_str("obj"),
2171 templ->GetFunction()->NewInstance());
2172 CHECK_EQ(echo_named_call_count, 0);
2173 v8_compile("obj.x")->Run();
2174 CHECK_EQ(echo_named_call_count, 1);
2175 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2176 v8::Handle<Value> str = CompileRun(code);
2177 String::Utf8Value value(str);
2178 CHECK_EQ(*value, "oddlepoddle");
2179 // Check default behavior
2180 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2181 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2182 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2186 int echo_indexed_call_count = 0;
2189 static void EchoIndexedProperty(
2191 const v8::PropertyCallbackInfo<v8::Value>& info) {
2192 ApiTestFuzzer::Fuzz();
2193 CHECK_EQ(v8_num(637), info.Data());
2194 echo_indexed_call_count++;
2195 info.GetReturnValue().Set(v8_num(index));
2199 THREADED_TEST(IndexedPropertyHandlerGetter) {
2200 v8::HandleScope scope(CcTest::isolate());
2201 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2202 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2206 env->Global()->Set(v8_str("obj"),
2207 templ->GetFunction()->NewInstance());
2208 Local<Script> script = v8_compile("obj[900]");
2209 CHECK_EQ(script->Run()->Int32Value(), 900);
2213 v8::Handle<v8::Object> bottom;
2215 static void CheckThisIndexedPropertyHandler(
2217 const v8::PropertyCallbackInfo<v8::Value>& info) {
2218 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2219 ApiTestFuzzer::Fuzz();
2220 CHECK(info.This()->Equals(bottom));
2223 static void CheckThisNamedPropertyHandler(
2225 const v8::PropertyCallbackInfo<v8::Value>& info) {
2226 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2227 ApiTestFuzzer::Fuzz();
2228 CHECK(info.This()->Equals(bottom));
2231 void CheckThisIndexedPropertySetter(
2234 const v8::PropertyCallbackInfo<v8::Value>& info) {
2235 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2236 ApiTestFuzzer::Fuzz();
2237 CHECK(info.This()->Equals(bottom));
2241 void CheckThisNamedPropertySetter(
2242 Local<String> property,
2244 const v8::PropertyCallbackInfo<v8::Value>& info) {
2245 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2246 ApiTestFuzzer::Fuzz();
2247 CHECK(info.This()->Equals(bottom));
2250 void CheckThisIndexedPropertyQuery(
2252 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2253 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2254 ApiTestFuzzer::Fuzz();
2255 CHECK(info.This()->Equals(bottom));
2259 void CheckThisNamedPropertyQuery(
2260 Local<String> property,
2261 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2262 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2263 ApiTestFuzzer::Fuzz();
2264 CHECK(info.This()->Equals(bottom));
2268 void CheckThisIndexedPropertyDeleter(
2270 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2271 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2272 ApiTestFuzzer::Fuzz();
2273 CHECK(info.This()->Equals(bottom));
2277 void CheckThisNamedPropertyDeleter(
2278 Local<String> property,
2279 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2280 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2281 ApiTestFuzzer::Fuzz();
2282 CHECK(info.This()->Equals(bottom));
2286 void CheckThisIndexedPropertyEnumerator(
2287 const v8::PropertyCallbackInfo<v8::Array>& info) {
2288 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2289 ApiTestFuzzer::Fuzz();
2290 CHECK(info.This()->Equals(bottom));
2294 void CheckThisNamedPropertyEnumerator(
2295 const v8::PropertyCallbackInfo<v8::Array>& info) {
2296 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2297 ApiTestFuzzer::Fuzz();
2298 CHECK(info.This()->Equals(bottom));
2302 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2304 v8::HandleScope scope(env->GetIsolate());
2306 // Set up a prototype chain with three interceptors.
2307 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2308 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2309 CheckThisIndexedPropertyHandler,
2310 CheckThisIndexedPropertySetter,
2311 CheckThisIndexedPropertyQuery,
2312 CheckThisIndexedPropertyDeleter,
2313 CheckThisIndexedPropertyEnumerator);
2315 templ->InstanceTemplate()->SetNamedPropertyHandler(
2316 CheckThisNamedPropertyHandler,
2317 CheckThisNamedPropertySetter,
2318 CheckThisNamedPropertyQuery,
2319 CheckThisNamedPropertyDeleter,
2320 CheckThisNamedPropertyEnumerator);
2322 bottom = templ->GetFunction()->NewInstance();
2323 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2324 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2326 bottom->SetPrototype(middle);
2327 middle->SetPrototype(top);
2328 env->Global()->Set(v8_str("obj"), bottom);
2330 // Indexed and named get.
2331 Script::Compile(v8_str("obj[0]"))->Run();
2332 Script::Compile(v8_str("obj.x"))->Run();
2334 // Indexed and named set.
2335 Script::Compile(v8_str("obj[1] = 42"))->Run();
2336 Script::Compile(v8_str("obj.y = 42"))->Run();
2338 // Indexed and named query.
2339 Script::Compile(v8_str("0 in obj"))->Run();
2340 Script::Compile(v8_str("'x' in obj"))->Run();
2342 // Indexed and named deleter.
2343 Script::Compile(v8_str("delete obj[0]"))->Run();
2344 Script::Compile(v8_str("delete obj.x"))->Run();
2347 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2351 static void PrePropertyHandlerGet(
2353 const v8::PropertyCallbackInfo<v8::Value>& info) {
2354 ApiTestFuzzer::Fuzz();
2355 if (v8_str("pre")->Equals(key)) {
2356 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2361 static void PrePropertyHandlerQuery(
2363 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2364 if (v8_str("pre")->Equals(key)) {
2365 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2370 THREADED_TEST(PrePropertyHandler) {
2371 v8::HandleScope scope(CcTest::isolate());
2372 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
2373 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2375 PrePropertyHandlerQuery);
2376 LocalContext env(NULL, desc->InstanceTemplate());
2377 Script::Compile(v8_str(
2378 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2379 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2380 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2381 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2382 CHECK_EQ(v8_str("Object: on"), result_on);
2383 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2384 CHECK(result_post.IsEmpty());
2388 THREADED_TEST(UndefinedIsNotEnumerable) {
2390 v8::HandleScope scope(env->GetIsolate());
2391 v8::Handle<Value> result = Script::Compile(v8_str(
2392 "this.propertyIsEnumerable(undefined)"))->Run();
2393 CHECK(result->IsFalse());
2397 v8::Handle<Script> call_recursively_script;
2398 static const int kTargetRecursionDepth = 200; // near maximum
2401 static void CallScriptRecursivelyCall(
2402 const v8::FunctionCallbackInfo<v8::Value>& args) {
2403 ApiTestFuzzer::Fuzz();
2404 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2405 if (depth == kTargetRecursionDepth) return;
2406 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2407 args.GetReturnValue().Set(call_recursively_script->Run());
2411 static void CallFunctionRecursivelyCall(
2412 const v8::FunctionCallbackInfo<v8::Value>& args) {
2413 ApiTestFuzzer::Fuzz();
2414 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2415 if (depth == kTargetRecursionDepth) {
2416 printf("[depth = %d]\n", depth);
2419 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2420 v8::Handle<Value> function =
2421 args.This()->Get(v8_str("callFunctionRecursively"));
2422 args.GetReturnValue().Set(
2423 function.As<Function>()->Call(args.This(), 0, NULL));
2427 THREADED_TEST(DeepCrossLanguageRecursion) {
2428 v8::HandleScope scope(CcTest::isolate());
2429 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2430 global->Set(v8_str("callScriptRecursively"),
2431 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
2432 global->Set(v8_str("callFunctionRecursively"),
2433 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
2434 LocalContext env(NULL, global);
2436 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2437 call_recursively_script = v8_compile("callScriptRecursively()");
2438 call_recursively_script->Run();
2439 call_recursively_script = v8::Handle<Script>();
2441 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2442 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2446 static void ThrowingPropertyHandlerGet(
2448 const v8::PropertyCallbackInfo<v8::Value>& info) {
2449 ApiTestFuzzer::Fuzz();
2450 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2454 static void ThrowingPropertyHandlerSet(
2457 const v8::PropertyCallbackInfo<v8::Value>& info) {
2458 info.GetIsolate()->ThrowException(key);
2459 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2463 THREADED_TEST(CallbackExceptionRegression) {
2464 v8::HandleScope scope(CcTest::isolate());
2465 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2466 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2467 ThrowingPropertyHandlerSet);
2469 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2470 v8::Handle<Value> otto = Script::Compile(v8_str(
2471 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2472 CHECK_EQ(v8_str("otto"), otto);
2473 v8::Handle<Value> netto = Script::Compile(v8_str(
2474 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2475 CHECK_EQ(v8_str("netto"), netto);
2479 THREADED_TEST(FunctionPrototype) {
2480 v8::HandleScope scope(CcTest::isolate());
2481 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2482 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2484 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2485 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2486 CHECK_EQ(script->Run()->Int32Value(), 321);
2490 THREADED_TEST(InternalFields) {
2492 v8::HandleScope scope(env->GetIsolate());
2494 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2495 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2496 instance_templ->SetInternalFieldCount(1);
2497 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2498 CHECK_EQ(1, obj->InternalFieldCount());
2499 CHECK(obj->GetInternalField(0)->IsUndefined());
2500 obj->SetInternalField(0, v8_num(17));
2501 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2505 THREADED_TEST(GlobalObjectInternalFields) {
2506 v8::HandleScope scope(CcTest::isolate());
2507 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2508 global_template->SetInternalFieldCount(1);
2509 LocalContext env(NULL, global_template);
2510 v8::Handle<v8::Object> global_proxy = env->Global();
2511 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2512 CHECK_EQ(1, global->InternalFieldCount());
2513 CHECK(global->GetInternalField(0)->IsUndefined());
2514 global->SetInternalField(0, v8_num(17));
2515 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2519 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2521 v8::HandleScope scope(CcTest::isolate());
2523 v8::Local<v8::Object> global = env->Global();
2524 global->Set(0, v8::String::New("value"));
2525 CHECK(global->HasRealIndexedProperty(0));
2529 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2531 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2532 obj->SetAlignedPointerInInternalField(0, value);
2533 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2534 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2538 THREADED_TEST(InternalFieldsAlignedPointers) {
2540 v8::HandleScope scope(env->GetIsolate());
2542 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2543 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2544 instance_templ->SetInternalFieldCount(1);
2545 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2546 CHECK_EQ(1, obj->InternalFieldCount());
2548 CheckAlignedPointerInInternalField(obj, NULL);
2550 int* heap_allocated = new int[100];
2551 CheckAlignedPointerInInternalField(obj, heap_allocated);
2552 delete[] heap_allocated;
2554 int stack_allocated[100];
2555 CheckAlignedPointerInInternalField(obj, stack_allocated);
2557 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2558 CheckAlignedPointerInInternalField(obj, huge);
2562 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2565 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2566 (*env)->SetAlignedPointerInEmbedderData(index, value);
2567 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2568 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2572 static void* AlignedTestPointer(int i) {
2573 return reinterpret_cast<void*>(i * 1234);
2577 THREADED_TEST(EmbedderDataAlignedPointers) {
2579 v8::HandleScope scope(env->GetIsolate());
2581 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2583 int* heap_allocated = new int[100];
2584 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2585 delete[] heap_allocated;
2587 int stack_allocated[100];
2588 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2590 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2591 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2593 // Test growing of the embedder data's backing store.
2594 for (int i = 0; i < 100; i++) {
2595 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2597 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2598 for (int i = 0; i < 100; i++) {
2599 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2604 static void CheckEmbedderData(LocalContext* env,
2606 v8::Handle<Value> data) {
2607 (*env)->SetEmbedderData(index, data);
2608 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2612 THREADED_TEST(EmbedderData) {
2614 v8::HandleScope scope(env->GetIsolate());
2616 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2617 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2618 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2619 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2623 THREADED_TEST(IdentityHash) {
2625 v8::HandleScope scope(env->GetIsolate());
2627 // Ensure that the test starts with an fresh heap to test whether the hash
2628 // code is based on the address.
2629 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2630 Local<v8::Object> obj = v8::Object::New();
2631 int hash = obj->GetIdentityHash();
2632 int hash1 = obj->GetIdentityHash();
2633 CHECK_EQ(hash, hash1);
2634 int hash2 = v8::Object::New()->GetIdentityHash();
2635 // Since the identity hash is essentially a random number two consecutive
2636 // objects should not be assigned the same hash code. If the test below fails
2637 // the random number generator should be evaluated.
2638 CHECK_NE(hash, hash2);
2639 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2640 int hash3 = v8::Object::New()->GetIdentityHash();
2641 // Make sure that the identity hash is not based on the initial address of
2642 // the object alone. If the test below fails the random number generator
2643 // should be evaluated.
2644 CHECK_NE(hash, hash3);
2645 int hash4 = obj->GetIdentityHash();
2646 CHECK_EQ(hash, hash4);
2648 // Check identity hashes behaviour in the presence of JS accessors.
2649 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2651 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2652 Local<v8::Object> o1 = v8::Object::New();
2653 Local<v8::Object> o2 = v8::Object::New();
2654 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2658 "function cnst() { return 42; };\n"
2659 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2660 Local<v8::Object> o1 = v8::Object::New();
2661 Local<v8::Object> o2 = v8::Object::New();
2662 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2667 THREADED_TEST(SymbolProperties) {
2668 i::FLAG_harmony_symbols = true;
2671 v8::Isolate* isolate = env->GetIsolate();
2672 v8::HandleScope scope(isolate);
2674 v8::Local<v8::Object> obj = v8::Object::New();
2675 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2676 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2678 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2680 // Check basic symbol functionality.
2681 CHECK(sym1->IsSymbol());
2682 CHECK(sym2->IsSymbol());
2683 CHECK(!obj->IsSymbol());
2685 CHECK(sym1->Equals(sym1));
2686 CHECK(sym2->Equals(sym2));
2687 CHECK(!sym1->Equals(sym2));
2688 CHECK(!sym2->Equals(sym1));
2689 CHECK(sym1->StrictEquals(sym1));
2690 CHECK(sym2->StrictEquals(sym2));
2691 CHECK(!sym1->StrictEquals(sym2));
2692 CHECK(!sym2->StrictEquals(sym1));
2694 CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
2696 v8::Local<v8::Value> sym_val = sym2;
2697 CHECK(sym_val->IsSymbol());
2698 CHECK(sym_val->Equals(sym2));
2699 CHECK(sym_val->StrictEquals(sym2));
2700 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2702 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2703 CHECK(sym_obj->IsSymbolObject());
2704 CHECK(!sym2->IsSymbolObject());
2705 CHECK(!obj->IsSymbolObject());
2706 CHECK(sym_obj->Equals(sym2));
2707 CHECK(!sym_obj->StrictEquals(sym2));
2708 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2709 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2711 // Make sure delete of a non-existent symbol property works.
2712 CHECK(obj->Delete(sym1));
2713 CHECK(!obj->Has(sym1));
2715 CHECK(obj->Set(sym1, v8::Integer::New(1503)));
2716 CHECK(obj->Has(sym1));
2717 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2718 CHECK(obj->Set(sym1, v8::Integer::New(2002)));
2719 CHECK(obj->Has(sym1));
2720 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2721 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2723 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2724 int num_props = obj->GetPropertyNames()->Length();
2725 CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
2726 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2727 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2729 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2731 // Add another property and delete it afterwards to force the object in
2733 CHECK(obj->Set(sym2, v8::Integer::New(2008)));
2734 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2735 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2736 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2737 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2739 CHECK(obj->Has(sym1));
2740 CHECK(obj->Has(sym2));
2741 CHECK(obj->Delete(sym2));
2742 CHECK(obj->Has(sym1));
2743 CHECK(!obj->Has(sym2));
2744 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2745 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2749 class ScopedArrayBufferContents {
2751 explicit ScopedArrayBufferContents(
2752 const v8::ArrayBuffer::Contents& contents)
2753 : contents_(contents) {}
2754 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2755 void* Data() const { return contents_.Data(); }
2756 size_t ByteLength() const { return contents_.ByteLength(); }
2758 const v8::ArrayBuffer::Contents contents_;
2761 template <typename T>
2762 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2763 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2764 for (int i = 0; i < value->InternalFieldCount(); i++) {
2765 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2770 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2772 v8::Isolate* isolate = env->GetIsolate();
2773 v8::HandleScope handle_scope(isolate);
2775 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
2776 CheckInternalFieldsAreZero(ab);
2777 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2778 CHECK(!ab->IsExternal());
2779 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2781 ScopedArrayBufferContents ab_contents(ab->Externalize());
2782 CHECK(ab->IsExternal());
2784 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2785 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2786 ASSERT(data != NULL);
2787 env->Global()->Set(v8_str("ab"), ab);
2789 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2790 CHECK_EQ(1024, result->Int32Value());
2792 result = CompileRun("var u8 = new Uint8Array(ab);"
2796 CHECK_EQ(1024, result->Int32Value());
2797 CHECK_EQ(0xFF, data[0]);
2798 CHECK_EQ(0xAA, data[1]);
2801 result = CompileRun("u8[0] + u8[1]");
2802 CHECK_EQ(0xDD, result->Int32Value());
2806 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2808 v8::Isolate* isolate = env->GetIsolate();
2809 v8::HandleScope handle_scope(isolate);
2812 v8::Local<v8::Value> result =
2813 CompileRun("var ab1 = new ArrayBuffer(2);"
2814 "var u8_a = new Uint8Array(ab1);"
2816 "u8_a[1] = 0xFF; u8_a.buffer");
2817 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2818 CheckInternalFieldsAreZero(ab1);
2819 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2820 CHECK(!ab1->IsExternal());
2821 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2822 CHECK(ab1->IsExternal());
2824 result = CompileRun("ab1.byteLength");
2825 CHECK_EQ(2, result->Int32Value());
2826 result = CompileRun("u8_a[0]");
2827 CHECK_EQ(0xAA, result->Int32Value());
2828 result = CompileRun("u8_a[1]");
2829 CHECK_EQ(0xFF, result->Int32Value());
2830 result = CompileRun("var u8_b = new Uint8Array(ab1);"
2833 CHECK_EQ(0xBB, result->Int32Value());
2834 result = CompileRun("u8_b[1]");
2835 CHECK_EQ(0xFF, result->Int32Value());
2837 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2838 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2839 CHECK_EQ(0xBB, ab1_data[0]);
2840 CHECK_EQ(0xFF, ab1_data[1]);
2843 result = CompileRun("u8_a[0] + u8_a[1]");
2844 CHECK_EQ(0xDD, result->Int32Value());
2848 THREADED_TEST(ArrayBuffer_External) {
2850 v8::Isolate* isolate = env->GetIsolate();
2851 v8::HandleScope handle_scope(isolate);
2853 i::ScopedVector<uint8_t> my_data(100);
2854 memset(my_data.start(), 0, 100);
2855 Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
2856 CheckInternalFieldsAreZero(ab3);
2857 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2858 CHECK(ab3->IsExternal());
2860 env->Global()->Set(v8_str("ab3"), ab3);
2862 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2863 CHECK_EQ(100, result->Int32Value());
2865 result = CompileRun("var u8_b = new Uint8Array(ab3);"
2869 CHECK_EQ(100, result->Int32Value());
2870 CHECK_EQ(0xBB, my_data[0]);
2871 CHECK_EQ(0xCC, my_data[1]);
2874 result = CompileRun("u8_b[0] + u8_b[1]");
2875 CHECK_EQ(0xDD, result->Int32Value());
2879 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2880 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2881 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2885 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2886 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2887 CHECK_EQ(0, static_cast<int>(ta->Length()));
2888 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2892 static void CheckIsTypedArrayVarNeutered(const char* name) {
2893 i::ScopedVector<char> source(1024);
2894 i::OS::SNPrintF(source,
2895 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2897 CHECK(CompileRun(source.start())->IsTrue());
2898 v8::Handle<v8::TypedArray> ta =
2899 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2900 CheckIsNeutered(ta);
2904 template <typename TypedArray, int kElementSize>
2905 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2908 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2909 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2910 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2911 CHECK_EQ(length, static_cast<int>(ta->Length()));
2912 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2917 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2919 v8::Isolate* isolate = env->GetIsolate();
2920 v8::HandleScope handle_scope(isolate);
2922 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024);
2924 v8::Handle<v8::Uint8Array> u8a =
2925 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2926 v8::Handle<v8::Uint8ClampedArray> u8c =
2927 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2928 v8::Handle<v8::Int8Array> i8a =
2929 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2931 v8::Handle<v8::Uint16Array> u16a =
2932 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2933 v8::Handle<v8::Int16Array> i16a =
2934 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2936 v8::Handle<v8::Uint32Array> u32a =
2937 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2938 v8::Handle<v8::Int32Array> i32a =
2939 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2941 v8::Handle<v8::Float32Array> f32a =
2942 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2943 v8::Handle<v8::Float64Array> f64a =
2944 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2946 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2947 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2948 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2949 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2951 ScopedArrayBufferContents contents(buffer->Externalize());
2953 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2954 CheckIsNeutered(u8a);
2955 CheckIsNeutered(u8c);
2956 CheckIsNeutered(i8a);
2957 CheckIsNeutered(u16a);
2958 CheckIsNeutered(i16a);
2959 CheckIsNeutered(u32a);
2960 CheckIsNeutered(i32a);
2961 CheckIsNeutered(f32a);
2962 CheckIsNeutered(f64a);
2963 CheckDataViewIsNeutered(dv);
2967 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2969 v8::Isolate* isolate = env->GetIsolate();
2970 v8::HandleScope handle_scope(isolate);
2973 "var ab = new ArrayBuffer(1024);"
2974 "var u8a = new Uint8Array(ab, 1, 1023);"
2975 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2976 "var i8a = new Int8Array(ab, 1, 1023);"
2977 "var u16a = new Uint16Array(ab, 2, 511);"
2978 "var i16a = new Int16Array(ab, 2, 511);"
2979 "var u32a = new Uint32Array(ab, 4, 255);"
2980 "var i32a = new Int32Array(ab, 4, 255);"
2981 "var f32a = new Float32Array(ab, 4, 255);"
2982 "var f64a = new Float64Array(ab, 8, 127);"
2983 "var dv = new DataView(ab, 1, 1023);");
2985 v8::Handle<v8::ArrayBuffer> ab =
2986 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2988 v8::Handle<v8::DataView> dv =
2989 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2991 ScopedArrayBufferContents contents(ab->Externalize());
2993 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2994 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2996 CheckIsTypedArrayVarNeutered("u8a");
2997 CheckIsTypedArrayVarNeutered("u8c");
2998 CheckIsTypedArrayVarNeutered("i8a");
2999 CheckIsTypedArrayVarNeutered("u16a");
3000 CheckIsTypedArrayVarNeutered("i16a");
3001 CheckIsTypedArrayVarNeutered("u32a");
3002 CheckIsTypedArrayVarNeutered("i32a");
3003 CheckIsTypedArrayVarNeutered("f32a");
3004 CheckIsTypedArrayVarNeutered("f64a");
3006 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3007 CheckDataViewIsNeutered(dv);
3012 THREADED_TEST(HiddenProperties) {
3014 v8::HandleScope scope(env->GetIsolate());
3016 v8::Local<v8::Object> obj = v8::Object::New();
3017 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3018 v8::Local<v8::String> empty = v8_str("");
3019 v8::Local<v8::String> prop_name = v8_str("prop_name");
3021 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3023 // Make sure delete of a non-existent hidden value works
3024 CHECK(obj->DeleteHiddenValue(key));
3026 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
3027 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3028 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3029 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3031 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3033 // Make sure we do not find the hidden property.
3034 CHECK(!obj->Has(empty));
3035 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3036 CHECK(obj->Get(empty)->IsUndefined());
3037 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3038 CHECK(obj->Set(empty, v8::Integer::New(2003)));
3039 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3040 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3042 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3044 // Add another property and delete it afterwards to force the object in
3046 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
3047 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3048 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3049 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3050 CHECK(obj->Delete(prop_name));
3051 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3053 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3055 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3056 CHECK(obj->GetHiddenValue(key).IsEmpty());
3058 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3059 CHECK(obj->DeleteHiddenValue(key));
3060 CHECK(obj->GetHiddenValue(key).IsEmpty());
3064 THREADED_TEST(Regress97784) {
3065 // Regression test for crbug.com/97784
3066 // Messing with the Object.prototype should not have effect on
3067 // hidden properties.
3069 v8::HandleScope scope(env->GetIsolate());
3071 v8::Local<v8::Object> obj = v8::Object::New();
3072 v8::Local<v8::String> key = v8_str("hidden");
3075 "set_called = false;"
3076 "Object.defineProperty("
3077 " Object.prototype,"
3079 " {get: function() { return 45; },"
3080 " set: function() { set_called = true; }})");
3082 CHECK(obj->GetHiddenValue(key).IsEmpty());
3083 // Make sure that the getter and setter from Object.prototype is not invoked.
3084 // If it did we would have full access to the hidden properties in
3086 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
3087 ExpectFalse("set_called");
3088 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3092 static bool interceptor_for_hidden_properties_called;
3093 static void InterceptorForHiddenProperties(
3094 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3095 interceptor_for_hidden_properties_called = true;
3099 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3100 LocalContext context;
3101 v8::HandleScope scope(context->GetIsolate());
3103 interceptor_for_hidden_properties_called = false;
3105 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3107 // Associate an interceptor with an object and start setting hidden values.
3108 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
3109 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3110 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3111 Local<v8::Function> function = fun_templ->GetFunction();
3112 Local<v8::Object> obj = function->NewInstance();
3113 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
3114 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3115 CHECK(!interceptor_for_hidden_properties_called);
3119 THREADED_TEST(External) {
3120 v8::HandleScope scope(CcTest::isolate());
3122 Local<v8::External> ext = v8::External::New(&x);
3124 env->Global()->Set(v8_str("ext"), ext);
3125 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3126 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3127 int* ptr = static_cast<int*>(reext->Value());
3132 // Make sure unaligned pointers are wrapped properly.
3133 char* data = i::StrDup("0123456789");
3134 Local<v8::Value> zero = v8::External::New(&data[0]);
3135 Local<v8::Value> one = v8::External::New(&data[1]);
3136 Local<v8::Value> two = v8::External::New(&data[2]);
3137 Local<v8::Value> three = v8::External::New(&data[3]);
3139 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3140 CHECK_EQ('0', *char_ptr);
3141 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3142 CHECK_EQ('1', *char_ptr);
3143 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3144 CHECK_EQ('2', *char_ptr);
3145 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3146 CHECK_EQ('3', *char_ptr);
3147 i::DeleteArray(data);
3151 THREADED_TEST(GlobalHandle) {
3152 v8::Isolate* isolate = CcTest::isolate();
3153 v8::Persistent<String> global;
3155 v8::HandleScope scope(isolate);
3156 global.Reset(isolate, v8_str("str"));
3159 v8::HandleScope scope(isolate);
3160 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3165 v8::HandleScope scope(isolate);
3166 global.Reset(isolate, v8_str("str"));
3169 v8::HandleScope scope(isolate);
3170 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3176 THREADED_TEST(ResettingGlobalHandle) {
3177 v8::Isolate* isolate = CcTest::isolate();
3178 v8::Persistent<String> global;
3180 v8::HandleScope scope(isolate);
3181 global.Reset(isolate, v8_str("str"));
3183 v8::internal::GlobalHandles* global_handles =
3184 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3185 int initial_handle_count = global_handles->global_handles_count();
3187 v8::HandleScope scope(isolate);
3188 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3191 v8::HandleScope scope(isolate);
3192 global.Reset(isolate, v8_str("longer"));
3194 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3196 v8::HandleScope scope(isolate);
3197 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3200 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3204 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3205 v8::Isolate* isolate = CcTest::isolate();
3206 v8::Persistent<String> global;
3208 v8::HandleScope scope(isolate);
3209 global.Reset(isolate, v8_str("str"));
3211 v8::internal::GlobalHandles* global_handles =
3212 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3213 int initial_handle_count = global_handles->global_handles_count();
3215 v8::HandleScope scope(isolate);
3216 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3219 v8::HandleScope scope(isolate);
3220 Local<String> empty;
3221 global.Reset(isolate, empty);
3223 CHECK(global.IsEmpty());
3224 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3228 THREADED_TEST(ClearAndLeakGlobal) {
3229 v8::Isolate* isolate = CcTest::isolate();
3230 v8::internal::GlobalHandles* global_handles = NULL;
3231 int initial_handle_count = 0;
3232 v8::Persistent<String> global;
3234 v8::HandleScope scope(isolate);
3235 Local<String> str = v8_str("str");
3237 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3238 initial_handle_count = global_handles->global_handles_count();
3239 global.Reset(isolate, str);
3241 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3242 String* str = global.ClearAndLeak();
3243 CHECK(global.IsEmpty());
3244 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3245 global_handles->Destroy(reinterpret_cast<i::Object**>(str));
3246 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3250 THREADED_TEST(GlobalHandleUpcast) {
3251 v8::Isolate* isolate = CcTest::isolate();
3252 v8::HandleScope scope(isolate);
3253 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3254 v8::Persistent<String> global_string(isolate, local);
3255 v8::Persistent<Value>& global_value =
3256 v8::Persistent<Value>::Cast(global_string);
3257 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3258 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3259 global_string.Dispose();
3263 THREADED_TEST(HandleEquality) {
3264 v8::Isolate* isolate = CcTest::isolate();
3265 v8::Persistent<String> global1;
3266 v8::Persistent<String> global2;
3268 v8::HandleScope scope(isolate);
3269 global1.Reset(isolate, v8_str("str"));
3270 global2.Reset(isolate, v8_str("str2"));
3272 CHECK_EQ(global1 == global1, true);
3273 CHECK_EQ(global1 != global1, false);
3275 v8::HandleScope scope(isolate);
3276 Local<String> local1 = Local<String>::New(isolate, global1);
3277 Local<String> local2 = Local<String>::New(isolate, global2);
3279 CHECK_EQ(global1 == local1, true);
3280 CHECK_EQ(global1 != local1, false);
3281 CHECK_EQ(local1 == global1, true);
3282 CHECK_EQ(local1 != global1, false);
3284 CHECK_EQ(global1 == local2, false);
3285 CHECK_EQ(global1 != local2, true);
3286 CHECK_EQ(local2 == global1, false);
3287 CHECK_EQ(local2 != global1, true);
3289 CHECK_EQ(local1 == local2, false);
3290 CHECK_EQ(local1 != local2, true);
3292 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3293 CHECK_EQ(local1 == anotherLocal1, true);
3294 CHECK_EQ(local1 != anotherLocal1, false);
3301 THREADED_TEST(LocalHandle) {
3302 v8::HandleScope scope(CcTest::isolate());
3303 v8::Local<String> local =
3304 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3305 CHECK_EQ(local->Length(), 3);
3309 class WeakCallCounter {
3311 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3312 int id() { return id_; }
3313 void increment() { number_of_weak_calls_++; }
3314 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3317 int number_of_weak_calls_;
3321 template<typename T>
3322 static void WeakPointerCallback(v8::Isolate* isolate,
3323 Persistent<T>* handle,
3324 WeakCallCounter* counter) {
3325 CHECK_EQ(1234, counter->id());
3326 counter->increment();
3331 template<typename T>
3332 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3333 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3337 THREADED_TEST(ApiObjectGroups) {
3339 v8::Isolate* iso = env->GetIsolate();
3340 HandleScope scope(iso);
3342 Persistent<Value> g1s1;
3343 Persistent<Value> g1s2;
3344 Persistent<Value> g1c1;
3345 Persistent<Value> g2s1;
3346 Persistent<Value> g2s2;
3347 Persistent<Value> g2c1;
3349 WeakCallCounter counter(1234);
3352 HandleScope scope(iso);
3353 g1s1.Reset(iso, Object::New());
3354 g1s2.Reset(iso, Object::New());
3355 g1c1.Reset(iso, Object::New());
3356 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3357 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3358 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3360 g2s1.Reset(iso, Object::New());
3361 g2s2.Reset(iso, Object::New());
3362 g2c1.Reset(iso, Object::New());
3363 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3364 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3365 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3368 Persistent<Value> root(iso, g1s1); // make a root.
3370 // Connect group 1 and 2, make a cycle.
3372 HandleScope scope(iso);
3373 CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
3374 Set(0, Local<Value>::New(iso, g2s2)));
3375 CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
3376 Set(0, Local<Value>::New(iso, g1s1)));
3380 UniqueId id1 = MakeUniqueId(g1s1);
3381 UniqueId id2 = MakeUniqueId(g2s2);
3382 iso->SetObjectGroupId(g1s1, id1);
3383 iso->SetObjectGroupId(g1s2, id1);
3384 iso->SetReferenceFromGroup(id1, g1c1);
3385 iso->SetObjectGroupId(g2s1, id2);
3386 iso->SetObjectGroupId(g2s2, id2);
3387 iso->SetReferenceFromGroup(id2, g2c1);
3389 // Do a single full GC, ensure incremental marking is stopped.
3390 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3392 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3394 // All object should be alive.
3395 CHECK_EQ(0, counter.NumberOfWeakCalls());
3398 root.MakeWeak(&counter, &WeakPointerCallback);
3399 // But make children strong roots---all the objects (except for children)
3400 // should be collectable now.
3404 // Groups are deleted, rebuild groups.
3406 UniqueId id1 = MakeUniqueId(g1s1);
3407 UniqueId id2 = MakeUniqueId(g2s2);
3408 iso->SetObjectGroupId(g1s1, id1);
3409 iso->SetObjectGroupId(g1s2, id1);
3410 iso->SetReferenceFromGroup(id1, g1c1);
3411 iso->SetObjectGroupId(g2s1, id2);
3412 iso->SetObjectGroupId(g2s2, id2);
3413 iso->SetReferenceFromGroup(id2, g2c1);
3416 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3418 // All objects should be gone. 5 global handles in total.
3419 CHECK_EQ(5, counter.NumberOfWeakCalls());
3421 // And now make children weak again and collect them.
3422 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3423 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3425 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3426 CHECK_EQ(7, counter.NumberOfWeakCalls());
3430 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3432 v8::Isolate* iso = env->GetIsolate();
3433 HandleScope scope(iso);
3435 Persistent<Object> g1s1;
3436 Persistent<String> g1s2;
3437 Persistent<String> g1c1;
3438 Persistent<Object> g2s1;
3439 Persistent<String> g2s2;
3440 Persistent<String> g2c1;
3442 WeakCallCounter counter(1234);
3445 HandleScope scope(iso);
3446 g1s1.Reset(iso, Object::New());
3447 g1s2.Reset(iso, String::New("foo1"));
3448 g1c1.Reset(iso, String::New("foo2"));
3449 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3450 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3451 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3453 g2s1.Reset(iso, Object::New());
3454 g2s2.Reset(iso, String::New("foo3"));
3455 g2c1.Reset(iso, String::New("foo4"));
3456 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3457 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3458 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3461 Persistent<Value> root(iso, g1s1); // make a root.
3463 // Connect group 1 and 2, make a cycle.
3465 HandleScope scope(iso);
3466 CHECK(Local<Object>::New(iso, g1s1)->Set(0, Local<Object>::New(iso, g2s1)));
3467 CHECK(Local<Object>::New(iso, g2s1)->Set(0, Local<Object>::New(iso, g1s1)));
3471 UniqueId id1 = MakeUniqueId(g1s1);
3472 UniqueId id2 = MakeUniqueId(g2s2);
3473 iso->SetObjectGroupId(g1s1, id1);
3474 iso->SetObjectGroupId(g1s2, id1);
3475 iso->SetReference(g1s1, g1c1);
3476 iso->SetObjectGroupId(g2s1, id2);
3477 iso->SetObjectGroupId(g2s2, id2);
3478 iso->SetReferenceFromGroup(id2, g2c1);
3480 // Do a single full GC, ensure incremental marking is stopped.
3481 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3483 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3485 // All object should be alive.
3486 CHECK_EQ(0, counter.NumberOfWeakCalls());
3489 root.MakeWeak(&counter, &WeakPointerCallback);
3490 // But make children strong roots---all the objects (except for children)
3491 // should be collectable now.
3495 // Groups are deleted, rebuild groups.
3497 UniqueId id1 = MakeUniqueId(g1s1);
3498 UniqueId id2 = MakeUniqueId(g2s2);
3499 iso->SetObjectGroupId(g1s1, id1);
3500 iso->SetObjectGroupId(g1s2, id1);
3501 iso->SetReference(g1s1, g1c1);
3502 iso->SetObjectGroupId(g2s1, id2);
3503 iso->SetObjectGroupId(g2s2, id2);
3504 iso->SetReferenceFromGroup(id2, g2c1);
3507 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3509 // All objects should be gone. 5 global handles in total.
3510 CHECK_EQ(5, counter.NumberOfWeakCalls());
3512 // And now make children weak again and collect them.
3513 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3514 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3516 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3517 CHECK_EQ(7, counter.NumberOfWeakCalls());
3521 THREADED_TEST(ApiObjectGroupsCycle) {
3523 v8::Isolate* iso = env->GetIsolate();
3524 HandleScope scope(iso);
3526 WeakCallCounter counter(1234);
3528 Persistent<Value> g1s1;
3529 Persistent<Value> g1s2;
3530 Persistent<Value> g2s1;
3531 Persistent<Value> g2s2;
3532 Persistent<Value> g3s1;
3533 Persistent<Value> g3s2;
3534 Persistent<Value> g4s1;
3535 Persistent<Value> g4s2;
3538 HandleScope scope(iso);
3539 g1s1.Reset(iso, Object::New());
3540 g1s2.Reset(iso, Object::New());
3541 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3542 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3543 CHECK(g1s1.IsWeak());
3544 CHECK(g1s2.IsWeak());
3546 g2s1.Reset(iso, Object::New());
3547 g2s2.Reset(iso, Object::New());
3548 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3549 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3550 CHECK(g2s1.IsWeak());
3551 CHECK(g2s2.IsWeak());
3553 g3s1.Reset(iso, Object::New());
3554 g3s2.Reset(iso, Object::New());
3555 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3556 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3557 CHECK(g3s1.IsWeak());
3558 CHECK(g3s2.IsWeak());
3560 g4s1.Reset(iso, Object::New());
3561 g4s2.Reset(iso, Object::New());
3562 g4s1.MakeWeak(&counter, &WeakPointerCallback);
3563 g4s2.MakeWeak(&counter, &WeakPointerCallback);
3564 CHECK(g4s1.IsWeak());
3565 CHECK(g4s2.IsWeak());
3568 Persistent<Value> root(iso, g1s1); // make a root.
3570 // Connect groups. We're building the following cycle:
3571 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3574 UniqueId id1 = MakeUniqueId(g1s1);
3575 UniqueId id2 = MakeUniqueId(g2s1);
3576 UniqueId id3 = MakeUniqueId(g3s1);
3577 UniqueId id4 = MakeUniqueId(g4s1);
3578 iso->SetObjectGroupId(g1s1, id1);
3579 iso->SetObjectGroupId(g1s2, id1);
3580 iso->SetReferenceFromGroup(id1, g2s1);
3581 iso->SetObjectGroupId(g2s1, id2);
3582 iso->SetObjectGroupId(g2s2, id2);
3583 iso->SetReferenceFromGroup(id2, g3s1);
3584 iso->SetObjectGroupId(g3s1, id3);
3585 iso->SetObjectGroupId(g3s2, id3);
3586 iso->SetReferenceFromGroup(id3, g4s1);
3587 iso->SetObjectGroupId(g4s1, id4);
3588 iso->SetObjectGroupId(g4s2, id4);
3589 iso->SetReferenceFromGroup(id4, g1s1);
3591 // Do a single full GC
3592 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3594 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3596 // All object should be alive.
3597 CHECK_EQ(0, counter.NumberOfWeakCalls());
3600 root.MakeWeak(&counter, &WeakPointerCallback);
3602 // Groups are deleted, rebuild groups.
3604 UniqueId id1 = MakeUniqueId(g1s1);
3605 UniqueId id2 = MakeUniqueId(g2s1);
3606 UniqueId id3 = MakeUniqueId(g3s1);
3607 UniqueId id4 = MakeUniqueId(g4s1);
3608 iso->SetObjectGroupId(g1s1, id1);
3609 iso->SetObjectGroupId(g1s2, id1);
3610 iso->SetReferenceFromGroup(id1, g2s1);
3611 iso->SetObjectGroupId(g2s1, id2);
3612 iso->SetObjectGroupId(g2s2, id2);
3613 iso->SetReferenceFromGroup(id2, g3s1);
3614 iso->SetObjectGroupId(g3s1, id3);
3615 iso->SetObjectGroupId(g3s2, id3);
3616 iso->SetReferenceFromGroup(id3, g4s1);
3617 iso->SetObjectGroupId(g4s1, id4);
3618 iso->SetObjectGroupId(g4s2, id4);
3619 iso->SetReferenceFromGroup(id4, g1s1);
3622 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3624 // All objects should be gone. 9 global handles in total.
3625 CHECK_EQ(9, counter.NumberOfWeakCalls());
3629 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3630 // on the buildbots, so was made non-threaded for the time being.
3631 TEST(ApiObjectGroupsCycleForScavenger) {
3632 i::FLAG_stress_compaction = false;
3633 i::FLAG_gc_global = false;
3635 v8::Isolate* iso = env->GetIsolate();
3636 HandleScope scope(iso);
3638 WeakCallCounter counter(1234);
3640 Persistent<Value> g1s1;
3641 Persistent<Value> g1s2;
3642 Persistent<Value> g2s1;
3643 Persistent<Value> g2s2;
3644 Persistent<Value> g3s1;
3645 Persistent<Value> g3s2;
3648 HandleScope scope(iso);
3649 g1s1.Reset(iso, Object::New());
3650 g1s2.Reset(iso, Object::New());
3651 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3652 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3654 g2s1.Reset(iso, Object::New());
3655 g2s2.Reset(iso, Object::New());
3656 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3657 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3659 g3s1.Reset(iso, Object::New());
3660 g3s2.Reset(iso, Object::New());
3661 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3662 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3666 Persistent<Value> root(iso, g1s1);
3667 root.MarkPartiallyDependent();
3669 // Connect groups. We're building the following cycle:
3670 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3673 HandleScope handle_scope(iso);
3674 g1s1.MarkPartiallyDependent();
3675 g1s2.MarkPartiallyDependent();
3676 g2s1.MarkPartiallyDependent();
3677 g2s2.MarkPartiallyDependent();
3678 g3s1.MarkPartiallyDependent();
3679 g3s2.MarkPartiallyDependent();
3680 iso->SetObjectGroupId(g1s1, UniqueId(1));
3681 iso->SetObjectGroupId(g1s2, UniqueId(1));
3682 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3683 v8_str("x"), Local<Value>::New(iso, g2s1));
3684 iso->SetObjectGroupId(g2s1, UniqueId(2));
3685 iso->SetObjectGroupId(g2s2, UniqueId(2));
3686 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3687 v8_str("x"), Local<Value>::New(iso, g3s1));
3688 iso->SetObjectGroupId(g3s1, UniqueId(3));
3689 iso->SetObjectGroupId(g3s2, UniqueId(3));
3690 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3691 v8_str("x"), Local<Value>::New(iso, g1s1));
3694 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3696 heap->CollectGarbage(i::NEW_SPACE);
3698 // All objects should be alive.
3699 CHECK_EQ(0, counter.NumberOfWeakCalls());
3702 root.MakeWeak(&counter, &WeakPointerCallback);
3703 root.MarkPartiallyDependent();
3705 // Groups are deleted, rebuild groups.
3707 HandleScope handle_scope(iso);
3708 g1s1.MarkPartiallyDependent();
3709 g1s2.MarkPartiallyDependent();
3710 g2s1.MarkPartiallyDependent();
3711 g2s2.MarkPartiallyDependent();
3712 g3s1.MarkPartiallyDependent();
3713 g3s2.MarkPartiallyDependent();
3714 iso->SetObjectGroupId(g1s1, UniqueId(1));
3715 iso->SetObjectGroupId(g1s2, UniqueId(1));
3716 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3717 v8_str("x"), Local<Value>::New(iso, g2s1));
3718 iso->SetObjectGroupId(g2s1, UniqueId(2));
3719 iso->SetObjectGroupId(g2s2, UniqueId(2));
3720 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3721 v8_str("x"), Local<Value>::New(iso, g3s1));
3722 iso->SetObjectGroupId(g3s1, UniqueId(3));
3723 iso->SetObjectGroupId(g3s2, UniqueId(3));
3724 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3725 v8_str("x"), Local<Value>::New(iso, g1s1));
3728 heap->CollectGarbage(i::NEW_SPACE);
3730 // All objects should be gone. 7 global handles in total.
3731 CHECK_EQ(7, counter.NumberOfWeakCalls());
3735 THREADED_TEST(ScriptException) {
3737 v8::HandleScope scope(env->GetIsolate());
3738 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3739 v8::TryCatch try_catch;
3740 Local<Value> result = script->Run();
3741 CHECK(result.IsEmpty());
3742 CHECK(try_catch.HasCaught());
3743 String::Utf8Value exception_value(try_catch.Exception());
3744 CHECK_EQ(*exception_value, "panama!");
3748 TEST(TryCatchCustomException) {
3750 v8::HandleScope scope(env->GetIsolate());
3751 v8::TryCatch try_catch;
3752 CompileRun("function CustomError() { this.a = 'b'; }"
3753 "(function f() { throw new CustomError(); })();");
3754 CHECK(try_catch.HasCaught());
3755 CHECK(try_catch.Exception()->ToObject()->
3756 Get(v8_str("a"))->Equals(v8_str("b")));
3760 bool message_received;
3763 static void check_message_0(v8::Handle<v8::Message> message,
3764 v8::Handle<Value> data) {
3765 CHECK_EQ(5.76, data->NumberValue());
3766 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3767 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3768 CHECK(!message->IsSharedCrossOrigin());
3769 message_received = true;
3773 THREADED_TEST(MessageHandler0) {
3774 message_received = false;
3775 v8::HandleScope scope(CcTest::isolate());
3776 CHECK(!message_received);
3777 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3778 LocalContext context;
3779 v8::ScriptOrigin origin =
3780 v8::ScriptOrigin(v8_str("6.75"));
3781 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3783 script->SetData(v8_str("7.56"));
3785 CHECK(message_received);
3786 // clear out the message listener
3787 v8::V8::RemoveMessageListeners(check_message_0);
3791 static void check_message_1(v8::Handle<v8::Message> message,
3792 v8::Handle<Value> data) {
3793 CHECK(data->IsNumber());
3794 CHECK_EQ(1337, data->Int32Value());
3795 CHECK(!message->IsSharedCrossOrigin());
3796 message_received = true;
3800 TEST(MessageHandler1) {
3801 message_received = false;
3802 v8::HandleScope scope(CcTest::isolate());
3803 CHECK(!message_received);
3804 v8::V8::AddMessageListener(check_message_1);
3805 LocalContext context;
3806 CompileRun("throw 1337;");
3807 CHECK(message_received);
3808 // clear out the message listener
3809 v8::V8::RemoveMessageListeners(check_message_1);
3813 static void check_message_2(v8::Handle<v8::Message> message,
3814 v8::Handle<Value> data) {
3815 LocalContext context;
3816 CHECK(data->IsObject());
3817 v8::Local<v8::Value> hidden_property =
3818 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3819 CHECK(v8_str("hidden value")->Equals(hidden_property));
3820 CHECK(!message->IsSharedCrossOrigin());
3821 message_received = true;
3825 TEST(MessageHandler2) {
3826 message_received = false;
3827 v8::HandleScope scope(CcTest::isolate());
3828 CHECK(!message_received);
3829 v8::V8::AddMessageListener(check_message_2);
3830 LocalContext context;
3831 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3832 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
3833 v8_str("hidden value"));
3834 context->Global()->Set(v8_str("error"), error);
3835 CompileRun("throw error;");
3836 CHECK(message_received);
3837 // clear out the message listener
3838 v8::V8::RemoveMessageListeners(check_message_2);
3842 static void check_message_3(v8::Handle<v8::Message> message,
3843 v8::Handle<Value> data) {
3844 CHECK(message->IsSharedCrossOrigin());
3845 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3846 message_received = true;
3850 TEST(MessageHandler3) {
3851 message_received = false;
3852 v8::Isolate* isolate = CcTest::isolate();
3853 v8::HandleScope scope(isolate);
3854 CHECK(!message_received);
3855 v8::V8::AddMessageListener(check_message_3);
3856 LocalContext context;
3857 v8::ScriptOrigin origin =
3858 v8::ScriptOrigin(v8_str("6.75"),
3859 v8::Integer::New(1, isolate),
3860 v8::Integer::New(2, isolate),
3862 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3865 CHECK(message_received);
3866 // clear out the message listener
3867 v8::V8::RemoveMessageListeners(check_message_3);
3871 static void check_message_4(v8::Handle<v8::Message> message,
3872 v8::Handle<Value> data) {
3873 CHECK(!message->IsSharedCrossOrigin());
3874 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3875 message_received = true;
3879 TEST(MessageHandler4) {
3880 message_received = false;
3881 v8::Isolate* isolate = CcTest::isolate();
3882 v8::HandleScope scope(isolate);
3883 CHECK(!message_received);
3884 v8::V8::AddMessageListener(check_message_4);
3885 LocalContext context;
3886 v8::ScriptOrigin origin =
3887 v8::ScriptOrigin(v8_str("6.75"),
3888 v8::Integer::New(1, isolate),
3889 v8::Integer::New(2, isolate),
3890 v8::False(isolate));
3891 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3894 CHECK(message_received);
3895 // clear out the message listener
3896 v8::V8::RemoveMessageListeners(check_message_4);
3900 static void check_message_5a(v8::Handle<v8::Message> message,
3901 v8::Handle<Value> data) {
3902 CHECK(message->IsSharedCrossOrigin());
3903 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3904 message_received = true;
3908 static void check_message_5b(v8::Handle<v8::Message> message,
3909 v8::Handle<Value> data) {
3910 CHECK(!message->IsSharedCrossOrigin());
3911 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3912 message_received = true;
3916 TEST(MessageHandler5) {
3917 message_received = false;
3918 v8::Isolate* isolate = CcTest::isolate();
3919 v8::HandleScope scope(isolate);
3920 CHECK(!message_received);
3921 v8::V8::AddMessageListener(check_message_5a);
3922 LocalContext context;
3923 v8::ScriptOrigin origin =
3924 v8::ScriptOrigin(v8_str("6.75"),
3925 v8::Integer::New(1, isolate),
3926 v8::Integer::New(2, isolate),
3928 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3931 CHECK(message_received);
3932 // clear out the message listener
3933 v8::V8::RemoveMessageListeners(check_message_5a);
3935 message_received = false;
3936 v8::V8::AddMessageListener(check_message_5b);
3938 v8::ScriptOrigin(v8_str("6.75"),
3939 v8::Integer::New(1, isolate),
3940 v8::Integer::New(2, isolate),
3941 v8::False(isolate));
3942 script = Script::Compile(v8_str("throw 'error'"),
3945 CHECK(message_received);
3946 // clear out the message listener
3947 v8::V8::RemoveMessageListeners(check_message_5b);
3951 THREADED_TEST(GetSetProperty) {
3952 LocalContext context;
3953 v8::HandleScope scope(context->GetIsolate());
3954 context->Global()->Set(v8_str("foo"), v8_num(14));
3955 context->Global()->Set(v8_str("12"), v8_num(92));
3956 context->Global()->Set(v8::Integer::New(16), v8_num(32));
3957 context->Global()->Set(v8_num(13), v8_num(56));
3958 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
3959 CHECK_EQ(14, foo->Int32Value());
3960 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
3961 CHECK_EQ(92, twelve->Int32Value());
3962 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
3963 CHECK_EQ(32, sixteen->Int32Value());
3964 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
3965 CHECK_EQ(56, thirteen->Int32Value());
3966 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
3967 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
3968 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
3969 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
3970 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
3971 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
3972 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
3973 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
3974 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
3978 THREADED_TEST(PropertyAttributes) {
3979 LocalContext context;
3980 v8::HandleScope scope(context->GetIsolate());
3982 Local<String> prop = v8_str("none");
3983 context->Global()->Set(prop, v8_num(7));
3984 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3986 prop = v8_str("read_only");
3987 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
3988 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3989 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
3990 Script::Compile(v8_str("read_only = 9"))->Run();
3991 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3992 context->Global()->Set(prop, v8_num(10));
3993 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3995 prop = v8_str("dont_delete");
3996 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
3997 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3998 Script::Compile(v8_str("delete dont_delete"))->Run();
3999 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4000 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4002 prop = v8_str("dont_enum");
4003 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4004 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4006 prop = v8_str("absent");
4007 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4008 Local<Value> fake_prop = v8_num(1);
4009 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4012 Local<Value> exception =
4013 CompileRun("({ toString: function() { throw 'exception';} })");
4014 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4015 CHECK(try_catch.HasCaught());
4016 String::Utf8Value exception_value(try_catch.Exception());
4017 CHECK_EQ("exception", *exception_value);
4022 THREADED_TEST(Array) {
4023 LocalContext context;
4024 v8::HandleScope scope(context->GetIsolate());
4025 Local<v8::Array> array = v8::Array::New();
4026 CHECK_EQ(0, array->Length());
4027 CHECK(array->Get(0)->IsUndefined());
4028 CHECK(!array->Has(0));
4029 CHECK(array->Get(100)->IsUndefined());
4030 CHECK(!array->Has(100));
4031 array->Set(2, v8_num(7));
4032 CHECK_EQ(3, array->Length());
4033 CHECK(!array->Has(0));
4034 CHECK(!array->Has(1));
4035 CHECK(array->Has(2));
4036 CHECK_EQ(7, array->Get(2)->Int32Value());
4037 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4038 Local<v8::Array> arr = obj.As<v8::Array>();
4039 CHECK_EQ(3, arr->Length());
4040 CHECK_EQ(1, arr->Get(0)->Int32Value());
4041 CHECK_EQ(2, arr->Get(1)->Int32Value());
4042 CHECK_EQ(3, arr->Get(2)->Int32Value());
4043 array = v8::Array::New(27);
4044 CHECK_EQ(27, array->Length());
4045 array = v8::Array::New(-27);
4046 CHECK_EQ(0, array->Length());
4050 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4051 v8::HandleScope scope(args.GetIsolate());
4052 ApiTestFuzzer::Fuzz();
4053 Local<v8::Array> result = v8::Array::New(args.Length());
4054 for (int i = 0; i < args.Length(); i++)
4055 result->Set(i, args[i]);
4056 args.GetReturnValue().Set(scope.Close(result));
4060 THREADED_TEST(Vector) {
4061 v8::HandleScope scope(CcTest::isolate());
4062 Local<ObjectTemplate> global = ObjectTemplate::New();
4063 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
4064 LocalContext context(0, global);
4066 const char* fun = "f()";
4067 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4068 CHECK_EQ(0, a0->Length());
4070 const char* fun2 = "f(11)";
4071 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4072 CHECK_EQ(1, a1->Length());
4073 CHECK_EQ(11, a1->Get(0)->Int32Value());
4075 const char* fun3 = "f(12, 13)";
4076 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4077 CHECK_EQ(2, a2->Length());
4078 CHECK_EQ(12, a2->Get(0)->Int32Value());
4079 CHECK_EQ(13, a2->Get(1)->Int32Value());
4081 const char* fun4 = "f(14, 15, 16)";
4082 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4083 CHECK_EQ(3, a3->Length());
4084 CHECK_EQ(14, a3->Get(0)->Int32Value());
4085 CHECK_EQ(15, a3->Get(1)->Int32Value());
4086 CHECK_EQ(16, a3->Get(2)->Int32Value());
4088 const char* fun5 = "f(17, 18, 19, 20)";
4089 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4090 CHECK_EQ(4, a4->Length());
4091 CHECK_EQ(17, a4->Get(0)->Int32Value());
4092 CHECK_EQ(18, a4->Get(1)->Int32Value());
4093 CHECK_EQ(19, a4->Get(2)->Int32Value());
4094 CHECK_EQ(20, a4->Get(3)->Int32Value());
4098 THREADED_TEST(FunctionCall) {
4099 LocalContext context;
4100 v8::Isolate* isolate = context->GetIsolate();
4101 v8::HandleScope scope(isolate);
4105 " for (var i = 0; i < arguments.length; i++) {"
4106 " result.push(arguments[i]);"
4110 "function ReturnThisSloppy() {"
4113 "function ReturnThisStrict() {"
4117 Local<Function> Foo =
4118 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4119 Local<Function> ReturnThisSloppy =
4120 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4121 Local<Function> ReturnThisStrict =
4122 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4124 v8::Handle<Value>* args0 = NULL;
4125 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4126 CHECK_EQ(0, a0->Length());
4128 v8::Handle<Value> args1[] = { v8_num(1.1) };
4129 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4130 CHECK_EQ(1, a1->Length());
4131 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4133 v8::Handle<Value> args2[] = { v8_num(2.2),
4135 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4136 CHECK_EQ(2, a2->Length());
4137 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4138 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4140 v8::Handle<Value> args3[] = { v8_num(4.4),
4143 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4144 CHECK_EQ(3, a3->Length());
4145 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4146 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4147 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4149 v8::Handle<Value> args4[] = { v8_num(7.7),
4153 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4154 CHECK_EQ(4, a4->Length());
4155 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4156 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4157 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4158 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4160 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4161 CHECK(r1->StrictEquals(context->Global()));
4162 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4163 CHECK(r2->StrictEquals(context->Global()));
4164 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4165 CHECK(r3->IsNumberObject());
4166 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4167 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4168 CHECK(r4->IsStringObject());
4169 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4170 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4171 CHECK(r5->IsBooleanObject());
4172 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4174 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4175 CHECK(r6->IsUndefined());
4176 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4177 CHECK(r7->IsNull());
4178 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4179 CHECK(r8->StrictEquals(v8_num(42)));
4180 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4181 CHECK(r9->StrictEquals(v8_str("hello")));
4182 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4183 CHECK(r10->StrictEquals(v8::True(isolate)));
4187 static const char* js_code_causing_out_of_memory =
4188 "var a = new Array(); while(true) a.push(a);";
4191 // These tests run for a long time and prevent us from running tests
4192 // that come after them so they cannot run in parallel.
4194 // It's not possible to read a snapshot into a heap with different dimensions.
4195 if (i::Snapshot::IsEnabled()) return;
4197 static const int K = 1024;
4198 v8::ResourceConstraints constraints;
4199 constraints.set_max_young_space_size(256 * K);
4200 constraints.set_max_old_space_size(5 * K * K);
4201 v8::SetResourceConstraints(&constraints);
4203 // Execute a script that causes out of memory.
4204 LocalContext context;
4205 v8::HandleScope scope(context->GetIsolate());
4206 v8::V8::IgnoreOutOfMemoryException();
4207 Local<Script> script =
4208 Script::Compile(String::New(js_code_causing_out_of_memory));
4209 Local<Value> result = script->Run();
4211 // Check for out of memory state.
4212 CHECK(result.IsEmpty());
4213 CHECK(context->HasOutOfMemoryException());
4217 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4218 ApiTestFuzzer::Fuzz();
4220 LocalContext context;
4221 v8::HandleScope scope(context->GetIsolate());
4222 Local<Script> script =
4223 Script::Compile(String::New(js_code_causing_out_of_memory));
4224 Local<Value> result = script->Run();
4226 // Check for out of memory state.
4227 CHECK(result.IsEmpty());
4228 CHECK(context->HasOutOfMemoryException());
4230 args.GetReturnValue().Set(result);
4234 TEST(OutOfMemoryNested) {
4235 // It's not possible to read a snapshot into a heap with different dimensions.
4236 if (i::Snapshot::IsEnabled()) return;
4238 static const int K = 1024;
4239 v8::ResourceConstraints constraints;
4240 constraints.set_max_young_space_size(256 * K);
4241 constraints.set_max_old_space_size(5 * K * K);
4242 v8::SetResourceConstraints(&constraints);
4244 v8::HandleScope scope(CcTest::isolate());
4245 Local<ObjectTemplate> templ = ObjectTemplate::New();
4246 templ->Set(v8_str("ProvokeOutOfMemory"),
4247 v8::FunctionTemplate::New(ProvokeOutOfMemory));
4248 LocalContext context(0, templ);
4249 v8::V8::IgnoreOutOfMemoryException();
4250 Local<Value> result = CompileRun(
4251 "var thrown = false;"
4253 " ProvokeOutOfMemory();"
4257 // Check for out of memory state.
4258 CHECK(result.IsEmpty());
4259 CHECK(context->HasOutOfMemoryException());
4263 TEST(HugeConsStringOutOfMemory) {
4264 // It's not possible to read a snapshot into a heap with different dimensions.
4265 if (i::Snapshot::IsEnabled()) return;
4267 static const int K = 1024;
4268 v8::ResourceConstraints constraints;
4269 constraints.set_max_young_space_size(256 * K);
4270 constraints.set_max_old_space_size(4 * K * K);
4271 v8::SetResourceConstraints(&constraints);
4273 // Execute a script that causes out of memory.
4274 v8::V8::IgnoreOutOfMemoryException();
4276 LocalContext context;
4277 v8::HandleScope scope(context->GetIsolate());
4279 // Build huge string. This should fail with out of memory exception.
4280 Local<Value> result = CompileRun(
4281 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4282 "for (var i = 0; i < 22; i++) { str = str + str; }");
4284 // Check for out of memory state.
4285 CHECK(result.IsEmpty());
4286 CHECK(context->HasOutOfMemoryException());
4290 THREADED_TEST(ConstructCall) {
4291 LocalContext context;
4292 v8::HandleScope scope(context->GetIsolate());
4296 " for (var i = 0; i < arguments.length; i++) {"
4297 " result.push(arguments[i]);"
4301 Local<Function> Foo =
4302 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4304 v8::Handle<Value>* args0 = NULL;
4305 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4306 CHECK_EQ(0, a0->Length());
4308 v8::Handle<Value> args1[] = { v8_num(1.1) };
4309 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4310 CHECK_EQ(1, a1->Length());
4311 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4313 v8::Handle<Value> args2[] = { v8_num(2.2),
4315 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4316 CHECK_EQ(2, a2->Length());
4317 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4318 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4320 v8::Handle<Value> args3[] = { v8_num(4.4),
4323 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4324 CHECK_EQ(3, a3->Length());
4325 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4326 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4327 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4329 v8::Handle<Value> args4[] = { v8_num(7.7),
4333 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4334 CHECK_EQ(4, a4->Length());
4335 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4336 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4337 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4338 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4342 static void CheckUncle(v8::TryCatch* try_catch) {
4343 CHECK(try_catch->HasCaught());
4344 String::Utf8Value str_value(try_catch->Exception());
4345 CHECK_EQ(*str_value, "uncle?");
4350 THREADED_TEST(ConversionNumber) {
4352 v8::HandleScope scope(env->GetIsolate());
4353 // Very large number.
4354 CompileRun("var obj = Math.pow(2,32) * 1237;");
4355 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4356 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4357 CHECK_EQ(0, obj->ToInt32()->Value());
4358 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4360 CompileRun("var obj = -1234567890123;");
4361 obj = env->Global()->Get(v8_str("obj"));
4362 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4363 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4364 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4365 // Small positive integer.
4366 CompileRun("var obj = 42;");
4367 obj = env->Global()->Get(v8_str("obj"));
4368 CHECK_EQ(42.0, obj->ToNumber()->Value());
4369 CHECK_EQ(42, obj->ToInt32()->Value());
4370 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4371 // Negative integer.
4372 CompileRun("var obj = -37;");
4373 obj = env->Global()->Get(v8_str("obj"));
4374 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4375 CHECK_EQ(-37, obj->ToInt32()->Value());
4376 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4377 // Positive non-int32 integer.
4378 CompileRun("var obj = 0x81234567;");
4379 obj = env->Global()->Get(v8_str("obj"));
4380 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4381 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4382 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4384 CompileRun("var obj = 42.3;");
4385 obj = env->Global()->Get(v8_str("obj"));
4386 CHECK_EQ(42.3, obj->ToNumber()->Value());
4387 CHECK_EQ(42, obj->ToInt32()->Value());
4388 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4389 // Large negative fraction.
4390 CompileRun("var obj = -5726623061.75;");
4391 obj = env->Global()->Get(v8_str("obj"));
4392 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4393 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4394 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4398 THREADED_TEST(isNumberType) {
4400 v8::HandleScope scope(env->GetIsolate());
4401 // Very large number.
4402 CompileRun("var obj = Math.pow(2,32) * 1237;");
4403 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4404 CHECK(!obj->IsInt32());
4405 CHECK(!obj->IsUint32());
4406 // Large negative number.
4407 CompileRun("var obj = -1234567890123;");
4408 obj = env->Global()->Get(v8_str("obj"));
4409 CHECK(!obj->IsInt32());
4410 CHECK(!obj->IsUint32());
4411 // Small positive integer.
4412 CompileRun("var obj = 42;");
4413 obj = env->Global()->Get(v8_str("obj"));
4414 CHECK(obj->IsInt32());
4415 CHECK(obj->IsUint32());
4416 // Negative integer.
4417 CompileRun("var obj = -37;");
4418 obj = env->Global()->Get(v8_str("obj"));
4419 CHECK(obj->IsInt32());
4420 CHECK(!obj->IsUint32());
4421 // Positive non-int32 integer.
4422 CompileRun("var obj = 0x81234567;");
4423 obj = env->Global()->Get(v8_str("obj"));
4424 CHECK(!obj->IsInt32());
4425 CHECK(obj->IsUint32());
4427 CompileRun("var obj = 42.3;");
4428 obj = env->Global()->Get(v8_str("obj"));
4429 CHECK(!obj->IsInt32());
4430 CHECK(!obj->IsUint32());
4431 // Large negative fraction.
4432 CompileRun("var obj = -5726623061.75;");
4433 obj = env->Global()->Get(v8_str("obj"));
4434 CHECK(!obj->IsInt32());
4435 CHECK(!obj->IsUint32());
4437 CompileRun("var obj = 0.0;");
4438 obj = env->Global()->Get(v8_str("obj"));
4439 CHECK(obj->IsInt32());
4440 CHECK(obj->IsUint32());
4442 CompileRun("var obj = -0.0;");
4443 obj = env->Global()->Get(v8_str("obj"));
4444 CHECK(!obj->IsInt32());
4445 CHECK(!obj->IsUint32());
4449 THREADED_TEST(ConversionException) {
4451 v8::Isolate* isolate = env->GetIsolate();
4452 v8::HandleScope scope(isolate);
4454 "function TestClass() { };"
4455 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4456 "var obj = new TestClass();");
4457 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4459 v8::TryCatch try_catch;
4461 Local<Value> to_string_result = obj->ToString();
4462 CHECK(to_string_result.IsEmpty());
4463 CheckUncle(&try_catch);
4465 Local<Value> to_number_result = obj->ToNumber();
4466 CHECK(to_number_result.IsEmpty());
4467 CheckUncle(&try_catch);
4469 Local<Value> to_integer_result = obj->ToInteger();
4470 CHECK(to_integer_result.IsEmpty());
4471 CheckUncle(&try_catch);
4473 Local<Value> to_uint32_result = obj->ToUint32();
4474 CHECK(to_uint32_result.IsEmpty());
4475 CheckUncle(&try_catch);
4477 Local<Value> to_int32_result = obj->ToInt32();
4478 CHECK(to_int32_result.IsEmpty());
4479 CheckUncle(&try_catch);
4481 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4482 CHECK(to_object_result.IsEmpty());
4483 CHECK(try_catch.HasCaught());
4486 int32_t int32_value = obj->Int32Value();
4487 CHECK_EQ(0, int32_value);
4488 CheckUncle(&try_catch);
4490 uint32_t uint32_value = obj->Uint32Value();
4491 CHECK_EQ(0, uint32_value);
4492 CheckUncle(&try_catch);
4494 double number_value = obj->NumberValue();
4495 CHECK_NE(0, std::isnan(number_value));
4496 CheckUncle(&try_catch);
4498 int64_t integer_value = obj->IntegerValue();
4499 CHECK_EQ(0.0, static_cast<double>(integer_value));
4500 CheckUncle(&try_catch);
4504 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4505 ApiTestFuzzer::Fuzz();
4506 args.GetIsolate()->ThrowException(v8_str("konto"));
4510 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4511 if (args.Length() < 1) {
4512 args.GetReturnValue().Set(false);
4515 v8::HandleScope scope(args.GetIsolate());
4516 v8::TryCatch try_catch;
4517 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4518 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4519 args.GetReturnValue().Set(try_catch.HasCaught());
4523 THREADED_TEST(APICatch) {
4524 v8::HandleScope scope(CcTest::isolate());
4525 Local<ObjectTemplate> templ = ObjectTemplate::New();
4526 templ->Set(v8_str("ThrowFromC"),
4527 v8::FunctionTemplate::New(ThrowFromC));
4528 LocalContext context(0, templ);
4530 "var thrown = false;"
4536 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4537 CHECK(thrown->BooleanValue());
4541 THREADED_TEST(APIThrowTryCatch) {
4542 v8::HandleScope scope(CcTest::isolate());
4543 Local<ObjectTemplate> templ = ObjectTemplate::New();
4544 templ->Set(v8_str("ThrowFromC"),
4545 v8::FunctionTemplate::New(ThrowFromC));
4546 LocalContext context(0, templ);
4547 v8::TryCatch try_catch;
4548 CompileRun("ThrowFromC();");
4549 CHECK(try_catch.HasCaught());
4553 // Test that a try-finally block doesn't shadow a try-catch block
4554 // when setting up an external handler.
4556 // BUG(271): Some of the exception propagation does not work on the
4557 // ARM simulator because the simulator separates the C++ stack and the
4558 // JS stack. This test therefore fails on the simulator. The test is
4559 // not threaded to allow the threading tests to run on the simulator.
4560 TEST(TryCatchInTryFinally) {
4561 v8::HandleScope scope(CcTest::isolate());
4562 Local<ObjectTemplate> templ = ObjectTemplate::New();
4563 templ->Set(v8_str("CCatcher"),
4564 v8::FunctionTemplate::New(CCatcher));
4565 LocalContext context(0, templ);
4566 Local<Value> result = CompileRun("try {"
4568 " CCatcher('throw 7;');"
4573 CHECK(result->IsTrue());
4577 static void check_reference_error_message(
4578 v8::Handle<v8::Message> message,
4579 v8::Handle<v8::Value> data) {
4580 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4581 CHECK(message->Get()->Equals(v8_str(reference_error)));
4585 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4586 ApiTestFuzzer::Fuzz();
4591 // Test that overwritten methods are not invoked on uncaught exception
4592 // formatting. However, they are invoked when performing normal error
4593 // string conversions.
4594 TEST(APIThrowMessageOverwrittenToString) {
4595 v8::HandleScope scope(CcTest::isolate());
4596 v8::V8::AddMessageListener(check_reference_error_message);
4597 Local<ObjectTemplate> templ = ObjectTemplate::New();
4598 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
4599 LocalContext context(NULL, templ);
4600 CompileRun("asdf;");
4601 CompileRun("var limit = {};"
4602 "limit.valueOf = fail;"
4603 "Error.stackTraceLimit = limit;");
4605 CompileRun("Array.prototype.pop = fail;");
4606 CompileRun("Object.prototype.hasOwnProperty = fail;");
4607 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4608 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4609 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4610 CompileRun("ReferenceError.prototype.toString ="
4611 " function() { return 'Whoops' }");
4612 CompileRun("asdf;");
4613 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4614 CompileRun("asdf;");
4615 CompileRun("ReferenceError.prototype.constructor = void 0;");
4616 CompileRun("asdf;");
4617 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4618 CompileRun("asdf;");
4619 CompileRun("ReferenceError.prototype = new Object();");
4620 CompileRun("asdf;");
4621 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4622 CHECK(string->Equals(v8_str("Whoops")));
4623 CompileRun("ReferenceError.prototype.constructor = new Object();"
4624 "ReferenceError.prototype.constructor.name = 1;"
4625 "Number.prototype.toString = function() { return 'Whoops'; };"
4626 "ReferenceError.prototype.toString = Object.prototype.toString;");
4627 CompileRun("asdf;");
4628 v8::V8::RemoveMessageListeners(check_reference_error_message);
4632 static void check_custom_error_tostring(
4633 v8::Handle<v8::Message> message,
4634 v8::Handle<v8::Value> data) {
4635 const char* uncaught_error = "Uncaught MyError toString";
4636 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4640 TEST(CustomErrorToString) {
4641 LocalContext context;
4642 v8::HandleScope scope(context->GetIsolate());
4643 v8::V8::AddMessageListener(check_custom_error_tostring);
4645 "function MyError(name, message) { "
4646 " this.name = name; "
4647 " this.message = message; "
4649 "MyError.prototype = Object.create(Error.prototype); "
4650 "MyError.prototype.toString = function() { "
4651 " return 'MyError toString'; "
4653 "throw new MyError('my name', 'my message'); ");
4654 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4658 static void check_custom_error_message(
4659 v8::Handle<v8::Message> message,
4660 v8::Handle<v8::Value> data) {
4661 const char* uncaught_error = "Uncaught MyError: my message";
4662 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4663 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4667 TEST(CustomErrorMessage) {
4668 LocalContext context;
4669 v8::HandleScope scope(context->GetIsolate());
4670 v8::V8::AddMessageListener(check_custom_error_message);
4674 "function MyError(msg) { "
4675 " this.name = 'MyError'; "
4676 " this.message = msg; "
4678 "MyError.prototype = new Error(); "
4679 "throw new MyError('my message'); ");
4683 "function MyError(msg) { "
4684 " this.name = 'MyError'; "
4685 " this.message = msg; "
4687 "inherits = function(childCtor, parentCtor) { "
4688 " function tempCtor() {}; "
4689 " tempCtor.prototype = parentCtor.prototype; "
4690 " childCtor.superClass_ = parentCtor.prototype; "
4691 " childCtor.prototype = new tempCtor(); "
4692 " childCtor.prototype.constructor = childCtor; "
4694 "inherits(MyError, Error); "
4695 "throw new MyError('my message'); ");
4699 "function MyError(msg) { "
4700 " this.name = 'MyError'; "
4701 " this.message = msg; "
4703 "MyError.prototype = Object.create(Error.prototype); "
4704 "throw new MyError('my message'); ");
4706 v8::V8::RemoveMessageListeners(check_custom_error_message);
4710 static void receive_message(v8::Handle<v8::Message> message,
4711 v8::Handle<v8::Value> data) {
4713 message_received = true;
4717 TEST(APIThrowMessage) {
4718 message_received = false;
4719 v8::HandleScope scope(CcTest::isolate());
4720 v8::V8::AddMessageListener(receive_message);
4721 Local<ObjectTemplate> templ = ObjectTemplate::New();
4722 templ->Set(v8_str("ThrowFromC"),
4723 v8::FunctionTemplate::New(ThrowFromC));
4724 LocalContext context(0, templ);
4725 CompileRun("ThrowFromC();");
4726 CHECK(message_received);
4727 v8::V8::RemoveMessageListeners(receive_message);
4731 TEST(APIThrowMessageAndVerboseTryCatch) {
4732 message_received = false;
4733 v8::HandleScope scope(CcTest::isolate());
4734 v8::V8::AddMessageListener(receive_message);
4735 Local<ObjectTemplate> templ = ObjectTemplate::New();
4736 templ->Set(v8_str("ThrowFromC"),
4737 v8::FunctionTemplate::New(ThrowFromC));
4738 LocalContext context(0, templ);
4739 v8::TryCatch try_catch;
4740 try_catch.SetVerbose(true);
4741 Local<Value> result = CompileRun("ThrowFromC();");
4742 CHECK(try_catch.HasCaught());
4743 CHECK(result.IsEmpty());
4744 CHECK(message_received);
4745 v8::V8::RemoveMessageListeners(receive_message);
4749 TEST(APIStackOverflowAndVerboseTryCatch) {
4750 message_received = false;
4751 LocalContext context;
4752 v8::HandleScope scope(context->GetIsolate());
4753 v8::V8::AddMessageListener(receive_message);
4754 v8::TryCatch try_catch;
4755 try_catch.SetVerbose(true);
4756 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4757 CHECK(try_catch.HasCaught());
4758 CHECK(result.IsEmpty());
4759 CHECK(message_received);
4760 v8::V8::RemoveMessageListeners(receive_message);
4764 THREADED_TEST(ExternalScriptException) {
4765 v8::HandleScope scope(CcTest::isolate());
4766 Local<ObjectTemplate> templ = ObjectTemplate::New();
4767 templ->Set(v8_str("ThrowFromC"),
4768 v8::FunctionTemplate::New(ThrowFromC));
4769 LocalContext context(0, templ);
4771 v8::TryCatch try_catch;
4772 Local<Script> script
4773 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4774 Local<Value> result = script->Run();
4775 CHECK(result.IsEmpty());
4776 CHECK(try_catch.HasCaught());
4777 String::Utf8Value exception_value(try_catch.Exception());
4778 CHECK_EQ("konto", *exception_value);
4783 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4784 ApiTestFuzzer::Fuzz();
4785 CHECK_EQ(4, args.Length());
4786 int count = args[0]->Int32Value();
4787 int cInterval = args[2]->Int32Value();
4789 args.GetIsolate()->ThrowException(v8_str("FromC"));
4792 Local<v8::Object> global =
4793 args.GetIsolate()->GetCurrentContext()->Global();
4794 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4795 v8::Handle<Value> argv[] = { v8_num(count - 1),
4799 if (count % cInterval == 0) {
4800 v8::TryCatch try_catch;
4801 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4802 int expected = args[3]->Int32Value();
4803 if (try_catch.HasCaught()) {
4804 CHECK_EQ(expected, count);
4805 CHECK(result.IsEmpty());
4806 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
4808 CHECK_NE(expected, count);
4810 args.GetReturnValue().Set(result);
4813 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4820 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4821 ApiTestFuzzer::Fuzz();
4822 CHECK_EQ(3, args.Length());
4823 bool equality = args[0]->BooleanValue();
4824 int count = args[1]->Int32Value();
4825 int expected = args[2]->Int32Value();
4827 CHECK_EQ(count, expected);
4829 CHECK_NE(count, expected);
4834 THREADED_TEST(EvalInTryFinally) {
4835 LocalContext context;
4836 v8::HandleScope scope(context->GetIsolate());
4837 v8::TryCatch try_catch;
4838 CompileRun("(function() {"
4840 " eval('asldkf (*&^&*^');"
4845 CHECK(!try_catch.HasCaught());
4849 // This test works by making a stack of alternating JavaScript and C
4850 // activations. These activations set up exception handlers with regular
4851 // intervals, one interval for C activations and another for JavaScript
4852 // activations. When enough activations have been created an exception is
4853 // thrown and we check that the right activation catches the exception and that
4854 // no other activations do. The right activation is always the topmost one with
4855 // a handler, regardless of whether it is in JavaScript or C.
4857 // The notation used to describe a test case looks like this:
4859 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4861 // Each entry is an activation, either JS or C. The index is the count at that
4862 // level. Stars identify activations with exception handlers, the @ identifies
4863 // the exception handler that should catch the exception.
4865 // BUG(271): Some of the exception propagation does not work on the
4866 // ARM simulator because the simulator separates the C++ stack and the
4867 // JS stack. This test therefore fails on the simulator. The test is
4868 // not threaded to allow the threading tests to run on the simulator.
4869 TEST(ExceptionOrder) {
4870 v8::HandleScope scope(CcTest::isolate());
4871 Local<ObjectTemplate> templ = ObjectTemplate::New();
4872 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
4873 templ->Set(v8_str("CThrowCountDown"),
4874 v8::FunctionTemplate::New(CThrowCountDown));
4875 LocalContext context(0, templ);
4877 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4878 " if (count == 0) throw 'FromJS';"
4879 " if (count % jsInterval == 0) {"
4881 " var value = CThrowCountDown(count - 1,"
4885 " check(false, count, expected);"
4888 " check(true, count, expected);"
4891 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4894 Local<Function> fun =
4895 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4898 // count jsInterval cInterval expected
4900 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4901 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
4902 fun->Call(fun, argc, a0);
4904 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4905 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
4906 fun->Call(fun, argc, a1);
4908 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4909 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
4910 fun->Call(fun, argc, a2);
4912 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4913 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
4914 fun->Call(fun, argc, a3);
4916 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4917 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
4918 fun->Call(fun, argc, a4);
4920 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4921 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
4922 fun->Call(fun, argc, a5);
4926 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4927 ApiTestFuzzer::Fuzz();
4928 CHECK_EQ(1, args.Length());
4929 args.GetIsolate()->ThrowException(args[0]);
4933 THREADED_TEST(ThrowValues) {
4934 v8::HandleScope scope(CcTest::isolate());
4935 Local<ObjectTemplate> templ = ObjectTemplate::New();
4936 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
4937 LocalContext context(0, templ);
4938 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4939 "function Run(obj) {"
4945 " return 'no exception';"
4947 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4948 CHECK_EQ(5, result->Length());
4949 CHECK(result->Get(v8::Integer::New(0))->IsString());
4950 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
4951 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
4952 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
4953 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
4954 CHECK(result->Get(v8::Integer::New(3))->IsNull());
4955 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
4959 THREADED_TEST(CatchZero) {
4960 LocalContext context;
4961 v8::HandleScope scope(context->GetIsolate());
4962 v8::TryCatch try_catch;
4963 CHECK(!try_catch.HasCaught());
4964 Script::Compile(v8_str("throw 10"))->Run();
4965 CHECK(try_catch.HasCaught());
4966 CHECK_EQ(10, try_catch.Exception()->Int32Value());
4968 CHECK(!try_catch.HasCaught());
4969 Script::Compile(v8_str("throw 0"))->Run();
4970 CHECK(try_catch.HasCaught());
4971 CHECK_EQ(0, try_catch.Exception()->Int32Value());
4975 THREADED_TEST(CatchExceptionFromWith) {
4976 LocalContext context;
4977 v8::HandleScope scope(context->GetIsolate());
4978 v8::TryCatch try_catch;
4979 CHECK(!try_catch.HasCaught());
4980 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
4981 CHECK(try_catch.HasCaught());
4985 THREADED_TEST(TryCatchAndFinallyHidingException) {
4986 LocalContext context;
4987 v8::HandleScope scope(context->GetIsolate());
4988 v8::TryCatch try_catch;
4989 CHECK(!try_catch.HasCaught());
4990 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4991 CompileRun("f({toString: function() { throw 42; }});");
4992 CHECK(!try_catch.HasCaught());
4996 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
4997 v8::TryCatch try_catch;
5001 THREADED_TEST(TryCatchAndFinally) {
5002 LocalContext context;
5003 v8::HandleScope scope(context->GetIsolate());
5004 context->Global()->Set(
5005 v8_str("native_with_try_catch"),
5006 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
5007 v8::TryCatch try_catch;
5008 CHECK(!try_catch.HasCaught());
5011 " throw new Error('a');\n"
5013 " native_with_try_catch();\n"
5015 CHECK(try_catch.HasCaught());
5019 static void TryCatchNestedHelper(int depth) {
5021 v8::TryCatch try_catch;
5022 try_catch.SetVerbose(true);
5023 TryCatchNestedHelper(depth - 1);
5024 CHECK(try_catch.HasCaught());
5025 try_catch.ReThrow();
5027 CcTest::isolate()->ThrowException(v8_str("back"));
5032 TEST(TryCatchNested) {
5033 v8::V8::Initialize();
5034 LocalContext context;
5035 v8::HandleScope scope(context->GetIsolate());
5036 v8::TryCatch try_catch;
5037 TryCatchNestedHelper(5);
5038 CHECK(try_catch.HasCaught());
5039 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5043 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5044 CHECK(try_catch->HasCaught());
5045 Handle<Message> message = try_catch->Message();
5046 Handle<Value> resource = message->GetScriptResourceName();
5047 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5048 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5049 "Uncaught Error: a"));
5050 CHECK_EQ(1, message->GetLineNumber());
5051 CHECK_EQ(6, message->GetStartColumn());
5055 void TryCatchMixedNestingHelper(
5056 const v8::FunctionCallbackInfo<v8::Value>& args) {
5057 ApiTestFuzzer::Fuzz();
5058 v8::TryCatch try_catch;
5059 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5060 CHECK(try_catch.HasCaught());
5061 TryCatchMixedNestingCheck(&try_catch);
5062 try_catch.ReThrow();
5066 // This test ensures that an outer TryCatch in the following situation:
5067 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5068 // does not clobber the Message object generated for the inner TryCatch.
5069 // This exercises the ability of TryCatch.ReThrow() to restore the
5070 // inner pending Message before throwing the exception again.
5071 TEST(TryCatchMixedNesting) {
5072 v8::HandleScope scope(CcTest::isolate());
5073 v8::V8::Initialize();
5074 v8::TryCatch try_catch;
5075 Local<ObjectTemplate> templ = ObjectTemplate::New();
5076 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5077 v8::FunctionTemplate::New(TryCatchMixedNestingHelper));
5078 LocalContext context(0, templ);
5079 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5080 TryCatchMixedNestingCheck(&try_catch);
5084 THREADED_TEST(Equality) {
5085 LocalContext context;
5086 v8::Isolate* isolate = context->GetIsolate();
5087 v8::HandleScope scope(context->GetIsolate());
5088 // Check that equality works at all before relying on CHECK_EQ
5089 CHECK(v8_str("a")->Equals(v8_str("a")));
5090 CHECK(!v8_str("a")->Equals(v8_str("b")));
5092 CHECK_EQ(v8_str("a"), v8_str("a"));
5093 CHECK_NE(v8_str("a"), v8_str("b"));
5094 CHECK_EQ(v8_num(1), v8_num(1));
5095 CHECK_EQ(v8_num(1.00), v8_num(1));
5096 CHECK_NE(v8_num(1), v8_num(2));
5098 // Assume String is not internalized.
5099 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5100 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5101 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5102 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5103 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5104 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5105 Local<Value> not_a_number = v8_num(i::OS::nan_value());
5106 CHECK(!not_a_number->StrictEquals(not_a_number));
5107 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5108 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5110 v8::Handle<v8::Object> obj = v8::Object::New();
5111 v8::Persistent<v8::Object> alias(isolate, obj);
5112 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5115 CHECK(v8_str("a")->SameValue(v8_str("a")));
5116 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5117 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5118 CHECK(v8_num(1)->SameValue(v8_num(1)));
5119 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5120 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5121 CHECK(not_a_number->SameValue(not_a_number));
5122 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5123 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5127 THREADED_TEST(MultiRun) {
5128 LocalContext context;
5129 v8::HandleScope scope(context->GetIsolate());
5130 Local<Script> script = Script::Compile(v8_str("x"));
5131 for (int i = 0; i < 10; i++)
5136 static void GetXValue(Local<String> name,
5137 const v8::PropertyCallbackInfo<v8::Value>& info) {
5138 ApiTestFuzzer::Fuzz();
5139 CHECK_EQ(info.Data(), v8_str("donut"));
5140 CHECK_EQ(name, v8_str("x"));
5141 info.GetReturnValue().Set(name);
5145 THREADED_TEST(SimplePropertyRead) {
5146 LocalContext context;
5147 v8::HandleScope scope(context->GetIsolate());
5148 Local<ObjectTemplate> templ = ObjectTemplate::New();
5149 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5150 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5151 Local<Script> script = Script::Compile(v8_str("obj.x"));
5152 for (int i = 0; i < 10; i++) {
5153 Local<Value> result = script->Run();
5154 CHECK_EQ(result, v8_str("x"));
5159 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5160 LocalContext context;
5161 v8::HandleScope scope(context->GetIsolate());
5162 Local<ObjectTemplate> templ = ObjectTemplate::New();
5163 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5164 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5166 // Uses getOwnPropertyDescriptor to check the configurable status
5167 Local<Script> script_desc
5168 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5170 "prop.configurable;"));
5171 Local<Value> result = script_desc->Run();
5172 CHECK_EQ(result->BooleanValue(), true);
5174 // Redefine get - but still configurable
5175 Local<Script> script_define
5176 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5177 " configurable: true };"
5178 "Object.defineProperty(obj, 'x', desc);"
5180 result = script_define->Run();
5181 CHECK_EQ(result, v8_num(42));
5183 // Check that the accessor is still configurable
5184 result = script_desc->Run();
5185 CHECK_EQ(result->BooleanValue(), true);
5187 // Redefine to a non-configurable
5189 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5190 " configurable: false };"
5191 "Object.defineProperty(obj, 'x', desc);"
5193 result = script_define->Run();
5194 CHECK_EQ(result, v8_num(43));
5195 result = script_desc->Run();
5196 CHECK_EQ(result->BooleanValue(), false);
5198 // Make sure that it is not possible to redefine again
5199 v8::TryCatch try_catch;
5200 result = script_define->Run();
5201 CHECK(try_catch.HasCaught());
5202 String::Utf8Value exception_value(try_catch.Exception());
5203 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5207 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5208 v8::HandleScope scope(CcTest::isolate());
5209 Local<ObjectTemplate> templ = ObjectTemplate::New();
5210 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5211 LocalContext context;
5212 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5214 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5215 "Object.getOwnPropertyDescriptor( "
5217 "prop.configurable;"));
5218 Local<Value> result = script_desc->Run();
5219 CHECK_EQ(result->BooleanValue(), true);
5221 Local<Script> script_define =
5222 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5223 " configurable: true };"
5224 "Object.defineProperty(obj, 'x', desc);"
5226 result = script_define->Run();
5227 CHECK_EQ(result, v8_num(42));
5230 result = script_desc->Run();
5231 CHECK_EQ(result->BooleanValue(), true);
5235 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5236 " configurable: false };"
5237 "Object.defineProperty(obj, 'x', desc);"
5239 result = script_define->Run();
5240 CHECK_EQ(result, v8_num(43));
5241 result = script_desc->Run();
5243 CHECK_EQ(result->BooleanValue(), false);
5245 v8::TryCatch try_catch;
5246 result = script_define->Run();
5247 CHECK(try_catch.HasCaught());
5248 String::Utf8Value exception_value(try_catch.Exception());
5249 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5253 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5255 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5259 THREADED_TEST(DefineAPIAccessorOnObject) {
5260 v8::HandleScope scope(CcTest::isolate());
5261 Local<ObjectTemplate> templ = ObjectTemplate::New();
5262 LocalContext context;
5264 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5265 CompileRun("var obj2 = {};");
5267 CHECK(CompileRun("obj1.x")->IsUndefined());
5268 CHECK(CompileRun("obj2.x")->IsUndefined());
5270 CHECK(GetGlobalProperty(&context, "obj1")->
5271 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5273 ExpectString("obj1.x", "x");
5274 CHECK(CompileRun("obj2.x")->IsUndefined());
5276 CHECK(GetGlobalProperty(&context, "obj2")->
5277 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5279 ExpectString("obj1.x", "x");
5280 ExpectString("obj2.x", "x");
5282 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5283 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5285 CompileRun("Object.defineProperty(obj1, 'x',"
5286 "{ get: function() { return 'y'; }, configurable: true })");
5288 ExpectString("obj1.x", "y");
5289 ExpectString("obj2.x", "x");
5291 CompileRun("Object.defineProperty(obj2, 'x',"
5292 "{ get: function() { return 'y'; }, configurable: true })");
5294 ExpectString("obj1.x", "y");
5295 ExpectString("obj2.x", "y");
5297 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5298 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5300 CHECK(GetGlobalProperty(&context, "obj1")->
5301 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5302 CHECK(GetGlobalProperty(&context, "obj2")->
5303 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5305 ExpectString("obj1.x", "x");
5306 ExpectString("obj2.x", "x");
5308 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5309 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5311 // Define getters/setters, but now make them not configurable.
5312 CompileRun("Object.defineProperty(obj1, 'x',"
5313 "{ get: function() { return 'z'; }, configurable: false })");
5314 CompileRun("Object.defineProperty(obj2, 'x',"
5315 "{ get: function() { return 'z'; }, configurable: false })");
5317 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5318 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5320 ExpectString("obj1.x", "z");
5321 ExpectString("obj2.x", "z");
5323 CHECK(!GetGlobalProperty(&context, "obj1")->
5324 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5325 CHECK(!GetGlobalProperty(&context, "obj2")->
5326 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5328 ExpectString("obj1.x", "z");
5329 ExpectString("obj2.x", "z");
5333 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5334 v8::HandleScope scope(CcTest::isolate());
5335 Local<ObjectTemplate> templ = ObjectTemplate::New();
5336 LocalContext context;
5338 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5339 CompileRun("var obj2 = {};");
5341 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5344 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5345 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5348 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5350 ExpectString("obj1.x", "x");
5351 ExpectString("obj2.x", "x");
5353 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5354 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5356 CHECK(!GetGlobalProperty(&context, "obj1")->
5357 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5358 CHECK(!GetGlobalProperty(&context, "obj2")->
5359 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5362 v8::TryCatch try_catch;
5363 CompileRun("Object.defineProperty(obj1, 'x',"
5364 "{get: function() { return 'func'; }})");
5365 CHECK(try_catch.HasCaught());
5366 String::Utf8Value exception_value(try_catch.Exception());
5367 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5370 v8::TryCatch try_catch;
5371 CompileRun("Object.defineProperty(obj2, 'x',"
5372 "{get: function() { return 'func'; }})");
5373 CHECK(try_catch.HasCaught());
5374 String::Utf8Value exception_value(try_catch.Exception());
5375 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5380 static void Get239Value(Local<String> name,
5381 const v8::PropertyCallbackInfo<v8::Value>& info) {
5382 ApiTestFuzzer::Fuzz();
5383 CHECK_EQ(info.Data(), v8_str("donut"));
5384 CHECK_EQ(name, v8_str("239"));
5385 info.GetReturnValue().Set(name);
5389 THREADED_TEST(ElementAPIAccessor) {
5390 v8::HandleScope scope(CcTest::isolate());
5391 Local<ObjectTemplate> templ = ObjectTemplate::New();
5392 LocalContext context;
5394 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5395 CompileRun("var obj2 = {};");
5397 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5401 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5406 ExpectString("obj1[239]", "239");
5407 ExpectString("obj2[239]", "239");
5408 ExpectString("obj1['239']", "239");
5409 ExpectString("obj2['239']", "239");
5413 v8::Persistent<Value> xValue;
5416 static void SetXValue(Local<String> name,
5418 const v8::PropertyCallbackInfo<void>& info) {
5419 CHECK_EQ(value, v8_num(4));
5420 CHECK_EQ(info.Data(), v8_str("donut"));
5421 CHECK_EQ(name, v8_str("x"));
5422 CHECK(xValue.IsEmpty());
5423 xValue.Reset(info.GetIsolate(), value);
5427 THREADED_TEST(SimplePropertyWrite) {
5428 v8::HandleScope scope(CcTest::isolate());
5429 Local<ObjectTemplate> templ = ObjectTemplate::New();
5430 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5431 LocalContext context;
5432 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5433 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5434 for (int i = 0; i < 10; i++) {
5435 CHECK(xValue.IsEmpty());
5437 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5444 THREADED_TEST(SetterOnly) {
5445 v8::HandleScope scope(CcTest::isolate());
5446 Local<ObjectTemplate> templ = ObjectTemplate::New();
5447 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5448 LocalContext context;
5449 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5450 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5451 for (int i = 0; i < 10; i++) {
5452 CHECK(xValue.IsEmpty());
5454 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5461 THREADED_TEST(NoAccessors) {
5462 v8::HandleScope scope(CcTest::isolate());
5463 Local<ObjectTemplate> templ = ObjectTemplate::New();
5464 templ->SetAccessor(v8_str("x"),
5465 static_cast<v8::AccessorGetterCallback>(NULL),
5468 LocalContext context;
5469 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5470 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5471 for (int i = 0; i < 10; i++) {
5477 static void XPropertyGetter(Local<String> property,
5478 const v8::PropertyCallbackInfo<v8::Value>& info) {
5479 ApiTestFuzzer::Fuzz();
5480 CHECK(info.Data()->IsUndefined());
5481 info.GetReturnValue().Set(property);
5485 THREADED_TEST(NamedInterceptorPropertyRead) {
5486 v8::HandleScope scope(CcTest::isolate());
5487 Local<ObjectTemplate> templ = ObjectTemplate::New();
5488 templ->SetNamedPropertyHandler(XPropertyGetter);
5489 LocalContext context;
5490 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5491 Local<Script> script = Script::Compile(v8_str("obj.x"));
5492 for (int i = 0; i < 10; i++) {
5493 Local<Value> result = script->Run();
5494 CHECK_EQ(result, v8_str("x"));
5499 THREADED_TEST(NamedInterceptorDictionaryIC) {
5500 v8::HandleScope scope(CcTest::isolate());
5501 Local<ObjectTemplate> templ = ObjectTemplate::New();
5502 templ->SetNamedPropertyHandler(XPropertyGetter);
5503 LocalContext context;
5504 // Create an object with a named interceptor.
5505 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5506 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5507 for (int i = 0; i < 10; i++) {
5508 Local<Value> result = script->Run();
5509 CHECK_EQ(result, v8_str("x"));
5511 // Create a slow case object and a function accessing a property in
5512 // that slow case object (with dictionary probing in generated
5513 // code). Then force object with a named interceptor into slow-case,
5514 // pass it to the function, and check that the interceptor is called
5515 // instead of accessing the local property.
5516 Local<Value> result =
5517 CompileRun("function get_x(o) { return o.x; };"
5518 "var obj = { x : 42, y : 0 };"
5520 "for (var i = 0; i < 10; i++) get_x(obj);"
5521 "interceptor_obj.x = 42;"
5522 "interceptor_obj.y = 10;"
5523 "delete interceptor_obj.y;"
5524 "get_x(interceptor_obj)");
5525 CHECK_EQ(result, v8_str("x"));
5529 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5530 v8::Isolate* isolate = CcTest::isolate();
5531 v8::HandleScope scope(isolate);
5532 v8::Local<Context> context1 = Context::New(isolate);
5535 Local<ObjectTemplate> templ = ObjectTemplate::New();
5536 templ->SetNamedPropertyHandler(XPropertyGetter);
5537 // Create an object with a named interceptor.
5538 v8::Local<v8::Object> object = templ->NewInstance();
5539 context1->Global()->Set(v8_str("interceptor_obj"), object);
5541 // Force the object into the slow case.
5542 CompileRun("interceptor_obj.y = 0;"
5543 "delete interceptor_obj.y;");
5547 // Introduce the object into a different context.
5548 // Repeat named loads to exercise ICs.
5549 LocalContext context2;
5550 context2->Global()->Set(v8_str("interceptor_obj"), object);
5551 Local<Value> result =
5552 CompileRun("function get_x(o) { return o.x; }"
5553 "interceptor_obj.x = 42;"
5554 "for (var i=0; i != 10; i++) {"
5555 " get_x(interceptor_obj);"
5557 "get_x(interceptor_obj)");
5558 // Check that the interceptor was actually invoked.
5559 CHECK_EQ(result, v8_str("x"));
5562 // Return to the original context and force some object to the slow case
5563 // to cause the NormalizedMapCache to verify.
5565 CompileRun("var obj = { x : 0 }; delete obj.x;");
5570 static void SetXOnPrototypeGetter(
5571 Local<String> property,
5572 const v8::PropertyCallbackInfo<v8::Value>& info) {
5573 // Set x on the prototype object and do not handle the get request.
5574 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5575 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
5579 // This is a regression test for http://crbug.com/20104. Map
5580 // transitions should not interfere with post interceptor lookup.
5581 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5582 v8::HandleScope scope(CcTest::isolate());
5583 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
5584 Local<v8::ObjectTemplate> instance_template
5585 = function_template->InstanceTemplate();
5586 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5587 LocalContext context;
5588 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5589 // Create an instance of F and introduce a map transition for x.
5590 CompileRun("var o = new F(); o.x = 23;");
5591 // Create an instance of F and invoke the getter. The result should be 23.
5592 Local<Value> result = CompileRun("o = new F(); o.x");
5593 CHECK_EQ(result->Int32Value(), 23);
5597 static void IndexedPropertyGetter(
5599 const v8::PropertyCallbackInfo<v8::Value>& info) {
5600 ApiTestFuzzer::Fuzz();
5602 info.GetReturnValue().Set(v8_num(625));
5607 static void IndexedPropertySetter(
5610 const v8::PropertyCallbackInfo<v8::Value>& info) {
5611 ApiTestFuzzer::Fuzz();
5613 info.GetReturnValue().Set(value);
5618 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5619 v8::HandleScope scope(CcTest::isolate());
5620 Local<ObjectTemplate> templ = ObjectTemplate::New();
5621 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5622 IndexedPropertySetter);
5623 LocalContext context;
5624 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5625 Local<Script> getter_script = Script::Compile(v8_str(
5626 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5627 Local<Script> setter_script = Script::Compile(v8_str(
5628 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5631 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5632 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5634 "obj.foo;")); // This setter should not run, due to the interceptor.
5635 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5637 Local<Value> result = getter_script->Run();
5638 CHECK_EQ(v8_num(5), result);
5639 result = setter_script->Run();
5640 CHECK_EQ(v8_num(23), result);
5641 result = interceptor_setter_script->Run();
5642 CHECK_EQ(v8_num(23), result);
5643 result = interceptor_getter_script->Run();
5644 CHECK_EQ(v8_num(625), result);
5648 static void UnboxedDoubleIndexedPropertyGetter(
5650 const v8::PropertyCallbackInfo<v8::Value>& info) {
5651 ApiTestFuzzer::Fuzz();
5653 info.GetReturnValue().Set(v8_num(index));
5658 static void UnboxedDoubleIndexedPropertySetter(
5661 const v8::PropertyCallbackInfo<v8::Value>& info) {
5662 ApiTestFuzzer::Fuzz();
5664 info.GetReturnValue().Set(v8_num(index));
5669 void UnboxedDoubleIndexedPropertyEnumerator(
5670 const v8::PropertyCallbackInfo<v8::Array>& info) {
5671 // Force the list of returned keys to be stored in a FastDoubleArray.
5672 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5673 "keys = new Array(); keys[125000] = 1;"
5674 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5675 "keys.length = 25; keys;"));
5676 Local<Value> result = indexed_property_names_script->Run();
5677 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5681 // Make sure that the the interceptor code in the runtime properly handles
5682 // merging property name lists for double-array-backed arrays.
5683 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5684 v8::HandleScope scope(CcTest::isolate());
5685 Local<ObjectTemplate> templ = ObjectTemplate::New();
5686 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5687 UnboxedDoubleIndexedPropertySetter,
5690 UnboxedDoubleIndexedPropertyEnumerator);
5691 LocalContext context;
5692 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5693 // When obj is created, force it to be Stored in a FastDoubleArray.
5694 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5695 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5697 "for (x in obj) {key_count++;};"
5699 Local<Value> result = create_unboxed_double_script->Run();
5700 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5701 Local<Script> key_count_check = Script::Compile(v8_str(
5703 result = key_count_check->Run();
5704 CHECK_EQ(v8_num(40013), result);
5708 void NonStrictArgsIndexedPropertyEnumerator(
5709 const v8::PropertyCallbackInfo<v8::Array>& info) {
5710 // Force the list of returned keys to be stored in a Arguments object.
5711 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5713 " return arguments;"
5715 "keys = f(0, 1, 2, 3);"
5717 Local<Object> result =
5718 Local<Object>::Cast(indexed_property_names_script->Run());
5719 // Have to populate the handle manually, as it's not Cast-able.
5720 i::Handle<i::JSObject> o =
5721 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5722 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5723 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5727 static void NonStrictIndexedPropertyGetter(
5729 const v8::PropertyCallbackInfo<v8::Value>& info) {
5730 ApiTestFuzzer::Fuzz();
5732 info.GetReturnValue().Set(v8_num(index));
5737 // Make sure that the the interceptor code in the runtime properly handles
5738 // merging property name lists for non-string arguments arrays.
5739 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5740 v8::HandleScope scope(CcTest::isolate());
5741 Local<ObjectTemplate> templ = ObjectTemplate::New();
5742 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5746 NonStrictArgsIndexedPropertyEnumerator);
5747 LocalContext context;
5748 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5749 Local<Script> create_args_script =
5750 Script::Compile(v8_str(
5751 "var key_count = 0;"
5752 "for (x in obj) {key_count++;} key_count;"));
5753 Local<Value> result = create_args_script->Run();
5754 CHECK_EQ(v8_num(4), result);
5758 static void IdentityIndexedPropertyGetter(
5760 const v8::PropertyCallbackInfo<v8::Value>& info) {
5761 info.GetReturnValue().Set(index);
5765 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
5766 v8::HandleScope scope(CcTest::isolate());
5767 Local<ObjectTemplate> templ = ObjectTemplate::New();
5768 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5770 LocalContext context;
5771 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5773 // Check fast object case.
5774 const char* fast_case_code =
5775 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
5776 ExpectString(fast_case_code, "0");
5779 const char* slow_case_code =
5780 "obj.x = 1; delete obj.x;"
5781 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
5782 ExpectString(slow_case_code, "1");
5786 THREADED_TEST(IndexedInterceptorWithNoSetter) {
5787 v8::HandleScope scope(CcTest::isolate());
5788 Local<ObjectTemplate> templ = ObjectTemplate::New();
5789 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5791 LocalContext context;
5792 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5797 " for (var i = 0; i < 100; i++) {"
5799 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
5805 ExpectString(code, "PASSED");
5809 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
5810 v8::HandleScope scope(CcTest::isolate());
5811 Local<ObjectTemplate> templ = ObjectTemplate::New();
5812 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5814 LocalContext context;
5815 Local<v8::Object> obj = templ->NewInstance();
5816 obj->TurnOnAccessCheck();
5817 context->Global()->Set(v8_str("obj"), obj);
5821 " for (var i = 0; i < 100; i++) {"
5823 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
5829 ExpectString(code, "PASSED");
5833 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
5834 i::FLAG_allow_natives_syntax = true;
5835 v8::HandleScope scope(CcTest::isolate());
5836 Local<ObjectTemplate> templ = ObjectTemplate::New();
5837 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5839 LocalContext context;
5840 Local<v8::Object> obj = templ->NewInstance();
5841 context->Global()->Set(v8_str("obj"), obj);
5845 " for (var i = 0; i < 100; i++) {"
5846 " var expected = i;"
5848 " %EnableAccessChecks(obj);"
5849 " expected = undefined;"
5852 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5853 " if (i == 5) %DisableAccessChecks(obj);"
5859 ExpectString(code, "PASSED");
5863 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
5864 v8::HandleScope scope(CcTest::isolate());
5865 Local<ObjectTemplate> templ = ObjectTemplate::New();
5866 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5868 LocalContext context;
5869 Local<v8::Object> obj = templ->NewInstance();
5870 context->Global()->Set(v8_str("obj"), obj);
5874 " for (var i = 0; i < 100; i++) {"
5876 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5882 ExpectString(code, "PASSED");
5886 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
5887 v8::HandleScope scope(CcTest::isolate());
5888 Local<ObjectTemplate> templ = ObjectTemplate::New();
5889 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5891 LocalContext context;
5892 Local<v8::Object> obj = templ->NewInstance();
5893 context->Global()->Set(v8_str("obj"), obj);
5897 " for (var i = 0; i < 100; i++) {"
5898 " var expected = i;"
5902 " expected = undefined;"
5905 " /* probe minimal Smi number on 32-bit platforms */"
5906 " key = -(1 << 30);"
5907 " expected = undefined;"
5910 " /* probe minimal Smi number on 64-bit platforms */"
5912 " expected = undefined;"
5914 " var v = obj[key];"
5915 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5921 ExpectString(code, "PASSED");
5925 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
5926 v8::HandleScope scope(CcTest::isolate());
5927 Local<ObjectTemplate> templ = ObjectTemplate::New();
5928 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5930 LocalContext context;
5931 Local<v8::Object> obj = templ->NewInstance();
5932 context->Global()->Set(v8_str("obj"), obj);
5936 " for (var i = 0; i < 100; i++) {"
5937 " var expected = i;"
5941 " expected = undefined;"
5943 " var v = obj[key];"
5944 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5950 ExpectString(code, "PASSED");
5954 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
5955 v8::HandleScope scope(CcTest::isolate());
5956 Local<ObjectTemplate> templ = ObjectTemplate::New();
5957 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5959 LocalContext context;
5960 Local<v8::Object> obj = templ->NewInstance();
5961 context->Global()->Set(v8_str("obj"), obj);
5964 "var original = obj;"
5966 " for (var i = 0; i < 100; i++) {"
5967 " var expected = i;"
5969 " obj = {50: 'foobar'};"
5970 " expected = 'foobar';"
5973 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5974 " if (i == 50) obj = original;"
5980 ExpectString(code, "PASSED");
5984 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
5985 v8::HandleScope scope(CcTest::isolate());
5986 Local<ObjectTemplate> templ = ObjectTemplate::New();
5987 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5989 LocalContext context;
5990 Local<v8::Object> obj = templ->NewInstance();
5991 context->Global()->Set(v8_str("obj"), obj);
5994 "var original = obj;"
5996 " for (var i = 0; i < 100; i++) {"
5997 " var expected = i;"
6000 " expected = undefined;"
6003 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6004 " if (i == 5) obj = original;"
6010 ExpectString(code, "PASSED");
6014 THREADED_TEST(IndexedInterceptorOnProto) {
6015 v8::HandleScope scope(CcTest::isolate());
6016 Local<ObjectTemplate> templ = ObjectTemplate::New();
6017 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6019 LocalContext context;
6020 Local<v8::Object> obj = templ->NewInstance();
6021 context->Global()->Set(v8_str("obj"), obj);
6024 "var o = {__proto__: obj};"
6026 " for (var i = 0; i < 100; i++) {"
6028 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6034 ExpectString(code, "PASSED");
6038 THREADED_TEST(MultiContexts) {
6039 v8::HandleScope scope(CcTest::isolate());
6040 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
6041 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
6043 Local<String> password = v8_str("Password");
6045 // Create an environment
6046 LocalContext context0(0, templ);
6047 context0->SetSecurityToken(password);
6048 v8::Handle<v8::Object> global0 = context0->Global();
6049 global0->Set(v8_str("custom"), v8_num(1234));
6050 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6052 // Create an independent environment
6053 LocalContext context1(0, templ);
6054 context1->SetSecurityToken(password);
6055 v8::Handle<v8::Object> global1 = context1->Global();
6056 global1->Set(v8_str("custom"), v8_num(1234));
6057 CHECK_NE(global0, global1);
6058 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6059 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6061 // Now create a new context with the old global
6062 LocalContext context2(0, templ, global1);
6063 context2->SetSecurityToken(password);
6064 v8::Handle<v8::Object> global2 = context2->Global();
6065 CHECK_EQ(global1, global2);
6066 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6067 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6071 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6072 // Make sure that functions created by cloning boilerplates cannot
6073 // communicate through their __proto__ field.
6075 v8::HandleScope scope(CcTest::isolate());
6078 v8::Handle<v8::Object> global0 =
6080 v8::Handle<v8::Object> object0 =
6081 global0->Get(v8_str("Object")).As<v8::Object>();
6082 v8::Handle<v8::Object> tostring0 =
6083 object0->Get(v8_str("toString")).As<v8::Object>();
6084 v8::Handle<v8::Object> proto0 =
6085 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6086 proto0->Set(v8_str("custom"), v8_num(1234));
6089 v8::Handle<v8::Object> global1 =
6091 v8::Handle<v8::Object> object1 =
6092 global1->Get(v8_str("Object")).As<v8::Object>();
6093 v8::Handle<v8::Object> tostring1 =
6094 object1->Get(v8_str("toString")).As<v8::Object>();
6095 v8::Handle<v8::Object> proto1 =
6096 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6097 CHECK(!proto1->Has(v8_str("custom")));
6101 THREADED_TEST(Regress892105) {
6102 // Make sure that object and array literals created by cloning
6103 // boilerplates cannot communicate through their __proto__
6104 // field. This is rather difficult to check, but we try to add stuff
6105 // to Object.prototype and Array.prototype and create a new
6106 // environment. This should succeed.
6108 v8::HandleScope scope(CcTest::isolate());
6110 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6111 "Array.prototype.arr = 4567;"
6115 Local<Script> script0 = Script::Compile(source);
6116 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6119 Local<Script> script1 = Script::Compile(source);
6120 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6124 THREADED_TEST(UndetectableObject) {
6126 v8::HandleScope scope(env->GetIsolate());
6128 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6129 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6131 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6132 env->Global()->Set(v8_str("undetectable"), obj);
6134 ExpectString("undetectable.toString()", "[object Object]");
6135 ExpectString("typeof undetectable", "undefined");
6136 ExpectString("typeof(undetectable)", "undefined");
6137 ExpectBoolean("typeof undetectable == 'undefined'", true);
6138 ExpectBoolean("typeof undetectable == 'object'", false);
6139 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6140 ExpectBoolean("!undetectable", true);
6142 ExpectObject("true&&undetectable", obj);
6143 ExpectBoolean("false&&undetectable", false);
6144 ExpectBoolean("true||undetectable", true);
6145 ExpectObject("false||undetectable", obj);
6147 ExpectObject("undetectable&&true", obj);
6148 ExpectObject("undetectable&&false", obj);
6149 ExpectBoolean("undetectable||true", true);
6150 ExpectBoolean("undetectable||false", false);
6152 ExpectBoolean("undetectable==null", true);
6153 ExpectBoolean("null==undetectable", true);
6154 ExpectBoolean("undetectable==undefined", true);
6155 ExpectBoolean("undefined==undetectable", true);
6156 ExpectBoolean("undetectable==undetectable", true);
6159 ExpectBoolean("undetectable===null", false);
6160 ExpectBoolean("null===undetectable", false);
6161 ExpectBoolean("undetectable===undefined", false);
6162 ExpectBoolean("undefined===undetectable", false);
6163 ExpectBoolean("undetectable===undetectable", true);
6167 THREADED_TEST(VoidLiteral) {
6169 v8::HandleScope scope(env->GetIsolate());
6171 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6172 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6174 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6175 env->Global()->Set(v8_str("undetectable"), obj);
6177 ExpectBoolean("undefined == void 0", true);
6178 ExpectBoolean("undetectable == void 0", true);
6179 ExpectBoolean("null == void 0", true);
6180 ExpectBoolean("undefined === void 0", true);
6181 ExpectBoolean("undetectable === void 0", false);
6182 ExpectBoolean("null === void 0", false);
6184 ExpectBoolean("void 0 == undefined", true);
6185 ExpectBoolean("void 0 == undetectable", true);
6186 ExpectBoolean("void 0 == null", true);
6187 ExpectBoolean("void 0 === undefined", true);
6188 ExpectBoolean("void 0 === undetectable", false);
6189 ExpectBoolean("void 0 === null", false);
6191 ExpectString("(function() {"
6193 " return x === void 0;"
6195 " return e.toString();"
6198 "ReferenceError: x is not defined");
6199 ExpectString("(function() {"
6201 " return void 0 === x;"
6203 " return e.toString();"
6206 "ReferenceError: x is not defined");
6210 THREADED_TEST(ExtensibleOnUndetectable) {
6212 v8::HandleScope scope(env->GetIsolate());
6214 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6215 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6217 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6218 env->Global()->Set(v8_str("undetectable"), obj);
6220 Local<String> source = v8_str("undetectable.x = 42;"
6223 Local<Script> script = Script::Compile(source);
6225 CHECK_EQ(v8::Integer::New(42), script->Run());
6227 ExpectBoolean("Object.isExtensible(undetectable)", true);
6229 source = v8_str("Object.preventExtensions(undetectable);");
6230 script = Script::Compile(source);
6232 ExpectBoolean("Object.isExtensible(undetectable)", false);
6234 source = v8_str("undetectable.y = 2000;");
6235 script = Script::Compile(source);
6237 ExpectBoolean("undetectable.y == undefined", true);
6242 THREADED_TEST(UndetectableString) {
6244 v8::HandleScope scope(env->GetIsolate());
6246 Local<String> obj = String::NewUndetectable("foo");
6247 env->Global()->Set(v8_str("undetectable"), obj);
6249 ExpectString("undetectable", "foo");
6250 ExpectString("typeof undetectable", "undefined");
6251 ExpectString("typeof(undetectable)", "undefined");
6252 ExpectBoolean("typeof undetectable == 'undefined'", true);
6253 ExpectBoolean("typeof undetectable == 'string'", false);
6254 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6255 ExpectBoolean("!undetectable", true);
6257 ExpectObject("true&&undetectable", obj);
6258 ExpectBoolean("false&&undetectable", false);
6259 ExpectBoolean("true||undetectable", true);
6260 ExpectObject("false||undetectable", obj);
6262 ExpectObject("undetectable&&true", obj);
6263 ExpectObject("undetectable&&false", obj);
6264 ExpectBoolean("undetectable||true", true);
6265 ExpectBoolean("undetectable||false", false);
6267 ExpectBoolean("undetectable==null", true);
6268 ExpectBoolean("null==undetectable", true);
6269 ExpectBoolean("undetectable==undefined", true);
6270 ExpectBoolean("undefined==undetectable", true);
6271 ExpectBoolean("undetectable==undetectable", true);
6274 ExpectBoolean("undetectable===null", false);
6275 ExpectBoolean("null===undetectable", false);
6276 ExpectBoolean("undetectable===undefined", false);
6277 ExpectBoolean("undefined===undetectable", false);
6278 ExpectBoolean("undetectable===undetectable", true);
6282 TEST(UndetectableOptimized) {
6283 i::FLAG_allow_natives_syntax = true;
6285 v8::HandleScope scope(env->GetIsolate());
6287 Local<String> obj = String::NewUndetectable("foo");
6288 env->Global()->Set(v8_str("undetectable"), obj);
6289 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6292 "function testBranch() {"
6293 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6294 " if (%_IsUndetectableObject(detectable)) throw 2;"
6296 "function testBool() {"
6297 " var b1 = !%_IsUndetectableObject(undetectable);"
6298 " var b2 = %_IsUndetectableObject(detectable);"
6303 "%OptimizeFunctionOnNextCall(testBranch);"
6304 "%OptimizeFunctionOnNextCall(testBool);"
6305 "for (var i = 0; i < 10; i++) {"
6314 template <typename T> static void USE(T) { }
6317 // This test is not intended to be run, just type checked.
6318 static inline void PersistentHandles(v8::Isolate* isolate) {
6319 USE(PersistentHandles);
6320 Local<String> str = v8_str("foo");
6321 v8::Persistent<String> p_str(isolate, str);
6323 Local<Script> scr = Script::Compile(v8_str(""));
6324 v8::Persistent<Script> p_scr(isolate, scr);
6326 Local<ObjectTemplate> templ = ObjectTemplate::New();
6327 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6332 static void HandleLogDelegator(
6333 const v8::FunctionCallbackInfo<v8::Value>& args) {
6334 ApiTestFuzzer::Fuzz();
6338 THREADED_TEST(GlobalObjectTemplate) {
6339 v8::Isolate* isolate = CcTest::isolate();
6340 v8::HandleScope handle_scope(isolate);
6341 Local<ObjectTemplate> global_template = ObjectTemplate::New();
6342 global_template->Set(v8_str("JSNI_Log"),
6343 v8::FunctionTemplate::New(HandleLogDelegator));
6344 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6345 Context::Scope context_scope(context);
6346 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6350 static const char* kSimpleExtensionSource =
6356 THREADED_TEST(SimpleExtensions) {
6357 v8::HandleScope handle_scope(CcTest::isolate());
6358 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6359 const char* extension_names[] = { "simpletest" };
6360 v8::ExtensionConfiguration extensions(1, extension_names);
6361 v8::Handle<Context> context =
6362 Context::New(CcTest::isolate(), &extensions);
6363 Context::Scope lock(context);
6364 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6365 CHECK_EQ(result, v8::Integer::New(4));
6369 THREADED_TEST(NullExtensions) {
6370 v8::HandleScope handle_scope(CcTest::isolate());
6371 v8::RegisterExtension(new Extension("nulltest", NULL));
6372 const char* extension_names[] = { "nulltest" };
6373 v8::ExtensionConfiguration extensions(1, extension_names);
6374 v8::Handle<Context> context =
6375 Context::New(CcTest::isolate(), &extensions);
6376 Context::Scope lock(context);
6377 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6378 CHECK_EQ(result, v8::Integer::New(4));
6382 static const char* kEmbeddedExtensionSource =
6383 "function Ret54321(){return 54321;}~~@@$"
6384 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6385 static const int kEmbeddedExtensionSourceValidLen = 34;
6388 THREADED_TEST(ExtensionMissingSourceLength) {
6389 v8::HandleScope handle_scope(CcTest::isolate());
6390 v8::RegisterExtension(new Extension("srclentest_fail",
6391 kEmbeddedExtensionSource));
6392 const char* extension_names[] = { "srclentest_fail" };
6393 v8::ExtensionConfiguration extensions(1, extension_names);
6394 v8::Handle<Context> context =
6395 Context::New(CcTest::isolate(), &extensions);
6396 CHECK_EQ(0, *context);
6400 THREADED_TEST(ExtensionWithSourceLength) {
6401 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6402 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6403 v8::HandleScope handle_scope(CcTest::isolate());
6404 i::ScopedVector<char> extension_name(32);
6405 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6406 v8::RegisterExtension(new Extension(extension_name.start(),
6407 kEmbeddedExtensionSource, 0, 0,
6409 const char* extension_names[1] = { extension_name.start() };
6410 v8::ExtensionConfiguration extensions(1, extension_names);
6411 v8::Handle<Context> context =
6412 Context::New(CcTest::isolate(), &extensions);
6413 if (source_len == kEmbeddedExtensionSourceValidLen) {
6414 Context::Scope lock(context);
6415 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6416 CHECK_EQ(v8::Integer::New(54321), result);
6418 // Anything but exactly the right length should fail to compile.
6419 CHECK_EQ(0, *context);
6425 static const char* kEvalExtensionSource1 =
6426 "function UseEval1() {"
6428 " return eval('x');"
6432 static const char* kEvalExtensionSource2 =
6436 " return eval('x');"
6438 " this.UseEval2 = e;"
6442 THREADED_TEST(UseEvalFromExtension) {
6443 v8::HandleScope handle_scope(CcTest::isolate());
6444 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6445 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6446 const char* extension_names[] = { "evaltest1", "evaltest2" };
6447 v8::ExtensionConfiguration extensions(2, extension_names);
6448 v8::Handle<Context> context =
6449 Context::New(CcTest::isolate(), &extensions);
6450 Context::Scope lock(context);
6451 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6452 CHECK_EQ(result, v8::Integer::New(42));
6453 result = Script::Compile(v8_str("UseEval2()"))->Run();
6454 CHECK_EQ(result, v8::Integer::New(42));
6458 static const char* kWithExtensionSource1 =
6459 "function UseWith1() {"
6461 " with({x:87}) { return x; }"
6466 static const char* kWithExtensionSource2 =
6470 " with ({x:87}) { return x; }"
6472 " this.UseWith2 = e;"
6476 THREADED_TEST(UseWithFromExtension) {
6477 v8::HandleScope handle_scope(CcTest::isolate());
6478 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6479 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6480 const char* extension_names[] = { "withtest1", "withtest2" };
6481 v8::ExtensionConfiguration extensions(2, extension_names);
6482 v8::Handle<Context> context =
6483 Context::New(CcTest::isolate(), &extensions);
6484 Context::Scope lock(context);
6485 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6486 CHECK_EQ(result, v8::Integer::New(87));
6487 result = Script::Compile(v8_str("UseWith2()"))->Run();
6488 CHECK_EQ(result, v8::Integer::New(87));
6492 THREADED_TEST(AutoExtensions) {
6493 v8::HandleScope handle_scope(CcTest::isolate());
6494 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6495 extension->set_auto_enable(true);
6496 v8::RegisterExtension(extension);
6497 v8::Handle<Context> context =
6498 Context::New(CcTest::isolate());
6499 Context::Scope lock(context);
6500 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6501 CHECK_EQ(result, v8::Integer::New(4));
6505 static const char* kSyntaxErrorInExtensionSource =
6509 // Test that a syntax error in an extension does not cause a fatal
6510 // error but results in an empty context.
6511 THREADED_TEST(SyntaxErrorExtensions) {
6512 v8::HandleScope handle_scope(CcTest::isolate());
6513 v8::RegisterExtension(new Extension("syntaxerror",
6514 kSyntaxErrorInExtensionSource));
6515 const char* extension_names[] = { "syntaxerror" };
6516 v8::ExtensionConfiguration extensions(1, extension_names);
6517 v8::Handle<Context> context =
6518 Context::New(CcTest::isolate(), &extensions);
6519 CHECK(context.IsEmpty());
6523 static const char* kExceptionInExtensionSource =
6527 // Test that an exception when installing an extension does not cause
6528 // a fatal error but results in an empty context.
6529 THREADED_TEST(ExceptionExtensions) {
6530 v8::HandleScope handle_scope(CcTest::isolate());
6531 v8::RegisterExtension(new Extension("exception",
6532 kExceptionInExtensionSource));
6533 const char* extension_names[] = { "exception" };
6534 v8::ExtensionConfiguration extensions(1, extension_names);
6535 v8::Handle<Context> context =
6536 Context::New(CcTest::isolate(), &extensions);
6537 CHECK(context.IsEmpty());
6541 static const char* kNativeCallInExtensionSource =
6542 "function call_runtime_last_index_of(x) {"
6543 " return %StringLastIndexOf(x, 'bob', 10);"
6547 static const char* kNativeCallTest =
6548 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6550 // Test that a native runtime calls are supported in extensions.
6551 THREADED_TEST(NativeCallInExtensions) {
6552 v8::HandleScope handle_scope(CcTest::isolate());
6553 v8::RegisterExtension(new Extension("nativecall",
6554 kNativeCallInExtensionSource));
6555 const char* extension_names[] = { "nativecall" };
6556 v8::ExtensionConfiguration extensions(1, extension_names);
6557 v8::Handle<Context> context =
6558 Context::New(CcTest::isolate(), &extensions);
6559 Context::Scope lock(context);
6560 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6561 CHECK_EQ(result, v8::Integer::New(3));
6565 class NativeFunctionExtension : public Extension {
6567 NativeFunctionExtension(const char* name,
6569 v8::FunctionCallback fun = &Echo)
6570 : Extension(name, source),
6573 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6574 v8::Handle<v8::String> name) {
6575 return v8::FunctionTemplate::New(function_);
6578 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6579 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6582 v8::FunctionCallback function_;
6586 THREADED_TEST(NativeFunctionDeclaration) {
6587 v8::HandleScope handle_scope(CcTest::isolate());
6588 const char* name = "nativedecl";
6589 v8::RegisterExtension(new NativeFunctionExtension(name,
6590 "native function foo();"));
6591 const char* extension_names[] = { name };
6592 v8::ExtensionConfiguration extensions(1, extension_names);
6593 v8::Handle<Context> context =
6594 Context::New(CcTest::isolate(), &extensions);
6595 Context::Scope lock(context);
6596 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6597 CHECK_EQ(result, v8::Integer::New(42));
6601 THREADED_TEST(NativeFunctionDeclarationError) {
6602 v8::HandleScope handle_scope(CcTest::isolate());
6603 const char* name = "nativedeclerr";
6604 // Syntax error in extension code.
6605 v8::RegisterExtension(new NativeFunctionExtension(name,
6606 "native\nfunction foo();"));
6607 const char* extension_names[] = { name };
6608 v8::ExtensionConfiguration extensions(1, extension_names);
6609 v8::Handle<Context> context =
6610 Context::New(CcTest::isolate(), &extensions);
6611 CHECK(context.IsEmpty());
6615 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6616 v8::HandleScope handle_scope(CcTest::isolate());
6617 const char* name = "nativedeclerresc";
6618 // Syntax error in extension code - escape code in "native" means that
6619 // it's not treated as a keyword.
6620 v8::RegisterExtension(new NativeFunctionExtension(
6622 "nativ\\u0065 function foo();"));
6623 const char* extension_names[] = { name };
6624 v8::ExtensionConfiguration extensions(1, extension_names);
6625 v8::Handle<Context> context =
6626 Context::New(CcTest::isolate(), &extensions);
6627 CHECK(context.IsEmpty());
6631 static void CheckDependencies(const char* name, const char* expected) {
6632 v8::HandleScope handle_scope(CcTest::isolate());
6633 v8::ExtensionConfiguration config(1, &name);
6634 LocalContext context(&config);
6635 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
6646 THREADED_TEST(ExtensionDependency) {
6647 static const char* kEDeps[] = { "D" };
6648 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6649 static const char* kDDeps[] = { "B", "C" };
6650 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6651 static const char* kBCDeps[] = { "A" };
6652 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6653 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6654 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6655 CheckDependencies("A", "undefinedA");
6656 CheckDependencies("B", "undefinedAB");
6657 CheckDependencies("C", "undefinedAC");
6658 CheckDependencies("D", "undefinedABCD");
6659 CheckDependencies("E", "undefinedABCDE");
6660 v8::HandleScope handle_scope(CcTest::isolate());
6661 static const char* exts[2] = { "C", "E" };
6662 v8::ExtensionConfiguration config(2, exts);
6663 LocalContext context(&config);
6664 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6668 static const char* kExtensionTestScript =
6669 "native function A();"
6670 "native function B();"
6671 "native function C();"
6673 " if (i == 0) return A();"
6674 " if (i == 1) return B();"
6675 " if (i == 2) return C();"
6679 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6680 ApiTestFuzzer::Fuzz();
6681 if (args.IsConstructCall()) {
6682 args.This()->Set(v8_str("data"), args.Data());
6683 args.GetReturnValue().SetNull();
6686 args.GetReturnValue().Set(args.Data());
6690 class FunctionExtension : public Extension {
6692 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6693 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6694 v8::Handle<String> name);
6698 static int lookup_count = 0;
6699 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
6700 v8::Handle<String> name) {
6702 if (name->Equals(v8_str("A"))) {
6703 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
6704 } else if (name->Equals(v8_str("B"))) {
6705 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
6706 } else if (name->Equals(v8_str("C"))) {
6707 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
6709 return v8::Handle<v8::FunctionTemplate>();
6714 THREADED_TEST(FunctionLookup) {
6715 v8::RegisterExtension(new FunctionExtension());
6716 v8::HandleScope handle_scope(CcTest::isolate());
6717 static const char* exts[1] = { "functiontest" };
6718 v8::ExtensionConfiguration config(1, exts);
6719 LocalContext context(&config);
6720 CHECK_EQ(3, lookup_count);
6721 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
6722 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
6723 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
6727 THREADED_TEST(NativeFunctionConstructCall) {
6728 v8::RegisterExtension(new FunctionExtension());
6729 v8::HandleScope handle_scope(CcTest::isolate());
6730 static const char* exts[1] = { "functiontest" };
6731 v8::ExtensionConfiguration config(1, exts);
6732 LocalContext context(&config);
6733 for (int i = 0; i < 10; i++) {
6734 // Run a few times to ensure that allocation of objects doesn't
6735 // change behavior of a constructor function.
6736 CHECK_EQ(v8::Integer::New(8),
6737 Script::Compile(v8_str("(new A()).data"))->Run());
6738 CHECK_EQ(v8::Integer::New(7),
6739 Script::Compile(v8_str("(new B()).data"))->Run());
6740 CHECK_EQ(v8::Integer::New(6),
6741 Script::Compile(v8_str("(new C()).data"))->Run());
6746 static const char* last_location;
6747 static const char* last_message;
6748 void StoringErrorCallback(const char* location, const char* message) {
6749 if (last_location == NULL) {
6750 last_location = location;
6751 last_message = message;
6756 // ErrorReporting creates a circular extensions configuration and
6757 // tests that the fatal error handler gets called. This renders V8
6758 // unusable and therefore this test cannot be run in parallel.
6759 TEST(ErrorReporting) {
6760 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6761 static const char* aDeps[] = { "B" };
6762 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6763 static const char* bDeps[] = { "A" };
6764 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6765 last_location = NULL;
6766 v8::ExtensionConfiguration config(1, bDeps);
6767 v8::Handle<Context> context =
6768 Context::New(CcTest::isolate(), &config);
6769 CHECK(context.IsEmpty());
6770 CHECK_NE(last_location, NULL);
6774 static const char* js_code_causing_huge_string_flattening =
6776 "for (var i = 0; i < 30; i++) {"
6782 void OOMCallback(const char* location, const char* message) {
6787 TEST(RegexpOutOfMemory) {
6788 // Execute a script that causes out of memory when flattening a string.
6789 v8::HandleScope scope(CcTest::isolate());
6790 v8::V8::SetFatalErrorHandler(OOMCallback);
6791 LocalContext context;
6792 Local<Script> script =
6793 Script::Compile(String::New(js_code_causing_huge_string_flattening));
6794 last_location = NULL;
6797 CHECK(false); // Should not return.
6801 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6802 v8::Handle<Value> data) {
6803 CHECK(message->GetScriptResourceName()->IsUndefined());
6804 CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
6805 message->GetLineNumber();
6806 message->GetSourceLine();
6810 THREADED_TEST(ErrorWithMissingScriptInfo) {
6811 LocalContext context;
6812 v8::HandleScope scope(context->GetIsolate());
6813 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6814 Script::Compile(v8_str("throw Error()"))->Run();
6815 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6819 int global_index = 0;
6823 Snorkel() { index_ = global_index++; }
6829 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
6830 ~Whammy() { script_.Dispose(); }
6831 v8::Handle<Script> getScript() {
6832 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
6833 return Local<Script>::New(isolate_, script_);
6837 static const int kObjectCount = 256;
6839 v8::Isolate* isolate_;
6840 v8::Persistent<v8::Object> objects_[kObjectCount];
6841 v8::Persistent<Script> script_;
6844 static void HandleWeakReference(v8::Isolate* isolate,
6845 v8::Persistent<v8::Value>* obj,
6851 void WhammyPropertyGetter(Local<String> name,
6852 const v8::PropertyCallbackInfo<v8::Value>& info) {
6854 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
6856 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
6858 v8::Handle<v8::Object> obj = v8::Object::New();
6859 if (!prev.IsEmpty()) {
6860 v8::Local<v8::Object>::New(info.GetIsolate(), prev)
6861 ->Set(v8_str("next"), obj);
6862 prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference);
6863 whammy->objects_[whammy->cursor_].Clear();
6865 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
6866 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
6867 info.GetReturnValue().Set(whammy->getScript()->Run());
6871 THREADED_TEST(WeakReference) {
6872 v8::HandleScope handle_scope(CcTest::isolate());
6873 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
6874 Whammy* whammy = new Whammy(CcTest::isolate());
6875 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
6877 v8::External::New(whammy));
6878 const char* extension_list[] = { "v8/gc" };
6879 v8::ExtensionConfiguration extensions(1, extension_list);
6880 v8::Handle<Context> context =
6881 Context::New(CcTest::isolate(), &extensions);
6882 Context::Scope context_scope(context);
6884 v8::Handle<v8::Object> interceptor = templ->NewInstance();
6885 context->Global()->Set(v8_str("whammy"), interceptor);
6888 "for (var i = 0; i < 10000; i++) {"
6889 " var obj = whammy.length;"
6890 " if (last) last.next = obj;"
6895 v8::Handle<Value> result = CompileRun(code);
6896 CHECK_EQ(4.0, result->NumberValue());
6901 static void DisposeAndSetFlag(v8::Isolate* isolate,
6902 v8::Persistent<v8::Object>* obj,
6909 THREADED_TEST(IndependentWeakHandle) {
6910 v8::Isolate* iso = CcTest::isolate();
6911 v8::HandleScope scope(iso);
6912 v8::Handle<Context> context = Context::New(iso);
6913 Context::Scope context_scope(context);
6915 v8::Persistent<v8::Object> object_a, object_b;
6918 v8::HandleScope handle_scope(iso);
6919 object_a.Reset(iso, v8::Object::New());
6920 object_b.Reset(iso, v8::Object::New());
6923 bool object_a_disposed = false;
6924 bool object_b_disposed = false;
6925 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
6926 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
6927 CHECK(!object_b.IsIndependent());
6928 object_a.MarkIndependent();
6929 object_b.MarkIndependent();
6930 CHECK(object_b.IsIndependent());
6931 CcTest::heap()->PerformScavenge();
6932 CHECK(object_a_disposed);
6933 CHECK(object_b_disposed);
6937 static void InvokeScavenge() {
6938 CcTest::heap()->PerformScavenge();
6942 static void InvokeMarkSweep() {
6943 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6947 static void ForceScavenge(v8::Isolate* isolate,
6948 v8::Persistent<v8::Object>* obj,
6956 static void ForceMarkSweep(v8::Isolate* isolate,
6957 v8::Persistent<v8::Object>* obj,
6965 THREADED_TEST(GCFromWeakCallbacks) {
6966 v8::Isolate* isolate = CcTest::isolate();
6967 v8::HandleScope scope(isolate);
6968 v8::Handle<Context> context = Context::New(isolate);
6969 Context::Scope context_scope(context);
6971 static const int kNumberOfGCTypes = 2;
6972 typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback;
6973 Callback gc_forcing_callback[kNumberOfGCTypes] =
6974 {&ForceScavenge, &ForceMarkSweep};
6976 typedef void (*GCInvoker)();
6977 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6979 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6980 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6981 v8::Persistent<v8::Object> object;
6983 v8::HandleScope handle_scope(isolate);
6984 object.Reset(isolate, v8::Object::New());
6986 bool disposed = false;
6987 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
6988 object.MarkIndependent();
6989 invoke_gc[outer_gc]();
6996 static void RevivingCallback(v8::Isolate* isolate,
6997 v8::Persistent<v8::Object>* obj,
7004 THREADED_TEST(IndependentHandleRevival) {
7005 v8::Isolate* isolate = CcTest::isolate();
7006 v8::HandleScope scope(isolate);
7007 v8::Handle<Context> context = Context::New(isolate);
7008 Context::Scope context_scope(context);
7010 v8::Persistent<v8::Object> object;
7012 v8::HandleScope handle_scope(isolate);
7013 v8::Local<v8::Object> o = v8::Object::New();
7014 object.Reset(isolate, o);
7015 o->Set(v8_str("x"), v8::Integer::New(1));
7016 v8::Local<String> y_str = v8_str("y");
7017 o->Set(y_str, y_str);
7019 bool revived = false;
7020 object.MakeWeak(&revived, &RevivingCallback);
7021 object.MarkIndependent();
7022 CcTest::heap()->PerformScavenge();
7024 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7026 v8::HandleScope handle_scope(isolate);
7027 v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object);
7028 v8::Local<String> y_str = v8_str("y");
7029 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x")));
7030 CHECK(o->Get(y_str)->Equals(y_str));
7035 v8::Handle<Function> args_fun;
7038 static void ArgumentsTestCallback(
7039 const v8::FunctionCallbackInfo<v8::Value>& args) {
7040 ApiTestFuzzer::Fuzz();
7041 v8::Isolate* isolate = args.GetIsolate();
7042 CHECK_EQ(args_fun, args.Callee());
7043 CHECK_EQ(3, args.Length());
7044 CHECK_EQ(v8::Integer::New(1, isolate), args[0]);
7045 CHECK_EQ(v8::Integer::New(2, isolate), args[1]);
7046 CHECK_EQ(v8::Integer::New(3, isolate), args[2]);
7047 CHECK_EQ(v8::Undefined(isolate), args[3]);
7048 v8::HandleScope scope(args.GetIsolate());
7049 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7053 THREADED_TEST(Arguments) {
7054 v8::HandleScope scope(CcTest::isolate());
7055 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
7056 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
7057 LocalContext context(NULL, global);
7058 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7059 v8_compile("f(1, 2, 3)")->Run();
7063 static void NoBlockGetterX(Local<String> name,
7064 const v8::PropertyCallbackInfo<v8::Value>&) {
7068 static void NoBlockGetterI(uint32_t index,
7069 const v8::PropertyCallbackInfo<v8::Value>&) {
7073 static void PDeleter(Local<String> name,
7074 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7075 if (!name->Equals(v8_str("foo"))) {
7076 return; // not intercepted
7079 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7083 static void IDeleter(uint32_t index,
7084 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7086 return; // not intercepted
7089 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7093 THREADED_TEST(Deleter) {
7094 v8::HandleScope scope(CcTest::isolate());
7095 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7096 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7097 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7098 LocalContext context;
7099 context->Global()->Set(v8_str("k"), obj->NewInstance());
7105 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7106 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7108 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7109 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7111 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7112 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7114 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7115 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7119 static void GetK(Local<String> name,
7120 const v8::PropertyCallbackInfo<v8::Value>& info) {
7121 ApiTestFuzzer::Fuzz();
7122 if (name->Equals(v8_str("foo")) ||
7123 name->Equals(v8_str("bar")) ||
7124 name->Equals(v8_str("baz"))) {
7125 info.GetReturnValue().SetUndefined();
7130 static void IndexedGetK(uint32_t index,
7131 const v8::PropertyCallbackInfo<v8::Value>& info) {
7132 ApiTestFuzzer::Fuzz();
7133 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7137 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7138 ApiTestFuzzer::Fuzz();
7139 v8::Handle<v8::Array> result = v8::Array::New(3);
7140 result->Set(v8::Integer::New(0), v8_str("foo"));
7141 result->Set(v8::Integer::New(1), v8_str("bar"));
7142 result->Set(v8::Integer::New(2), v8_str("baz"));
7143 info.GetReturnValue().Set(result);
7147 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7148 ApiTestFuzzer::Fuzz();
7149 v8::Handle<v8::Array> result = v8::Array::New(2);
7150 result->Set(v8::Integer::New(0), v8_str("0"));
7151 result->Set(v8::Integer::New(1), v8_str("1"));
7152 info.GetReturnValue().Set(result);
7156 THREADED_TEST(Enumerators) {
7157 v8::HandleScope scope(CcTest::isolate());
7158 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7159 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7160 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7161 LocalContext context;
7162 context->Global()->Set(v8_str("k"), obj->NewInstance());
7163 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7168 "k[4294967295] = 0;"
7170 "k[4294967296] = 0;"
7174 "k[30000000000] = 0;"
7177 "for (var prop in k) {"
7178 " result.push(prop);"
7181 // Check that we get all the property names returned including the
7182 // ones from the enumerators in the right order: indexed properties
7183 // in numerical order, indexed interceptor properties, named
7184 // properties in insertion order, named interceptor properties.
7185 // This order is not mandated by the spec, so this test is just
7186 // documenting our behavior.
7187 CHECK_EQ(17, result->Length());
7188 // Indexed properties in numerical order.
7189 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
7190 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
7191 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
7192 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
7193 // Indexed interceptor properties in the order they are returned
7194 // from the enumerator interceptor.
7195 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
7196 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
7197 // Named properties in insertion order.
7198 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
7199 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
7200 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
7201 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
7202 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
7203 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
7204 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
7205 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
7206 // Named interceptor properties.
7207 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
7208 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
7209 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
7214 int p_getter_count2;
7217 static void PGetter(Local<String> name,
7218 const v8::PropertyCallbackInfo<v8::Value>& info) {
7219 ApiTestFuzzer::Fuzz();
7221 v8::Handle<v8::Object> global =
7222 info.GetIsolate()->GetCurrentContext()->Global();
7223 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7224 if (name->Equals(v8_str("p1"))) {
7225 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7226 } else if (name->Equals(v8_str("p2"))) {
7227 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7228 } else if (name->Equals(v8_str("p3"))) {
7229 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7230 } else if (name->Equals(v8_str("p4"))) {
7231 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7236 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7237 ApiTestFuzzer::Fuzz();
7238 LocalContext context;
7239 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7241 "o1.__proto__ = { };"
7242 "var o2 = { __proto__: o1 };"
7243 "var o3 = { __proto__: o2 };"
7244 "var o4 = { __proto__: o3 };"
7245 "for (var i = 0; i < 10; i++) o4.p4;"
7246 "for (var i = 0; i < 10; i++) o3.p3;"
7247 "for (var i = 0; i < 10; i++) o2.p2;"
7248 "for (var i = 0; i < 10; i++) o1.p1;");
7252 static void PGetter2(Local<String> name,
7253 const v8::PropertyCallbackInfo<v8::Value>& info) {
7254 ApiTestFuzzer::Fuzz();
7256 v8::Handle<v8::Object> global =
7257 info.GetIsolate()->GetCurrentContext()->Global();
7258 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7259 if (name->Equals(v8_str("p1"))) {
7260 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7261 } else if (name->Equals(v8_str("p2"))) {
7262 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7263 } else if (name->Equals(v8_str("p3"))) {
7264 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7265 } else if (name->Equals(v8_str("p4"))) {
7266 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7271 THREADED_TEST(GetterHolders) {
7272 v8::HandleScope scope(CcTest::isolate());
7273 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7274 obj->SetAccessor(v8_str("p1"), PGetter);
7275 obj->SetAccessor(v8_str("p2"), PGetter);
7276 obj->SetAccessor(v8_str("p3"), PGetter);
7277 obj->SetAccessor(v8_str("p4"), PGetter);
7280 CHECK_EQ(40, p_getter_count);
7284 THREADED_TEST(PreInterceptorHolders) {
7285 v8::HandleScope scope(CcTest::isolate());
7286 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7287 obj->SetNamedPropertyHandler(PGetter2);
7288 p_getter_count2 = 0;
7290 CHECK_EQ(40, p_getter_count2);
7294 THREADED_TEST(ObjectInstantiation) {
7295 v8::Isolate* isolate = CcTest::isolate();
7296 v8::HandleScope scope(isolate);
7297 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7298 templ->SetAccessor(v8_str("t"), PGetter2);
7299 LocalContext context;
7300 context->Global()->Set(v8_str("o"), templ->NewInstance());
7301 for (int i = 0; i < 100; i++) {
7302 v8::HandleScope inner_scope(CcTest::isolate());
7303 v8::Handle<v8::Object> obj = templ->NewInstance();
7304 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7305 context->Global()->Set(v8_str("o2"), obj);
7306 v8::Handle<Value> value =
7307 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7308 CHECK_EQ(v8::True(isolate), value);
7309 context->Global()->Set(v8_str("o"), obj);
7314 static int StrCmp16(uint16_t* a, uint16_t* b) {
7316 if (*a == 0 && *b == 0) return 0;
7317 if (*a != *b) return 0 + *a - *b;
7324 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7326 if (n-- == 0) return 0;
7327 if (*a == 0 && *b == 0) return 0;
7328 if (*a != *b) return 0 + *a - *b;
7335 int GetUtf8Length(Handle<String> str) {
7336 int len = str->Utf8Length();
7338 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7339 i::FlattenString(istr);
7340 len = str->Utf8Length();
7346 THREADED_TEST(StringWrite) {
7347 LocalContext context;
7348 v8::HandleScope scope(context->GetIsolate());
7349 v8::Handle<String> str = v8_str("abcde");
7350 // abc<Icelandic eth><Unicode snowman>.
7351 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7352 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
7353 const int kStride = 4; // Must match stride in for loops in JS below.
7356 "for (var i = 0; i < 0xd800; i += 4) {"
7357 " left = left + String.fromCharCode(i);"
7361 "for (var i = 0; i < 0xd800; i += 4) {"
7362 " right = String.fromCharCode(i) + right;"
7364 v8::Handle<v8::Object> global = context->Global();
7365 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7366 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7368 CHECK_EQ(5, str2->Length());
7369 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7370 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7373 char utf8buf[0xd800 * 3];
7378 memset(utf8buf, 0x1, 1000);
7379 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7381 CHECK_EQ(5, charlen);
7382 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7384 memset(utf8buf, 0x1, 1000);
7385 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7387 CHECK_EQ(5, charlen);
7388 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7390 memset(utf8buf, 0x1, 1000);
7391 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7393 CHECK_EQ(4, charlen);
7394 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7396 memset(utf8buf, 0x1, 1000);
7397 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7399 CHECK_EQ(4, charlen);
7400 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7402 memset(utf8buf, 0x1, 1000);
7403 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7405 CHECK_EQ(4, charlen);
7406 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7408 memset(utf8buf, 0x1, 1000);
7409 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7411 CHECK_EQ(3, charlen);
7412 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7414 memset(utf8buf, 0x1, 1000);
7415 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7417 CHECK_EQ(3, charlen);
7418 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7420 memset(utf8buf, 0x1, 1000);
7421 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7423 CHECK_EQ(2, charlen);
7424 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7426 memset(utf8buf, 0x1, sizeof(utf8buf));
7427 len = GetUtf8Length(left_tree);
7429 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7430 CHECK_EQ(utf8_expected, len);
7431 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7432 CHECK_EQ(utf8_expected, len);
7433 CHECK_EQ(0xd800 / kStride, charlen);
7434 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7435 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7436 CHECK_EQ(0xc0 - kStride,
7437 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7438 CHECK_EQ(1, utf8buf[utf8_expected]);
7440 memset(utf8buf, 0x1, sizeof(utf8buf));
7441 len = GetUtf8Length(right_tree);
7442 CHECK_EQ(utf8_expected, len);
7443 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7444 CHECK_EQ(utf8_expected, len);
7445 CHECK_EQ(0xd800 / kStride, charlen);
7446 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7447 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7448 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7449 CHECK_EQ(1, utf8buf[utf8_expected]);
7451 memset(buf, 0x1, sizeof(buf));
7452 memset(wbuf, 0x1, sizeof(wbuf));
7453 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7455 len = str->Write(wbuf);
7457 CHECK_EQ(0, strcmp("abcde", buf));
7458 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7459 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7461 memset(buf, 0x1, sizeof(buf));
7462 memset(wbuf, 0x1, sizeof(wbuf));
7463 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7465 len = str->Write(wbuf, 0, 4);
7467 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7468 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7469 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7471 memset(buf, 0x1, sizeof(buf));
7472 memset(wbuf, 0x1, sizeof(wbuf));
7473 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7475 len = str->Write(wbuf, 0, 5);
7477 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7478 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7479 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7481 memset(buf, 0x1, sizeof(buf));
7482 memset(wbuf, 0x1, sizeof(wbuf));
7483 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7485 len = str->Write(wbuf, 0, 6);
7487 CHECK_EQ(0, strcmp("abcde", buf));
7488 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7489 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7491 memset(buf, 0x1, sizeof(buf));
7492 memset(wbuf, 0x1, sizeof(wbuf));
7493 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7495 len = str->Write(wbuf, 4, -1);
7497 CHECK_EQ(0, strcmp("e", buf));
7498 uint16_t answer5[] = {'e', '\0'};
7499 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7501 memset(buf, 0x1, sizeof(buf));
7502 memset(wbuf, 0x1, sizeof(wbuf));
7503 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7505 len = str->Write(wbuf, 4, 6);
7507 CHECK_EQ(0, strcmp("e", buf));
7508 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7510 memset(buf, 0x1, sizeof(buf));
7511 memset(wbuf, 0x1, sizeof(wbuf));
7512 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7514 len = str->Write(wbuf, 4, 1);
7516 CHECK_EQ(0, strncmp("e\1", buf, 2));
7517 uint16_t answer6[] = {'e', 0x101};
7518 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7520 memset(buf, 0x1, sizeof(buf));
7521 memset(wbuf, 0x1, sizeof(wbuf));
7522 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7524 len = str->Write(wbuf, 3, 1);
7526 CHECK_EQ(0, strncmp("d\1", buf, 2));
7527 uint16_t answer7[] = {'d', 0x101};
7528 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7530 memset(wbuf, 0x1, sizeof(wbuf));
7532 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7534 CHECK_EQ('X', wbuf[5]);
7535 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7536 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7537 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7538 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7540 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7542 memset(buf, 0x1, sizeof(buf));
7544 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7547 String::NO_NULL_TERMINATION);
7549 CHECK_EQ('X', buf[5]);
7550 CHECK_EQ(0, strncmp("abcde", buf, 5));
7551 CHECK_NE(0, strcmp("abcde", buf));
7553 CHECK_EQ(0, strcmp("abcde", buf));
7555 memset(utf8buf, 0x1, sizeof(utf8buf));
7557 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7558 String::NO_NULL_TERMINATION);
7560 CHECK_EQ('X', utf8buf[8]);
7561 CHECK_EQ(5, charlen);
7562 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7563 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7565 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7567 memset(utf8buf, 0x1, sizeof(utf8buf));
7569 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7570 String::NO_NULL_TERMINATION);
7572 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7573 CHECK_EQ(5, charlen);
7575 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7577 memset(buf, 0x1, sizeof(buf));
7578 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7580 CHECK_EQ(0, strcmp("abc", buf));
7581 CHECK_EQ(0, buf[3]);
7582 CHECK_EQ(0, strcmp("def", buf + 4));
7584 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7585 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7586 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7590 static void Utf16Helper(
7591 LocalContext& context,
7593 const char* lengths_name,
7595 Local<v8::Array> a =
7596 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7597 Local<v8::Array> alens =
7598 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7599 for (int i = 0; i < len; i++) {
7600 Local<v8::String> string =
7601 Local<v8::String>::Cast(a->Get(i));
7602 Local<v8::Number> expected_len =
7603 Local<v8::Number>::Cast(alens->Get(i));
7604 int length = GetUtf8Length(string);
7605 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7610 static uint16_t StringGet(Handle<String> str, int index) {
7611 i::Handle<i::String> istring =
7612 v8::Utils::OpenHandle(String::Cast(*str));
7613 return istring->Get(index);
7617 static void WriteUtf8Helper(
7618 LocalContext& context,
7620 const char* lengths_name,
7622 Local<v8::Array> b =
7623 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7624 Local<v8::Array> alens =
7625 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7628 for (int i = 0; i < len; i++) {
7629 Local<v8::String> string =
7630 Local<v8::String>::Cast(b->Get(i));
7631 Local<v8::Number> expected_len =
7632 Local<v8::Number>::Cast(alens->Get(i));
7633 int utf8_length = static_cast<int>(expected_len->Value());
7634 for (int j = utf8_length + 1; j >= 0; j--) {
7635 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7636 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7639 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7641 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7642 CHECK_GE(utf8_length + 1, utf8_written);
7643 CHECK_GE(utf8_length, utf8_written2);
7644 for (int k = 0; k < utf8_written2; k++) {
7645 CHECK_EQ(buffer[k], buffer2[k]);
7647 CHECK(nchars * 3 >= utf8_written - 1);
7648 CHECK(nchars <= utf8_written);
7649 if (j == utf8_length + 1) {
7650 CHECK_EQ(utf8_written2, utf8_length);
7651 CHECK_EQ(utf8_written2 + 1, utf8_written);
7653 CHECK_EQ(buffer[utf8_written], 42);
7654 if (j > utf8_length) {
7655 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7656 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7657 Handle<String> roundtrip = v8_str(buffer);
7658 CHECK(roundtrip->Equals(string));
7660 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7662 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7664 uint16_t trail = StringGet(string, nchars - 1);
7665 uint16_t lead = StringGet(string, nchars - 2);
7666 if (((lead & 0xfc00) == 0xd800) &&
7667 ((trail & 0xfc00) == 0xdc00)) {
7668 unsigned char u1 = buffer2[utf8_written2 - 4];
7669 unsigned char u2 = buffer2[utf8_written2 - 3];
7670 unsigned char u3 = buffer2[utf8_written2 - 2];
7671 unsigned char u4 = buffer2[utf8_written2 - 1];
7672 CHECK_EQ((u1 & 0xf8), 0xf0);
7673 CHECK_EQ((u2 & 0xc0), 0x80);
7674 CHECK_EQ((u3 & 0xc0), 0x80);
7675 CHECK_EQ((u4 & 0xc0), 0x80);
7676 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7677 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7678 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7679 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7680 CHECK_EQ((u1 & 0x3), c >> 18);
7688 THREADED_TEST(Utf16) {
7689 LocalContext context;
7690 v8::HandleScope scope(context->GetIsolate());
7692 "var pad = '01234567890123456789';"
7694 "var plens = [20, 3, 3];"
7695 "p.push('01234567890123456789');"
7696 "var lead = 0xd800;"
7697 "var trail = 0xdc00;"
7698 "p.push(String.fromCharCode(0xd800));"
7699 "p.push(String.fromCharCode(0xdc00));"
7704 "for (var i = 0; i < 3; i++) {"
7705 " p[1] = String.fromCharCode(lead++);"
7706 " for (var j = 0; j < 3; j++) {"
7707 " p[2] = String.fromCharCode(trail++);"
7708 " a.push(p[i] + p[j]);"
7709 " b.push(p[i] + p[j]);"
7710 " c.push(p[i] + p[j]);"
7711 " alens.push(plens[i] + plens[j]);"
7714 "alens[5] -= 2;" // Here the surrogate pairs match up.
7719 "for (var m = 0; m < 9; m++) {"
7720 " for (var n = 0; n < 9; n++) {"
7721 " a2.push(a[m] + a[n]);"
7722 " b2.push(b[m] + b[n]);"
7723 " var newc = 'x' + c[m] + c[n] + 'y';"
7724 " c2.push(newc.substring(1, newc.length - 1));"
7725 " var utf = alens[m] + alens[n];" // And here.
7726 // The 'n's that start with 0xdc.. are 6-8
7727 // The 'm's that end with 0xd8.. are 1, 4 and 7
7728 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7729 " a2lens.push(utf);"
7732 Utf16Helper(context, "a", "alens", 9);
7733 Utf16Helper(context, "a2", "a2lens", 81);
7734 WriteUtf8Helper(context, "b", "alens", 9);
7735 WriteUtf8Helper(context, "b2", "a2lens", 81);
7736 WriteUtf8Helper(context, "c2", "a2lens", 81);
7740 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7741 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7742 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7743 return *is1 == *is2;
7747 static void SameSymbolHelper(const char* a, const char* b) {
7748 Handle<String> symbol1 = v8::String::NewSymbol(a);
7749 Handle<String> symbol2 = v8::String::NewSymbol(b);
7750 CHECK(SameSymbol(symbol1, symbol2));
7754 THREADED_TEST(Utf16Symbol) {
7755 LocalContext context;
7756 v8::HandleScope scope(context->GetIsolate());
7758 Handle<String> symbol1 = v8::String::NewSymbol("abc");
7759 Handle<String> symbol2 = v8::String::NewSymbol("abc");
7760 CHECK(SameSymbol(symbol1, symbol2));
7762 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
7763 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
7764 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
7765 "\360\220\220\206"); // 4 byte encoding.
7766 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
7767 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
7768 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
7769 "x\360\220\220\206"); // 4 byte encoding.
7771 "var sym0 = 'benedictus';"
7772 "var sym0b = 'S\303\270ren';"
7773 "var sym1 = '\355\240\201\355\260\207';"
7774 "var sym2 = '\360\220\220\210';"
7775 "var sym3 = 'x\355\240\201\355\260\207';"
7776 "var sym4 = 'x\360\220\220\210';"
7777 "if (sym1.length != 2) throw sym1;"
7778 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7779 "if (sym2.length != 2) throw sym2;"
7780 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7781 "if (sym3.length != 3) throw sym3;"
7782 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7783 "if (sym4.length != 3) throw sym4;"
7784 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7785 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
7786 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
7787 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
7788 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
7789 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
7790 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
7791 v8::Local<v8::Object> global = context->Global();
7792 Local<Value> s0 = global->Get(v8_str("sym0"));
7793 Local<Value> s0b = global->Get(v8_str("sym0b"));
7794 Local<Value> s1 = global->Get(v8_str("sym1"));
7795 Local<Value> s2 = global->Get(v8_str("sym2"));
7796 Local<Value> s3 = global->Get(v8_str("sym3"));
7797 Local<Value> s4 = global->Get(v8_str("sym4"));
7798 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7799 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7800 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7801 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7802 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7803 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7807 THREADED_TEST(ToArrayIndex) {
7808 LocalContext context;
7809 v8::HandleScope scope(context->GetIsolate());
7811 v8::Handle<String> str = v8_str("42");
7812 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7813 CHECK(!index.IsEmpty());
7814 CHECK_EQ(42.0, index->Uint32Value());
7815 str = v8_str("42asdf");
7816 index = str->ToArrayIndex();
7817 CHECK(index.IsEmpty());
7818 str = v8_str("-42");
7819 index = str->ToArrayIndex();
7820 CHECK(index.IsEmpty());
7821 str = v8_str("4294967295");
7822 index = str->ToArrayIndex();
7823 CHECK(!index.IsEmpty());
7824 CHECK_EQ(4294967295.0, index->Uint32Value());
7825 v8::Handle<v8::Number> num = v8::Number::New(1);
7826 index = num->ToArrayIndex();
7827 CHECK(!index.IsEmpty());
7828 CHECK_EQ(1.0, index->Uint32Value());
7829 num = v8::Number::New(-1);
7830 index = num->ToArrayIndex();
7831 CHECK(index.IsEmpty());
7832 v8::Handle<v8::Object> obj = v8::Object::New();
7833 index = obj->ToArrayIndex();
7834 CHECK(index.IsEmpty());
7838 THREADED_TEST(ErrorConstruction) {
7839 LocalContext context;
7840 v8::HandleScope scope(context->GetIsolate());
7842 v8::Handle<String> foo = v8_str("foo");
7843 v8::Handle<String> message = v8_str("message");
7844 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7845 CHECK(range_error->IsObject());
7846 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7847 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7848 CHECK(reference_error->IsObject());
7849 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7850 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7851 CHECK(syntax_error->IsObject());
7852 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7853 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7854 CHECK(type_error->IsObject());
7855 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7856 v8::Handle<Value> error = v8::Exception::Error(foo);
7857 CHECK(error->IsObject());
7858 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7862 static void YGetter(Local<String> name,
7863 const v8::PropertyCallbackInfo<v8::Value>& info) {
7864 ApiTestFuzzer::Fuzz();
7865 info.GetReturnValue().Set(v8_num(10));
7869 static void YSetter(Local<String> name,
7871 const v8::PropertyCallbackInfo<void>& info) {
7872 if (info.This()->Has(name)) {
7873 info.This()->Delete(name);
7875 info.This()->Set(name, value);
7879 THREADED_TEST(DeleteAccessor) {
7880 v8::HandleScope scope(CcTest::isolate());
7881 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7882 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7883 LocalContext context;
7884 v8::Handle<v8::Object> holder = obj->NewInstance();
7885 context->Global()->Set(v8_str("holder"), holder);
7886 v8::Handle<Value> result = CompileRun(
7887 "holder.y = 11; holder.y = 12; holder.y");
7888 CHECK_EQ(12, result->Uint32Value());
7892 THREADED_TEST(TypeSwitch) {
7893 v8::HandleScope scope(CcTest::isolate());
7894 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
7895 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
7896 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
7897 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7898 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7899 LocalContext context;
7900 v8::Handle<v8::Object> obj0 = v8::Object::New();
7901 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7902 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7903 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7904 for (int i = 0; i < 10; i++) {
7905 CHECK_EQ(0, type_switch->match(obj0));
7906 CHECK_EQ(1, type_switch->match(obj1));
7907 CHECK_EQ(2, type_switch->match(obj2));
7908 CHECK_EQ(3, type_switch->match(obj3));
7909 CHECK_EQ(3, type_switch->match(obj3));
7910 CHECK_EQ(2, type_switch->match(obj2));
7911 CHECK_EQ(1, type_switch->match(obj1));
7912 CHECK_EQ(0, type_switch->match(obj0));
7917 // For use within the TestSecurityHandler() test.
7918 static bool g_security_callback_result = false;
7919 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7921 v8::AccessType type,
7922 Local<Value> data) {
7923 // Always allow read access.
7924 if (type == v8::ACCESS_GET)
7927 // Sometimes allow other access.
7928 return g_security_callback_result;
7932 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7934 v8::AccessType type,
7935 Local<Value> data) {
7936 // Always allow read access.
7937 if (type == v8::ACCESS_GET)
7940 // Sometimes allow other access.
7941 return g_security_callback_result;
7945 static int trouble_nesting = 0;
7946 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7947 ApiTestFuzzer::Fuzz();
7950 // Call a JS function that throws an uncaught exception.
7951 Local<v8::Object> arg_this =
7952 args.GetIsolate()->GetCurrentContext()->Global();
7953 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7954 arg_this->Get(v8_str("trouble_callee")) :
7955 arg_this->Get(v8_str("trouble_caller"));
7956 CHECK(trouble_callee->IsFunction());
7957 args.GetReturnValue().Set(
7958 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7962 static int report_count = 0;
7963 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7964 v8::Handle<Value>) {
7969 // Counts uncaught exceptions, but other tests running in parallel
7970 // also have uncaught exceptions.
7971 TEST(ApiUncaughtException) {
7974 v8::HandleScope scope(env->GetIsolate());
7975 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7977 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7978 v8::Local<v8::Object> global = env->Global();
7979 global->Set(v8_str("trouble"), fun->GetFunction());
7981 Script::Compile(v8_str("function trouble_callee() {"
7985 "function trouble_caller() {"
7988 Local<Value> trouble = global->Get(v8_str("trouble"));
7989 CHECK(trouble->IsFunction());
7990 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7991 CHECK(trouble_callee->IsFunction());
7992 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7993 CHECK(trouble_caller->IsFunction());
7994 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7995 CHECK_EQ(1, report_count);
7996 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7999 static const char* script_resource_name = "ExceptionInNativeScript.js";
8000 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8001 v8::Handle<Value>) {
8002 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8003 CHECK(!name_val.IsEmpty() && name_val->IsString());
8004 v8::String::Utf8Value name(message->GetScriptResourceName());
8005 CHECK_EQ(script_resource_name, *name);
8006 CHECK_EQ(3, message->GetLineNumber());
8007 v8::String::Utf8Value source_line(message->GetSourceLine());
8008 CHECK_EQ(" new o.foo();", *source_line);
8012 TEST(ExceptionInNativeScript) {
8014 v8::HandleScope scope(env->GetIsolate());
8015 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8017 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
8018 v8::Local<v8::Object> global = env->Global();
8019 global->Set(v8_str("trouble"), fun->GetFunction());
8021 Script::Compile(v8_str("function trouble() {\n"
8024 "};"), v8::String::New(script_resource_name))->Run();
8025 Local<Value> trouble = global->Get(v8_str("trouble"));
8026 CHECK(trouble->IsFunction());
8027 Function::Cast(*trouble)->Call(global, 0, NULL);
8028 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8032 TEST(CompilationErrorUsingTryCatchHandler) {
8034 v8::HandleScope scope(env->GetIsolate());
8035 v8::TryCatch try_catch;
8036 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8037 CHECK_NE(NULL, *try_catch.Exception());
8038 CHECK(try_catch.HasCaught());
8042 TEST(TryCatchFinallyUsingTryCatchHandler) {
8044 v8::HandleScope scope(env->GetIsolate());
8045 v8::TryCatch try_catch;
8046 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8047 CHECK(!try_catch.HasCaught());
8048 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8049 CHECK(try_catch.HasCaught());
8051 Script::Compile(v8_str("(function() {"
8052 "try { throw ''; } finally { return; }"
8054 CHECK(!try_catch.HasCaught());
8055 Script::Compile(v8_str("(function()"
8056 " { try { throw ''; } finally { throw 0; }"
8058 CHECK(try_catch.HasCaught());
8062 // SecurityHandler can't be run twice
8063 TEST(SecurityHandler) {
8064 v8::HandleScope scope0(CcTest::isolate());
8065 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8066 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8067 IndexedSecurityTestCallback);
8068 // Create an environment
8069 v8::Handle<Context> context0 =
8070 Context::New(CcTest::isolate(), NULL, global_template);
8073 v8::Handle<v8::Object> global0 = context0->Global();
8074 v8::Handle<Script> script0 = v8_compile("foo = 111");
8076 global0->Set(v8_str("0"), v8_num(999));
8077 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8078 CHECK_EQ(111, foo0->Int32Value());
8079 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8080 CHECK_EQ(999, z0->Int32Value());
8082 // Create another environment, should fail security checks.
8083 v8::HandleScope scope1(CcTest::isolate());
8085 v8::Handle<Context> context1 =
8086 Context::New(CcTest::isolate(), NULL, global_template);
8089 v8::Handle<v8::Object> global1 = context1->Global();
8090 global1->Set(v8_str("othercontext"), global0);
8091 // This set will fail the security check.
8092 v8::Handle<Script> script1 =
8093 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8095 // This read will pass the security check.
8096 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8097 CHECK_EQ(111, foo1->Int32Value());
8098 // This read will pass the security check.
8099 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8100 CHECK_EQ(999, z1->Int32Value());
8102 // Create another environment, should pass security checks.
8103 { g_security_callback_result = true; // allow security handler to pass.
8104 v8::HandleScope scope2(CcTest::isolate());
8105 LocalContext context2;
8106 v8::Handle<v8::Object> global2 = context2->Global();
8107 global2->Set(v8_str("othercontext"), global0);
8108 v8::Handle<Script> script2 =
8109 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8111 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8112 CHECK_EQ(333, foo2->Int32Value());
8113 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8114 CHECK_EQ(888, z2->Int32Value());
8122 THREADED_TEST(SecurityChecks) {
8124 v8::HandleScope handle_scope(env1->GetIsolate());
8125 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8127 Local<Value> foo = v8_str("foo");
8128 Local<Value> bar = v8_str("bar");
8130 // Set to the same domain.
8131 env1->SetSecurityToken(foo);
8133 // Create a function in env1.
8134 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8135 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8136 CHECK(spy->IsFunction());
8138 // Create another function accessing global objects.
8139 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8140 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8141 CHECK(spy2->IsFunction());
8143 // Switch to env2 in the same domain and invoke spy on env2.
8145 env2->SetSecurityToken(foo);
8147 Context::Scope scope_env2(env2);
8148 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8149 CHECK(result->IsFunction());
8153 env2->SetSecurityToken(bar);
8154 Context::Scope scope_env2(env2);
8156 // Call cross_domain_call, it should throw an exception
8157 v8::TryCatch try_catch;
8158 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8159 CHECK(try_catch.HasCaught());
8164 // Regression test case for issue 1183439.
8165 THREADED_TEST(SecurityChecksForPrototypeChain) {
8166 LocalContext current;
8167 v8::HandleScope scope(current->GetIsolate());
8168 v8::Handle<Context> other = Context::New(current->GetIsolate());
8170 // Change context to be able to get to the Object function in the
8171 // other context without hitting the security checks.
8172 v8::Local<Value> other_object;
8173 { Context::Scope scope(other);
8174 other_object = other->Global()->Get(v8_str("Object"));
8175 other->Global()->Set(v8_num(42), v8_num(87));
8178 current->Global()->Set(v8_str("other"), other->Global());
8179 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8181 // Make sure the security check fails here and we get an undefined
8182 // result instead of getting the Object function. Repeat in a loop
8183 // to make sure to exercise the IC code.
8184 v8::Local<Script> access_other0 = v8_compile("other.Object");
8185 v8::Local<Script> access_other1 = v8_compile("other[42]");
8186 for (int i = 0; i < 5; i++) {
8187 CHECK(!access_other0->Run()->Equals(other_object));
8188 CHECK(access_other0->Run()->IsUndefined());
8189 CHECK(!access_other1->Run()->Equals(v8_num(87)));
8190 CHECK(access_other1->Run()->IsUndefined());
8193 // Create an object that has 'other' in its prototype chain and make
8194 // sure we cannot access the Object function indirectly through
8195 // that. Repeat in a loop to make sure to exercise the IC code.
8196 v8_compile("function F() { };"
8197 "F.prototype = other;"
8198 "var f = new F();")->Run();
8199 v8::Local<Script> access_f0 = v8_compile("f.Object");
8200 v8::Local<Script> access_f1 = v8_compile("f[42]");
8201 for (int j = 0; j < 5; j++) {
8202 CHECK(!access_f0->Run()->Equals(other_object));
8203 CHECK(access_f0->Run()->IsUndefined());
8204 CHECK(!access_f1->Run()->Equals(v8_num(87)));
8205 CHECK(access_f1->Run()->IsUndefined());
8208 // Now it gets hairy: Set the prototype for the other global object
8209 // to be the current global object. The prototype chain for 'f' now
8210 // goes through 'other' but ends up in the current global object.
8211 { Context::Scope scope(other);
8212 other->Global()->Set(v8_str("__proto__"), current->Global());
8214 // Set a named and an index property on the current global
8215 // object. To force the lookup to go through the other global object,
8216 // the properties must not exist in the other global object.
8217 current->Global()->Set(v8_str("foo"), v8_num(100));
8218 current->Global()->Set(v8_num(99), v8_num(101));
8219 // Try to read the properties from f and make sure that the access
8220 // gets stopped by the security checks on the other global object.
8221 Local<Script> access_f2 = v8_compile("f.foo");
8222 Local<Script> access_f3 = v8_compile("f[99]");
8223 for (int k = 0; k < 5; k++) {
8224 CHECK(!access_f2->Run()->Equals(v8_num(100)));
8225 CHECK(access_f2->Run()->IsUndefined());
8226 CHECK(!access_f3->Run()->Equals(v8_num(101)));
8227 CHECK(access_f3->Run()->IsUndefined());
8232 THREADED_TEST(CrossDomainDelete) {
8234 v8::HandleScope handle_scope(env1->GetIsolate());
8235 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8237 Local<Value> foo = v8_str("foo");
8238 Local<Value> bar = v8_str("bar");
8240 // Set to the same domain.
8241 env1->SetSecurityToken(foo);
8242 env2->SetSecurityToken(foo);
8244 env1->Global()->Set(v8_str("prop"), v8_num(3));
8245 env2->Global()->Set(v8_str("env1"), env1->Global());
8247 // Change env2 to a different domain and delete env1.prop.
8248 env2->SetSecurityToken(bar);
8250 Context::Scope scope_env2(env2);
8251 Local<Value> result =
8252 Script::Compile(v8_str("delete env1.prop"))->Run();
8253 CHECK(result->IsFalse());
8256 // Check that env1.prop still exists.
8257 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8258 CHECK(v->IsNumber());
8259 CHECK_EQ(3, v->Int32Value());
8263 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8265 v8::HandleScope handle_scope(env1->GetIsolate());
8266 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8268 Local<Value> foo = v8_str("foo");
8269 Local<Value> bar = v8_str("bar");
8271 // Set to the same domain.
8272 env1->SetSecurityToken(foo);
8273 env2->SetSecurityToken(foo);
8275 env1->Global()->Set(v8_str("prop"), v8_num(3));
8276 env2->Global()->Set(v8_str("env1"), env1->Global());
8278 // env1.prop is enumerable in env2.
8279 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8281 Context::Scope scope_env2(env2);
8282 Local<Value> result = Script::Compile(test)->Run();
8283 CHECK(result->IsTrue());
8286 // Change env2 to a different domain and test again.
8287 env2->SetSecurityToken(bar);
8289 Context::Scope scope_env2(env2);
8290 Local<Value> result = Script::Compile(test)->Run();
8291 CHECK(result->IsFalse());
8296 THREADED_TEST(CrossDomainForIn) {
8298 v8::HandleScope handle_scope(env1->GetIsolate());
8299 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8301 Local<Value> foo = v8_str("foo");
8302 Local<Value> bar = v8_str("bar");
8304 // Set to the same domain.
8305 env1->SetSecurityToken(foo);
8306 env2->SetSecurityToken(foo);
8308 env1->Global()->Set(v8_str("prop"), v8_num(3));
8309 env2->Global()->Set(v8_str("env1"), env1->Global());
8311 // Change env2 to a different domain and set env1's global object
8312 // as the __proto__ of an object in env2 and enumerate properties
8313 // in for-in. It shouldn't enumerate properties on env1's global
8315 env2->SetSecurityToken(bar);
8317 Context::Scope scope_env2(env2);
8318 Local<Value> result =
8319 CompileRun("(function(){var obj = {'__proto__':env1};"
8320 "for (var p in obj)"
8321 " if (p == 'prop') return false;"
8322 "return true;})()");
8323 CHECK(result->IsTrue());
8328 TEST(ContextDetachGlobal) {
8330 v8::HandleScope handle_scope(env1->GetIsolate());
8331 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8333 Local<v8::Object> global1 = env1->Global();
8335 Local<Value> foo = v8_str("foo");
8337 // Set to the same domain.
8338 env1->SetSecurityToken(foo);
8339 env2->SetSecurityToken(foo);
8344 // Create a function in env2 and add a reference to it in env1.
8345 Local<v8::Object> global2 = env2->Global();
8346 global2->Set(v8_str("prop"), v8::Integer::New(1));
8347 CompileRun("function getProp() {return prop;}");
8349 env1->Global()->Set(v8_str("getProp"),
8350 global2->Get(v8_str("getProp")));
8352 // Detach env2's global, and reuse the global object of env2
8354 env2->DetachGlobal();
8355 // env2 has a new global object.
8356 CHECK(!env2->Global()->Equals(global2));
8358 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8360 v8::Handle<v8::ObjectTemplate>(),
8362 env3->SetSecurityToken(v8_str("bar"));
8365 Local<v8::Object> global3 = env3->Global();
8366 CHECK_EQ(global2, global3);
8367 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8368 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8369 global3->Set(v8_str("prop"), v8::Integer::New(-1));
8370 global3->Set(v8_str("prop2"), v8::Integer::New(2));
8373 // Call getProp in env1, and it should return the value 1
8375 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8376 CHECK(get_prop->IsFunction());
8377 v8::TryCatch try_catch;
8378 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8379 CHECK(!try_catch.HasCaught());
8380 CHECK_EQ(1, r->Int32Value());
8383 // Check that env3 is not accessible from env1
8385 Local<Value> r = global3->Get(v8_str("prop2"));
8386 CHECK(r->IsUndefined());
8391 TEST(DetachAndReattachGlobal) {
8393 v8::HandleScope scope(env1->GetIsolate());
8395 // Create second environment.
8396 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8398 Local<Value> foo = v8_str("foo");
8400 // Set same security token for env1 and env2.
8401 env1->SetSecurityToken(foo);
8402 env2->SetSecurityToken(foo);
8404 // Create a property on the global object in env2.
8406 v8::Context::Scope scope(env2);
8407 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
8410 // Create a reference to env2 global from env1 global.
8411 env1->Global()->Set(v8_str("other"), env2->Global());
8413 // Check that we have access to other.p in env2 from env1.
8414 Local<Value> result = CompileRun("other.p");
8415 CHECK(result->IsInt32());
8416 CHECK_EQ(42, result->Int32Value());
8418 // Hold on to global from env2 and detach global from env2.
8419 Local<v8::Object> global2 = env2->Global();
8420 env2->DetachGlobal();
8422 // Check that the global has been detached. No other.p property can
8424 result = CompileRun("other.p");
8425 CHECK(result->IsUndefined());
8427 // Reuse global2 for env3.
8428 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8430 v8::Handle<v8::ObjectTemplate>(),
8432 CHECK_EQ(global2, env3->Global());
8434 // Start by using the same security token for env3 as for env1 and env2.
8435 env3->SetSecurityToken(foo);
8437 // Create a property on the global object in env3.
8439 v8::Context::Scope scope(env3);
8440 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
8443 // Check that other.p is now the property in env3 and that we have access.
8444 result = CompileRun("other.p");
8445 CHECK(result->IsInt32());
8446 CHECK_EQ(24, result->Int32Value());
8448 // Change security token for env3 to something different from env1 and env2.
8449 env3->SetSecurityToken(v8_str("bar"));
8451 // Check that we do not have access to other.p in env1. |other| is now
8452 // the global object for env3 which has a different security token,
8453 // so access should be blocked.
8454 result = CompileRun("other.p");
8455 CHECK(result->IsUndefined());
8457 // Detach the global for env3 and reattach it to env2.
8458 env3->DetachGlobal();
8459 env2->ReattachGlobal(global2);
8461 // Check that we have access to other.p again in env1. |other| is now
8462 // the global object for env2 which has the same security token as env1.
8463 result = CompileRun("other.p");
8464 CHECK(result->IsInt32());
8465 CHECK_EQ(42, result->Int32Value());
8469 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8470 static bool NamedAccessBlocker(Local<v8::Object> global,
8472 v8::AccessType type,
8473 Local<Value> data) {
8474 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8475 allowed_access_type[type];
8479 static bool IndexedAccessBlocker(Local<v8::Object> global,
8481 v8::AccessType type,
8482 Local<Value> data) {
8483 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8484 allowed_access_type[type];
8488 static int g_echo_value_1 = -1;
8489 static int g_echo_value_2 = -1;
8492 static void EchoGetter(
8494 const v8::PropertyCallbackInfo<v8::Value>& info) {
8495 info.GetReturnValue().Set(v8_num(g_echo_value_1));
8499 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8500 info.GetReturnValue().Set(v8_num(g_echo_value_2));
8504 static void EchoSetter(Local<String> name,
8506 const v8::PropertyCallbackInfo<void>&) {
8507 if (value->IsNumber())
8508 g_echo_value_1 = value->Int32Value();
8512 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8513 v8::Handle<v8::Value> value = info[0];
8514 if (value->IsNumber())
8515 g_echo_value_2 = value->Int32Value();
8519 static void UnreachableGetter(
8521 const v8::PropertyCallbackInfo<v8::Value>& info) {
8522 CHECK(false); // This function should not be called..
8526 static void UnreachableSetter(Local<String>,
8528 const v8::PropertyCallbackInfo<void>&) {
8529 CHECK(false); // This function should nto be called.
8533 static void UnreachableFunction(
8534 const v8::FunctionCallbackInfo<v8::Value>& info) {
8535 CHECK(false); // This function should not be called..
8539 TEST(AccessControl) {
8540 v8::Isolate* isolate = CcTest::isolate();
8541 v8::HandleScope handle_scope(isolate);
8542 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8544 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8545 IndexedAccessBlocker);
8547 // Add an accessor accessible by cross-domain JS code.
8548 global_template->SetAccessor(
8549 v8_str("accessible_prop"),
8550 EchoGetter, EchoSetter,
8551 v8::Handle<Value>(),
8552 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8555 global_template->SetAccessorProperty(
8556 v8_str("accessible_js_prop"),
8557 v8::FunctionTemplate::New(EchoGetter),
8558 v8::FunctionTemplate::New(EchoSetter),
8560 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8562 // Add an accessor that is not accessible by cross-domain JS code.
8563 global_template->SetAccessor(v8_str("blocked_prop"),
8564 UnreachableGetter, UnreachableSetter,
8565 v8::Handle<Value>(),
8568 global_template->SetAccessorProperty(
8569 v8_str("blocked_js_prop"),
8570 v8::FunctionTemplate::New(UnreachableFunction),
8571 v8::FunctionTemplate::New(UnreachableFunction),
8575 // Create an environment
8576 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8579 v8::Handle<v8::Object> global0 = context0->Global();
8581 // Define a property with JS getter and setter.
8583 "function getter() { return 'getter'; };\n"
8584 "function setter() { return 'setter'; }\n"
8585 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8587 Local<Value> getter = global0->Get(v8_str("getter"));
8588 Local<Value> setter = global0->Get(v8_str("setter"));
8590 // And define normal element.
8591 global0->Set(239, v8_str("239"));
8593 // Define an element with JS getter and setter.
8595 "function el_getter() { return 'el_getter'; };\n"
8596 "function el_setter() { return 'el_setter'; };\n"
8597 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8599 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8600 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8602 v8::HandleScope scope1(isolate);
8604 v8::Local<Context> context1 = Context::New(isolate);
8607 v8::Handle<v8::Object> global1 = context1->Global();
8608 global1->Set(v8_str("other"), global0);
8610 // Access blocked property.
8611 CompileRun("other.blocked_prop = 1");
8613 ExpectUndefined("other.blocked_prop");
8615 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8616 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8618 // Enable ACCESS_HAS
8619 allowed_access_type[v8::ACCESS_HAS] = true;
8620 ExpectUndefined("other.blocked_prop");
8621 // ... and now we can get the descriptor...
8623 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
8624 // ... and enumerate the property.
8625 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
8626 allowed_access_type[v8::ACCESS_HAS] = false;
8628 // Access blocked element.
8629 CompileRun("other[239] = 1");
8631 ExpectUndefined("other[239]");
8632 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
8633 ExpectFalse("propertyIsEnumerable.call(other, '239')");
8635 // Enable ACCESS_HAS
8636 allowed_access_type[v8::ACCESS_HAS] = true;
8637 ExpectUndefined("other[239]");
8638 // ... and now we can get the descriptor...
8639 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
8640 // ... and enumerate the property.
8641 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8642 allowed_access_type[v8::ACCESS_HAS] = false;
8644 // Access a property with JS accessor.
8645 CompileRun("other.js_accessor_p = 2");
8647 ExpectUndefined("other.js_accessor_p");
8649 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
8651 // Enable ACCESS_HAS.
8652 allowed_access_type[v8::ACCESS_HAS] = true;
8653 ExpectUndefined("other.js_accessor_p");
8655 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8657 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8659 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8660 allowed_access_type[v8::ACCESS_HAS] = false;
8662 // Enable both ACCESS_HAS and ACCESS_GET.
8663 allowed_access_type[v8::ACCESS_HAS] = true;
8664 allowed_access_type[v8::ACCESS_GET] = true;
8666 ExpectString("other.js_accessor_p", "getter");
8668 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8670 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8672 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8674 allowed_access_type[v8::ACCESS_GET] = false;
8675 allowed_access_type[v8::ACCESS_HAS] = false;
8677 // Enable both ACCESS_HAS and ACCESS_SET.
8678 allowed_access_type[v8::ACCESS_HAS] = true;
8679 allowed_access_type[v8::ACCESS_SET] = true;
8681 ExpectUndefined("other.js_accessor_p");
8683 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8685 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8687 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8689 allowed_access_type[v8::ACCESS_SET] = false;
8690 allowed_access_type[v8::ACCESS_HAS] = false;
8692 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8693 allowed_access_type[v8::ACCESS_HAS] = true;
8694 allowed_access_type[v8::ACCESS_GET] = true;
8695 allowed_access_type[v8::ACCESS_SET] = true;
8697 ExpectString("other.js_accessor_p", "getter");
8699 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8701 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8703 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8705 allowed_access_type[v8::ACCESS_SET] = false;
8706 allowed_access_type[v8::ACCESS_GET] = false;
8707 allowed_access_type[v8::ACCESS_HAS] = false;
8709 // Access an element with JS accessor.
8710 CompileRun("other[42] = 2");
8712 ExpectUndefined("other[42]");
8713 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
8715 // Enable ACCESS_HAS.
8716 allowed_access_type[v8::ACCESS_HAS] = true;
8717 ExpectUndefined("other[42]");
8718 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8719 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8720 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8721 allowed_access_type[v8::ACCESS_HAS] = false;
8723 // Enable both ACCESS_HAS and ACCESS_GET.
8724 allowed_access_type[v8::ACCESS_HAS] = true;
8725 allowed_access_type[v8::ACCESS_GET] = true;
8727 ExpectString("other[42]", "el_getter");
8728 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8729 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8730 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8732 allowed_access_type[v8::ACCESS_GET] = false;
8733 allowed_access_type[v8::ACCESS_HAS] = false;
8735 // Enable both ACCESS_HAS and ACCESS_SET.
8736 allowed_access_type[v8::ACCESS_HAS] = true;
8737 allowed_access_type[v8::ACCESS_SET] = true;
8739 ExpectUndefined("other[42]");
8740 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8741 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8742 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8744 allowed_access_type[v8::ACCESS_SET] = false;
8745 allowed_access_type[v8::ACCESS_HAS] = false;
8747 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8748 allowed_access_type[v8::ACCESS_HAS] = true;
8749 allowed_access_type[v8::ACCESS_GET] = true;
8750 allowed_access_type[v8::ACCESS_SET] = true;
8752 ExpectString("other[42]", "el_getter");
8753 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8754 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8755 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8757 allowed_access_type[v8::ACCESS_SET] = false;
8758 allowed_access_type[v8::ACCESS_GET] = false;
8759 allowed_access_type[v8::ACCESS_HAS] = false;
8761 v8::Handle<Value> value;
8763 // Access accessible property
8764 value = CompileRun("other.accessible_prop = 3");
8765 CHECK(value->IsNumber());
8766 CHECK_EQ(3, value->Int32Value());
8767 CHECK_EQ(3, g_echo_value_1);
8769 // Access accessible js property
8770 value = CompileRun("other.accessible_js_prop = 3");
8771 CHECK(value->IsNumber());
8772 CHECK_EQ(3, value->Int32Value());
8773 CHECK_EQ(3, g_echo_value_2);
8775 value = CompileRun("other.accessible_prop");
8776 CHECK(value->IsNumber());
8777 CHECK_EQ(3, value->Int32Value());
8779 value = CompileRun("other.accessible_js_prop");
8780 CHECK(value->IsNumber());
8781 CHECK_EQ(3, value->Int32Value());
8784 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8785 CHECK(value->IsNumber());
8786 CHECK_EQ(3, value->Int32Value());
8789 "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
8790 CHECK(value->IsNumber());
8791 CHECK_EQ(3, value->Int32Value());
8793 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8794 CHECK(value->IsTrue());
8796 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
8797 CHECK(value->IsTrue());
8799 // Enumeration doesn't enumerate accessors from inaccessible objects in
8800 // the prototype chain even if the accessors are in themselves accessible.
8802 CompileRun("(function(){var obj = {'__proto__':other};"
8803 "for (var p in obj)"
8804 " if (p == 'accessible_prop' ||"
8805 " p == 'accessible_js_prop' ||"
8806 " p == 'blocked_js_prop' ||"
8807 " p == 'blocked_js_prop') {"
8810 "return true;})()");
8811 CHECK(value->IsTrue());
8818 TEST(AccessControlES5) {
8819 v8::Isolate* isolate = CcTest::isolate();
8820 v8::HandleScope handle_scope(isolate);
8821 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8823 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8824 IndexedAccessBlocker);
8826 // Add accessible accessor.
8827 global_template->SetAccessor(
8828 v8_str("accessible_prop"),
8829 EchoGetter, EchoSetter,
8830 v8::Handle<Value>(),
8831 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8834 // Add an accessor that is not accessible by cross-domain JS code.
8835 global_template->SetAccessor(v8_str("blocked_prop"),
8836 UnreachableGetter, UnreachableSetter,
8837 v8::Handle<Value>(),
8840 // Create an environment
8841 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8844 v8::Handle<v8::Object> global0 = context0->Global();
8846 v8::Local<Context> context1 = Context::New(isolate);
8848 v8::Handle<v8::Object> global1 = context1->Global();
8849 global1->Set(v8_str("other"), global0);
8851 // Regression test for issue 1154.
8852 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
8854 ExpectUndefined("other.blocked_prop");
8856 // Regression test for issue 1027.
8857 CompileRun("Object.defineProperty(\n"
8858 " other, 'blocked_prop', {configurable: false})");
8859 ExpectUndefined("other.blocked_prop");
8861 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8863 // Regression test for issue 1171.
8864 ExpectTrue("Object.isExtensible(other)");
8865 CompileRun("Object.preventExtensions(other)");
8866 ExpectTrue("Object.isExtensible(other)");
8868 // Object.seal and Object.freeze.
8869 CompileRun("Object.freeze(other)");
8870 ExpectTrue("Object.isExtensible(other)");
8872 CompileRun("Object.seal(other)");
8873 ExpectTrue("Object.isExtensible(other)");
8875 // Regression test for issue 1250.
8876 // Make sure that we can set the accessible accessors value using normal
8878 CompileRun("other.accessible_prop = 42");
8879 CHECK_EQ(42, g_echo_value_1);
8881 v8::Handle<Value> value;
8882 // We follow Safari in ignoring assignments to host object accessors.
8883 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8884 value = CompileRun("other.accessible_prop == 42");
8885 CHECK(value->IsTrue());
8889 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
8891 v8::AccessType type,
8892 Local<Value> data) {
8897 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
8899 v8::AccessType type,
8900 Local<Value> data) {
8905 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8906 v8::Isolate* isolate = CcTest::isolate();
8907 v8::HandleScope handle_scope(isolate);
8908 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8910 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8911 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
8912 GetOwnPropertyNamesIndexedBlocker);
8914 // Create an environment
8915 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8918 v8::Handle<v8::Object> global0 = context0->Global();
8920 v8::HandleScope scope1(CcTest::isolate());
8922 v8::Local<Context> context1 = Context::New(isolate);
8925 v8::Handle<v8::Object> global1 = context1->Global();
8926 global1->Set(v8_str("other"), global0);
8927 global1->Set(v8_str("object"), obj_template->NewInstance());
8929 v8::Handle<Value> value;
8931 // Attempt to get the property names of the other global object and
8932 // of an object that requires access checks. Accessing the other
8933 // global object should be blocked by access checks on the global
8934 // proxy object. Accessing the object that requires access checks
8935 // is blocked by the access checks on the object itself.
8936 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8937 CHECK(value->IsTrue());
8939 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8940 CHECK(value->IsTrue());
8947 static void IndexedPropertyEnumerator(
8948 const v8::PropertyCallbackInfo<v8::Array>& info) {
8949 v8::Handle<v8::Array> result = v8::Array::New(2);
8950 result->Set(0, v8::Integer::New(7));
8951 result->Set(1, v8::Object::New());
8952 info.GetReturnValue().Set(result);
8956 static void NamedPropertyEnumerator(
8957 const v8::PropertyCallbackInfo<v8::Array>& info) {
8958 v8::Handle<v8::Array> result = v8::Array::New(2);
8959 result->Set(0, v8_str("x"));
8960 result->Set(1, v8::Object::New());
8961 info.GetReturnValue().Set(result);
8965 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
8966 v8::HandleScope handle_scope(CcTest::isolate());
8967 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8969 obj_template->Set(v8_str("7"), v8::Integer::New(7));
8970 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8971 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
8972 IndexedPropertyEnumerator);
8973 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
8974 NamedPropertyEnumerator);
8976 LocalContext context;
8977 v8::Handle<v8::Object> global = context->Global();
8978 global->Set(v8_str("object"), obj_template->NewInstance());
8980 v8::Handle<v8::Value> result =
8981 CompileRun("Object.getOwnPropertyNames(object)");
8982 CHECK(result->IsArray());
8983 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
8984 CHECK_EQ(3, result_array->Length());
8985 CHECK(result_array->Get(0)->IsString());
8986 CHECK(result_array->Get(1)->IsString());
8987 CHECK(result_array->Get(2)->IsString());
8988 CHECK_EQ(v8_str("7"), result_array->Get(0));
8989 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
8990 CHECK_EQ(v8_str("x"), result_array->Get(2));
8994 static void ConstTenGetter(Local<String> name,
8995 const v8::PropertyCallbackInfo<v8::Value>& info) {
8996 info.GetReturnValue().Set(v8_num(10));
9000 THREADED_TEST(CrossDomainAccessors) {
9001 v8::Isolate* isolate = CcTest::isolate();
9002 v8::HandleScope handle_scope(isolate);
9004 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
9006 v8::Handle<v8::ObjectTemplate> global_template =
9007 func_template->InstanceTemplate();
9009 v8::Handle<v8::ObjectTemplate> proto_template =
9010 func_template->PrototypeTemplate();
9012 // Add an accessor to proto that's accessible by cross-domain JS code.
9013 proto_template->SetAccessor(v8_str("accessible"),
9015 v8::Handle<Value>(),
9018 // Add an accessor that is not accessible by cross-domain JS code.
9019 global_template->SetAccessor(v8_str("unreachable"),
9020 UnreachableGetter, 0,
9021 v8::Handle<Value>(),
9024 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9027 Local<v8::Object> global = context0->Global();
9028 // Add a normal property that shadows 'accessible'
9029 global->Set(v8_str("accessible"), v8_num(11));
9031 // Enter a new context.
9032 v8::HandleScope scope1(CcTest::isolate());
9033 v8::Local<Context> context1 = Context::New(isolate);
9036 v8::Handle<v8::Object> global1 = context1->Global();
9037 global1->Set(v8_str("other"), global);
9039 // Should return 10, instead of 11
9040 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9041 CHECK(value->IsNumber());
9042 CHECK_EQ(10, value->Int32Value());
9044 value = v8_compile("other.unreachable")->Run();
9045 CHECK(value->IsUndefined());
9052 static int named_access_count = 0;
9053 static int indexed_access_count = 0;
9055 static bool NamedAccessCounter(Local<v8::Object> global,
9057 v8::AccessType type,
9058 Local<Value> data) {
9059 named_access_count++;
9064 static bool IndexedAccessCounter(Local<v8::Object> global,
9066 v8::AccessType type,
9067 Local<Value> data) {
9068 indexed_access_count++;
9073 // This one is too easily disturbed by other tests.
9074 TEST(AccessControlIC) {
9075 named_access_count = 0;
9076 indexed_access_count = 0;
9078 v8::Isolate* isolate = CcTest::isolate();
9079 v8::HandleScope handle_scope(isolate);
9081 // Create an environment.
9082 v8::Local<Context> context0 = Context::New(isolate);
9085 // Create an object that requires access-check functions to be
9086 // called for cross-domain access.
9087 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9088 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9089 IndexedAccessCounter);
9090 Local<v8::Object> object = object_template->NewInstance();
9092 v8::HandleScope scope1(isolate);
9094 // Create another environment.
9095 v8::Local<Context> context1 = Context::New(isolate);
9098 // Make easy access to the object from the other environment.
9099 v8::Handle<v8::Object> global1 = context1->Global();
9100 global1->Set(v8_str("obj"), object);
9102 v8::Handle<Value> value;
9104 // Check that the named access-control function is called every time.
9105 CompileRun("function testProp(obj) {"
9106 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9107 " for (var j = 0; j < 10; j++) obj.prop;"
9110 value = CompileRun("testProp(obj)");
9111 CHECK(value->IsNumber());
9112 CHECK_EQ(1, value->Int32Value());
9113 CHECK_EQ(21, named_access_count);
9115 // Check that the named access-control function is called every time.
9116 CompileRun("var p = 'prop';"
9117 "function testKeyed(obj) {"
9118 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9119 " for (var j = 0; j < 10; j++) obj[p];"
9122 // Use obj which requires access checks. No inline caching is used
9124 value = CompileRun("testKeyed(obj)");
9125 CHECK(value->IsNumber());
9126 CHECK_EQ(1, value->Int32Value());
9127 CHECK_EQ(42, named_access_count);
9128 // Force the inline caches into generic state and try again.
9129 CompileRun("testKeyed({ a: 0 })");
9130 CompileRun("testKeyed({ b: 0 })");
9131 value = CompileRun("testKeyed(obj)");
9132 CHECK(value->IsNumber());
9133 CHECK_EQ(1, value->Int32Value());
9134 CHECK_EQ(63, named_access_count);
9136 // Check that the indexed access-control function is called every time.
9137 CompileRun("function testIndexed(obj) {"
9138 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9139 " for (var j = 0; j < 10; j++) obj[0];"
9142 value = CompileRun("testIndexed(obj)");
9143 CHECK(value->IsNumber());
9144 CHECK_EQ(1, value->Int32Value());
9145 CHECK_EQ(21, indexed_access_count);
9146 // Force the inline caches into generic state.
9147 CompileRun("testIndexed(new Array(1))");
9148 // Test that the indexed access check is called.
9149 value = CompileRun("testIndexed(obj)");
9150 CHECK(value->IsNumber());
9151 CHECK_EQ(1, value->Int32Value());
9152 CHECK_EQ(42, indexed_access_count);
9154 // Check that the named access check is called when invoking
9155 // functions on an object that requires access checks.
9156 CompileRun("obj.f = function() {}");
9157 CompileRun("function testCallNormal(obj) {"
9158 " for (var i = 0; i < 10; i++) obj.f();"
9160 CompileRun("testCallNormal(obj)");
9161 CHECK_EQ(74, named_access_count);
9163 // Force obj into slow case.
9164 value = CompileRun("delete obj.prop");
9165 CHECK(value->BooleanValue());
9166 // Force inline caches into dictionary probing mode.
9167 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9168 // Test that the named access check is called.
9169 value = CompileRun("testProp(obj);");
9170 CHECK(value->IsNumber());
9171 CHECK_EQ(1, value->Int32Value());
9172 CHECK_EQ(96, named_access_count);
9174 // Force the call inline cache into dictionary probing mode.
9175 CompileRun("o.f = function() {}; testCallNormal(o)");
9176 // Test that the named access check is still called for each
9177 // invocation of the function.
9178 value = CompileRun("testCallNormal(obj)");
9179 CHECK_EQ(106, named_access_count);
9186 static bool NamedAccessFlatten(Local<v8::Object> global,
9188 v8::AccessType type,
9189 Local<Value> data) {
9193 CHECK(name->IsString());
9195 memset(buf, 0x1, sizeof(buf));
9196 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9201 memset(buf, 0x1, sizeof(buf));
9202 len = name.As<String>()->Write(buf2);
9209 static bool IndexedAccessFlatten(Local<v8::Object> global,
9211 v8::AccessType type,
9212 Local<Value> data) {
9217 // Regression test. In access checks, operations that may cause
9218 // garbage collection are not allowed. It used to be the case that
9219 // using the Write operation on a string could cause a garbage
9220 // collection due to flattening of the string. This is no longer the
9222 THREADED_TEST(AccessControlFlatten) {
9223 named_access_count = 0;
9224 indexed_access_count = 0;
9226 v8::Isolate* isolate = CcTest::isolate();
9227 v8::HandleScope handle_scope(isolate);
9229 // Create an environment.
9230 v8::Local<Context> context0 = Context::New(isolate);
9233 // Create an object that requires access-check functions to be
9234 // called for cross-domain access.
9235 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9236 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9237 IndexedAccessFlatten);
9238 Local<v8::Object> object = object_template->NewInstance();
9240 v8::HandleScope scope1(isolate);
9242 // Create another environment.
9243 v8::Local<Context> context1 = Context::New(isolate);
9246 // Make easy access to the object from the other environment.
9247 v8::Handle<v8::Object> global1 = context1->Global();
9248 global1->Set(v8_str("obj"), object);
9250 v8::Handle<Value> value;
9252 value = v8_compile("var p = 'as' + 'df';")->Run();
9253 value = v8_compile("obj[p];")->Run();
9260 static void AccessControlNamedGetter(
9262 const v8::PropertyCallbackInfo<v8::Value>& info) {
9263 info.GetReturnValue().Set(42);
9267 static void AccessControlNamedSetter(
9270 const v8::PropertyCallbackInfo<v8::Value>& info) {
9271 info.GetReturnValue().Set(value);
9275 static void AccessControlIndexedGetter(
9277 const v8::PropertyCallbackInfo<v8::Value>& info) {
9278 info.GetReturnValue().Set(v8_num(42));
9282 static void AccessControlIndexedSetter(
9285 const v8::PropertyCallbackInfo<v8::Value>& info) {
9286 info.GetReturnValue().Set(value);
9290 THREADED_TEST(AccessControlInterceptorIC) {
9291 named_access_count = 0;
9292 indexed_access_count = 0;
9294 v8::Isolate* isolate = CcTest::isolate();
9295 v8::HandleScope handle_scope(isolate);
9297 // Create an environment.
9298 v8::Local<Context> context0 = Context::New(isolate);
9301 // Create an object that requires access-check functions to be
9302 // called for cross-domain access. The object also has interceptors
9304 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9305 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9306 IndexedAccessCounter);
9307 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9308 AccessControlNamedSetter);
9309 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9310 AccessControlIndexedSetter);
9311 Local<v8::Object> object = object_template->NewInstance();
9313 v8::HandleScope scope1(isolate);
9315 // Create another environment.
9316 v8::Local<Context> context1 = Context::New(isolate);
9319 // Make easy access to the object from the other environment.
9320 v8::Handle<v8::Object> global1 = context1->Global();
9321 global1->Set(v8_str("obj"), object);
9323 v8::Handle<Value> value;
9325 // Check that the named access-control function is called every time
9326 // eventhough there is an interceptor on the object.
9327 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9328 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9330 CHECK(value->IsNumber());
9331 CHECK_EQ(42, value->Int32Value());
9332 CHECK_EQ(21, named_access_count);
9334 value = v8_compile("var p = 'x';")->Run();
9335 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9336 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9338 CHECK(value->IsNumber());
9339 CHECK_EQ(42, value->Int32Value());
9340 CHECK_EQ(42, named_access_count);
9342 // Check that the indexed access-control function is called every
9343 // time eventhough there is an interceptor on the object.
9344 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9345 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9347 CHECK(value->IsNumber());
9348 CHECK_EQ(42, value->Int32Value());
9349 CHECK_EQ(21, indexed_access_count);
9356 THREADED_TEST(Version) {
9357 v8::V8::GetVersion();
9361 static void InstanceFunctionCallback(
9362 const v8::FunctionCallbackInfo<v8::Value>& args) {
9363 ApiTestFuzzer::Fuzz();
9364 args.GetReturnValue().Set(v8_num(12));
9368 THREADED_TEST(InstanceProperties) {
9369 LocalContext context;
9370 v8::HandleScope handle_scope(context->GetIsolate());
9372 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9373 Local<ObjectTemplate> instance = t->InstanceTemplate();
9375 instance->Set(v8_str("x"), v8_num(42));
9376 instance->Set(v8_str("f"),
9377 v8::FunctionTemplate::New(InstanceFunctionCallback));
9379 Local<Value> o = t->GetFunction()->NewInstance();
9381 context->Global()->Set(v8_str("i"), o);
9382 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9383 CHECK_EQ(42, value->Int32Value());
9385 value = Script::Compile(v8_str("i.f()"))->Run();
9386 CHECK_EQ(12, value->Int32Value());
9390 static void GlobalObjectInstancePropertiesGet(
9392 const v8::PropertyCallbackInfo<v8::Value>&) {
9393 ApiTestFuzzer::Fuzz();
9397 THREADED_TEST(GlobalObjectInstanceProperties) {
9398 v8::HandleScope handle_scope(CcTest::isolate());
9400 Local<Value> global_object;
9402 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9403 t->InstanceTemplate()->SetNamedPropertyHandler(
9404 GlobalObjectInstancePropertiesGet);
9405 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9406 instance_template->Set(v8_str("x"), v8_num(42));
9407 instance_template->Set(v8_str("f"),
9408 v8::FunctionTemplate::New(InstanceFunctionCallback));
9410 // The script to check how Crankshaft compiles missing global function
9411 // invocations. function g is not defined and should throw on call.
9412 const char* script =
9413 "function wrapper(call) {"
9414 " var x = 0, y = 1;"
9415 " for (var i = 0; i < 1000; i++) {"
9421 "for (var i = 0; i < 17; i++) wrapper(false);"
9423 "try { wrapper(true); } catch (e) { thrown = 1; };"
9427 LocalContext env(NULL, instance_template);
9428 // Hold on to the global object so it can be used again in another
9429 // environment initialization.
9430 global_object = env->Global();
9432 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9433 CHECK_EQ(42, value->Int32Value());
9434 value = Script::Compile(v8_str("f()"))->Run();
9435 CHECK_EQ(12, value->Int32Value());
9436 value = Script::Compile(v8_str(script))->Run();
9437 CHECK_EQ(1, value->Int32Value());
9441 // Create new environment reusing the global object.
9442 LocalContext env(NULL, instance_template, global_object);
9443 Local<Value> value = Script::Compile(v8_str("x"))->Run();
9444 CHECK_EQ(42, value->Int32Value());
9445 value = Script::Compile(v8_str("f()"))->Run();
9446 CHECK_EQ(12, value->Int32Value());
9447 value = Script::Compile(v8_str(script))->Run();
9448 CHECK_EQ(1, value->Int32Value());
9453 THREADED_TEST(CallKnownGlobalReceiver) {
9454 v8::HandleScope handle_scope(CcTest::isolate());
9456 Local<Value> global_object;
9458 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9459 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9461 // The script to check that we leave global object not
9462 // global object proxy on stack when we deoptimize from inside
9463 // arguments evaluation.
9464 // To provoke error we need to both force deoptimization
9465 // from arguments evaluation and to force CallIC to take
9466 // CallIC_Miss code path that can't cope with global proxy.
9467 const char* script =
9468 "function bar(x, y) { try { } finally { } }"
9469 "function baz(x) { try { } finally { } }"
9470 "function bom(x) { try { } finally { } }"
9471 "function foo(x) { bar([x], bom(2)); }"
9472 "for (var i = 0; i < 10000; i++) foo(1);"
9477 LocalContext env(NULL, instance_template);
9478 // Hold on to the global object so it can be used again in another
9479 // environment initialization.
9480 global_object = env->Global();
9481 foo = Script::Compile(v8_str(script))->Run();
9485 // Create new environment reusing the global object.
9486 LocalContext env(NULL, instance_template, global_object);
9487 env->Global()->Set(v8_str("foo"), foo);
9488 Script::Compile(v8_str("foo()"))->Run();
9493 static void ShadowFunctionCallback(
9494 const v8::FunctionCallbackInfo<v8::Value>& args) {
9495 ApiTestFuzzer::Fuzz();
9496 args.GetReturnValue().Set(v8_num(42));
9500 static int shadow_y;
9501 static int shadow_y_setter_call_count;
9502 static int shadow_y_getter_call_count;
9505 static void ShadowYSetter(Local<String>,
9507 const v8::PropertyCallbackInfo<void>&) {
9508 shadow_y_setter_call_count++;
9513 static void ShadowYGetter(Local<String> name,
9514 const v8::PropertyCallbackInfo<v8::Value>& info) {
9515 ApiTestFuzzer::Fuzz();
9516 shadow_y_getter_call_count++;
9517 info.GetReturnValue().Set(v8_num(shadow_y));
9521 static void ShadowIndexedGet(uint32_t index,
9522 const v8::PropertyCallbackInfo<v8::Value>&) {
9526 static void ShadowNamedGet(Local<String> key,
9527 const v8::PropertyCallbackInfo<v8::Value>&) {
9531 THREADED_TEST(ShadowObject) {
9532 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9533 v8::HandleScope handle_scope(CcTest::isolate());
9535 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
9536 LocalContext context(NULL, global_template);
9538 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9539 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9540 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9541 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9542 Local<ObjectTemplate> instance = t->InstanceTemplate();
9544 proto->Set(v8_str("f"),
9545 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
9546 proto->Set(v8_str("x"), v8_num(12));
9548 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9550 Local<Value> o = t->GetFunction()->NewInstance();
9551 context->Global()->Set(v8_str("__proto__"), o);
9553 Local<Value> value =
9554 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9555 CHECK(value->IsBoolean());
9556 CHECK(!value->BooleanValue());
9558 value = Script::Compile(v8_str("x"))->Run();
9559 CHECK_EQ(12, value->Int32Value());
9561 value = Script::Compile(v8_str("f()"))->Run();
9562 CHECK_EQ(42, value->Int32Value());
9564 Script::Compile(v8_str("y = 43"))->Run();
9565 CHECK_EQ(1, shadow_y_setter_call_count);
9566 value = Script::Compile(v8_str("y"))->Run();
9567 CHECK_EQ(1, shadow_y_getter_call_count);
9568 CHECK_EQ(42, value->Int32Value());
9572 THREADED_TEST(HiddenPrototype) {
9573 LocalContext context;
9574 v8::HandleScope handle_scope(context->GetIsolate());
9576 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9577 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9578 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9579 t1->SetHiddenPrototype(true);
9580 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9581 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9582 t2->SetHiddenPrototype(true);
9583 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9584 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9585 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9587 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9588 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9589 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9590 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9592 // Setting the prototype on an object skips hidden prototypes.
9593 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9594 o0->Set(v8_str("__proto__"), o1);
9595 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9596 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9597 o0->Set(v8_str("__proto__"), o2);
9598 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9599 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9600 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9601 o0->Set(v8_str("__proto__"), o3);
9602 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9603 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9604 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9605 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9607 // Getting the prototype of o0 should get the first visible one
9608 // which is o3. Therefore, z should not be defined on the prototype
9610 Local<Value> proto = o0->Get(v8_str("__proto__"));
9611 CHECK(proto->IsObject());
9612 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9616 THREADED_TEST(HiddenPrototypeSet) {
9617 LocalContext context;
9618 v8::HandleScope handle_scope(context->GetIsolate());
9620 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
9621 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
9622 ht->SetHiddenPrototype(true);
9623 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
9624 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9626 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9627 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9628 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9629 o->Set(v8_str("__proto__"), h);
9630 h->Set(v8_str("__proto__"), p);
9632 // Setting a property that exists on the hidden prototype goes there.
9633 o->Set(v8_str("x"), v8_num(7));
9634 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9635 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9636 CHECK(p->Get(v8_str("x"))->IsUndefined());
9638 // Setting a new property should not be forwarded to the hidden prototype.
9639 o->Set(v8_str("y"), v8_num(6));
9640 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9641 CHECK(h->Get(v8_str("y"))->IsUndefined());
9642 CHECK(p->Get(v8_str("y"))->IsUndefined());
9644 // Setting a property that only exists on a prototype of the hidden prototype
9645 // is treated normally again.
9646 p->Set(v8_str("z"), v8_num(8));
9647 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9648 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9649 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9650 o->Set(v8_str("z"), v8_num(9));
9651 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9652 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9653 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9657 // Regression test for issue 2457.
9658 THREADED_TEST(HiddenPrototypeIdentityHash) {
9659 LocalContext context;
9660 v8::HandleScope handle_scope(context->GetIsolate());
9662 Handle<FunctionTemplate> t = FunctionTemplate::New();
9663 t->SetHiddenPrototype(true);
9664 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9665 Handle<Object> p = t->GetFunction()->NewInstance();
9666 Handle<Object> o = Object::New();
9669 int hash = o->GetIdentityHash();
9671 o->Set(v8_str("foo"), v8_num(42));
9672 ASSERT_EQ(hash, o->GetIdentityHash());
9676 THREADED_TEST(SetPrototype) {
9677 LocalContext context;
9678 v8::HandleScope handle_scope(context->GetIsolate());
9680 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9681 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9682 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9683 t1->SetHiddenPrototype(true);
9684 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9685 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9686 t2->SetHiddenPrototype(true);
9687 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9688 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9689 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9691 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9692 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9693 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9694 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9696 // Setting the prototype on an object does not skip hidden prototypes.
9697 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9698 CHECK(o0->SetPrototype(o1));
9699 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9700 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9701 CHECK(o1->SetPrototype(o2));
9702 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9703 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9704 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9705 CHECK(o2->SetPrototype(o3));
9706 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9707 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9708 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9709 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9711 // Getting the prototype of o0 should get the first visible one
9712 // which is o3. Therefore, z should not be defined on the prototype
9714 Local<Value> proto = o0->Get(v8_str("__proto__"));
9715 CHECK(proto->IsObject());
9716 CHECK_EQ(proto.As<v8::Object>(), o3);
9718 // However, Object::GetPrototype ignores hidden prototype.
9719 Local<Value> proto0 = o0->GetPrototype();
9720 CHECK(proto0->IsObject());
9721 CHECK_EQ(proto0.As<v8::Object>(), o1);
9723 Local<Value> proto1 = o1->GetPrototype();
9724 CHECK(proto1->IsObject());
9725 CHECK_EQ(proto1.As<v8::Object>(), o2);
9727 Local<Value> proto2 = o2->GetPrototype();
9728 CHECK(proto2->IsObject());
9729 CHECK_EQ(proto2.As<v8::Object>(), o3);
9733 // Getting property names of an object with a prototype chain that
9734 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
9735 // crash the runtime.
9736 THREADED_TEST(Regress91517) {
9737 i::FLAG_allow_natives_syntax = true;
9738 LocalContext context;
9739 v8::HandleScope handle_scope(context->GetIsolate());
9741 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9742 t1->SetHiddenPrototype(true);
9743 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9744 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9745 t2->SetHiddenPrototype(true);
9746 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9747 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
9748 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9749 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9750 t3->SetHiddenPrototype(true);
9751 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9752 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
9753 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9755 // Force dictionary-based properties.
9756 i::ScopedVector<char> name_buf(1024);
9757 for (int i = 1; i <= 1000; i++) {
9758 i::OS::SNPrintF(name_buf, "sdf%d", i);
9759 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9762 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9763 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9764 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9765 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9767 // Create prototype chain of hidden prototypes.
9768 CHECK(o4->SetPrototype(o3));
9769 CHECK(o3->SetPrototype(o2));
9770 CHECK(o2->SetPrototype(o1));
9772 // Call the runtime version of GetLocalPropertyNames() on the natively
9773 // created object through JavaScript.
9774 context->Global()->Set(v8_str("obj"), o4);
9775 CompileRun("var names = %GetLocalPropertyNames(obj, true);");
9777 ExpectInt32("names.length", 1006);
9778 ExpectTrue("names.indexOf(\"baz\") >= 0");
9779 ExpectTrue("names.indexOf(\"boo\") >= 0");
9780 ExpectTrue("names.indexOf(\"foo\") >= 0");
9781 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9782 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9783 ExpectFalse("names[1005] == undefined");
9787 THREADED_TEST(FunctionReadOnlyPrototype) {
9788 LocalContext context;
9789 v8::HandleScope handle_scope(context->GetIsolate());
9791 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9792 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9793 t1->ReadOnlyPrototype();
9794 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9795 // Configured value of ReadOnly flag.
9798 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9799 " return (descriptor['writable'] == false);"
9800 "})()")->BooleanValue());
9801 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9803 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9805 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9806 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9807 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9808 // Default value of ReadOnly flag.
9811 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9812 " return (descriptor['writable'] == true);"
9813 "})()")->BooleanValue());
9814 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9818 THREADED_TEST(SetPrototypeThrows) {
9819 LocalContext context;
9820 v8::HandleScope handle_scope(context->GetIsolate());
9822 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9824 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9825 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9827 CHECK(o0->SetPrototype(o1));
9828 // If setting the prototype leads to the cycle, SetPrototype should
9829 // return false and keep VM in sane state.
9830 v8::TryCatch try_catch;
9831 CHECK(!o1->SetPrototype(o0));
9832 CHECK(!try_catch.HasCaught());
9833 ASSERT(!CcTest::i_isolate()->has_pending_exception());
9835 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9839 THREADED_TEST(FunctionRemovePrototype) {
9840 LocalContext context;
9841 v8::HandleScope handle_scope(context->GetIsolate());
9843 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9844 t1->RemovePrototype();
9845 Local<v8::Function> fun = t1->GetFunction();
9846 context->Global()->Set(v8_str("fun"), fun);
9847 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9849 v8::TryCatch try_catch;
9850 CompileRun("new fun()");
9851 CHECK(try_catch.HasCaught());
9855 CHECK(try_catch.HasCaught());
9859 THREADED_TEST(GetterSetterExceptions) {
9860 LocalContext context;
9861 v8::HandleScope handle_scope(context->GetIsolate());
9863 "function Foo() { };"
9864 "function Throw() { throw 5; };"
9866 "x.__defineSetter__('set', Throw);"
9867 "x.__defineGetter__('get', Throw);");
9868 Local<v8::Object> x =
9869 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9870 v8::TryCatch try_catch;
9871 x->Set(v8_str("set"), v8::Integer::New(8));
9872 x->Get(v8_str("get"));
9873 x->Set(v8_str("set"), v8::Integer::New(8));
9874 x->Get(v8_str("get"));
9875 x->Set(v8_str("set"), v8::Integer::New(8));
9876 x->Get(v8_str("get"));
9877 x->Set(v8_str("set"), v8::Integer::New(8));
9878 x->Get(v8_str("get"));
9882 THREADED_TEST(Constructor) {
9883 LocalContext context;
9884 v8::HandleScope handle_scope(context->GetIsolate());
9885 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9886 templ->SetClassName(v8_str("Fun"));
9887 Local<Function> cons = templ->GetFunction();
9888 context->Global()->Set(v8_str("Fun"), cons);
9889 Local<v8::Object> inst = cons->NewInstance();
9890 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9891 CHECK(obj->IsJSObject());
9892 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9893 CHECK(value->BooleanValue());
9897 static void ConstructorCallback(
9898 const v8::FunctionCallbackInfo<v8::Value>& args) {
9899 ApiTestFuzzer::Fuzz();
9902 if (args.IsConstructCall()) {
9903 Local<Object> Holder = args.Holder();
9904 This = Object::New();
9905 Local<Value> proto = Holder->GetPrototype();
9906 if (proto->IsObject()) {
9907 This->SetPrototype(proto);
9913 This->Set(v8_str("a"), args[0]);
9914 args.GetReturnValue().Set(This);
9918 static void FakeConstructorCallback(
9919 const v8::FunctionCallbackInfo<v8::Value>& args) {
9920 ApiTestFuzzer::Fuzz();
9921 args.GetReturnValue().Set(args[0]);
9925 THREADED_TEST(ConstructorForObject) {
9926 LocalContext context;
9927 v8::Isolate* isolate = context->GetIsolate();
9928 v8::HandleScope handle_scope(isolate);
9930 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9931 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9932 Local<Object> instance = instance_template->NewInstance();
9933 context->Global()->Set(v8_str("obj"), instance);
9934 v8::TryCatch try_catch;
9936 CHECK(!try_catch.HasCaught());
9938 // Call the Object's constructor with a 32-bit signed integer.
9939 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9940 CHECK(!try_catch.HasCaught());
9941 CHECK(value->IsInt32());
9942 CHECK_EQ(28, value->Int32Value());
9944 Local<Value> args1[] = { v8_num(28) };
9945 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9946 CHECK(value_obj1->IsObject());
9947 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9948 value = object1->Get(v8_str("a"));
9949 CHECK(value->IsInt32());
9950 CHECK(!try_catch.HasCaught());
9951 CHECK_EQ(28, value->Int32Value());
9953 // Call the Object's constructor with a String.
9955 "(function() { var o = new obj('tipli'); return o.a; })()");
9956 CHECK(!try_catch.HasCaught());
9957 CHECK(value->IsString());
9958 String::Utf8Value string_value1(value->ToString());
9959 CHECK_EQ("tipli", *string_value1);
9961 Local<Value> args2[] = { v8_str("tipli") };
9962 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9963 CHECK(value_obj2->IsObject());
9964 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9965 value = object2->Get(v8_str("a"));
9966 CHECK(!try_catch.HasCaught());
9967 CHECK(value->IsString());
9968 String::Utf8Value string_value2(value->ToString());
9969 CHECK_EQ("tipli", *string_value2);
9971 // Call the Object's constructor with a Boolean.
9972 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9973 CHECK(!try_catch.HasCaught());
9974 CHECK(value->IsBoolean());
9975 CHECK_EQ(true, value->BooleanValue());
9977 Handle<Value> args3[] = { v8::True(isolate) };
9978 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9979 CHECK(value_obj3->IsObject());
9980 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9981 value = object3->Get(v8_str("a"));
9982 CHECK(!try_catch.HasCaught());
9983 CHECK(value->IsBoolean());
9984 CHECK_EQ(true, value->BooleanValue());
9986 // Call the Object's constructor with undefined.
9987 Handle<Value> args4[] = { v8::Undefined(isolate) };
9988 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9989 CHECK(value_obj4->IsObject());
9990 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9991 value = object4->Get(v8_str("a"));
9992 CHECK(!try_catch.HasCaught());
9993 CHECK(value->IsUndefined());
9995 // Call the Object's constructor with null.
9996 Handle<Value> args5[] = { v8::Null(isolate) };
9997 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9998 CHECK(value_obj5->IsObject());
9999 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10000 value = object5->Get(v8_str("a"));
10001 CHECK(!try_catch.HasCaught());
10002 CHECK(value->IsNull());
10005 // Check exception handling when there is no constructor set for the Object.
10006 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10007 Local<Object> instance = instance_template->NewInstance();
10008 context->Global()->Set(v8_str("obj2"), instance);
10009 v8::TryCatch try_catch;
10010 Local<Value> value;
10011 CHECK(!try_catch.HasCaught());
10013 value = CompileRun("new obj2(28)");
10014 CHECK(try_catch.HasCaught());
10015 String::Utf8Value exception_value1(try_catch.Exception());
10016 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10019 Local<Value> args[] = { v8_num(29) };
10020 value = instance->CallAsConstructor(1, args);
10021 CHECK(try_catch.HasCaught());
10022 String::Utf8Value exception_value2(try_catch.Exception());
10023 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10027 // Check the case when constructor throws exception.
10028 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10029 instance_template->SetCallAsFunctionHandler(ThrowValue);
10030 Local<Object> instance = instance_template->NewInstance();
10031 context->Global()->Set(v8_str("obj3"), instance);
10032 v8::TryCatch try_catch;
10033 Local<Value> value;
10034 CHECK(!try_catch.HasCaught());
10036 value = CompileRun("new obj3(22)");
10037 CHECK(try_catch.HasCaught());
10038 String::Utf8Value exception_value1(try_catch.Exception());
10039 CHECK_EQ("22", *exception_value1);
10042 Local<Value> args[] = { v8_num(23) };
10043 value = instance->CallAsConstructor(1, args);
10044 CHECK(try_catch.HasCaught());
10045 String::Utf8Value exception_value2(try_catch.Exception());
10046 CHECK_EQ("23", *exception_value2);
10050 // Check whether constructor returns with an object or non-object.
10051 { Local<FunctionTemplate> function_template =
10052 FunctionTemplate::New(FakeConstructorCallback);
10053 Local<Function> function = function_template->GetFunction();
10054 Local<Object> instance1 = function;
10055 context->Global()->Set(v8_str("obj4"), instance1);
10056 v8::TryCatch try_catch;
10057 Local<Value> value;
10058 CHECK(!try_catch.HasCaught());
10060 CHECK(instance1->IsObject());
10061 CHECK(instance1->IsFunction());
10063 value = CompileRun("new obj4(28)");
10064 CHECK(!try_catch.HasCaught());
10065 CHECK(value->IsObject());
10067 Local<Value> args1[] = { v8_num(28) };
10068 value = instance1->CallAsConstructor(1, args1);
10069 CHECK(!try_catch.HasCaught());
10070 CHECK(value->IsObject());
10072 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10073 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10074 Local<Object> instance2 = instance_template->NewInstance();
10075 context->Global()->Set(v8_str("obj5"), instance2);
10076 CHECK(!try_catch.HasCaught());
10078 CHECK(instance2->IsObject());
10079 CHECK(!instance2->IsFunction());
10081 value = CompileRun("new obj5(28)");
10082 CHECK(!try_catch.HasCaught());
10083 CHECK(!value->IsObject());
10085 Local<Value> args2[] = { v8_num(28) };
10086 value = instance2->CallAsConstructor(1, args2);
10087 CHECK(!try_catch.HasCaught());
10088 CHECK(!value->IsObject());
10093 THREADED_TEST(FunctionDescriptorException) {
10094 LocalContext context;
10095 v8::HandleScope handle_scope(context->GetIsolate());
10096 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10097 templ->SetClassName(v8_str("Fun"));
10098 Local<Function> cons = templ->GetFunction();
10099 context->Global()->Set(v8_str("Fun"), cons);
10100 Local<Value> value = CompileRun(
10101 "function test() {"
10103 " (new Fun()).blah()"
10105 " var str = String(e);"
10106 " if (str.indexOf('TypeError') == -1) return 1;"
10107 " if (str.indexOf('[object Fun]') != -1) return 2;"
10108 " if (str.indexOf('#<Fun>') == -1) return 3;"
10114 CHECK_EQ(0, value->Int32Value());
10118 THREADED_TEST(EvalAliasedDynamic) {
10119 LocalContext current;
10120 v8::HandleScope scope(current->GetIsolate());
10122 // Tests where aliased eval can only be resolved dynamically.
10123 Local<Script> script =
10124 Script::Compile(v8_str("function f(x) { "
10126 " with (x) { return eval('foo'); }"
10129 "result1 = f(new Object());"
10130 "result2 = f(this);"
10131 "var x = new Object();"
10132 "x.eval = function(x) { return 1; };"
10133 "result3 = f(x);"));
10135 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10136 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10137 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10139 v8::TryCatch try_catch;
10141 Script::Compile(v8_str("function f(x) { "
10143 " with (x) { return eval('bar'); }"
10145 "result4 = f(this)"));
10147 CHECK(!try_catch.HasCaught());
10148 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10154 THREADED_TEST(CrossEval) {
10155 v8::HandleScope scope(CcTest::isolate());
10156 LocalContext other;
10157 LocalContext current;
10159 Local<String> token = v8_str("<security token>");
10160 other->SetSecurityToken(token);
10161 current->SetSecurityToken(token);
10163 // Set up reference from current to other.
10164 current->Global()->Set(v8_str("other"), other->Global());
10166 // Check that new variables are introduced in other context.
10167 Local<Script> script =
10168 Script::Compile(v8_str("other.eval('var foo = 1234')"));
10170 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10171 CHECK_EQ(1234, foo->Int32Value());
10172 CHECK(!current->Global()->Has(v8_str("foo")));
10174 // Check that writing to non-existing properties introduces them in
10175 // the other context.
10177 Script::Compile(v8_str("other.eval('na = 1234')"));
10179 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10180 CHECK(!current->Global()->Has(v8_str("na")));
10182 // Check that global variables in current context are not visible in other
10184 v8::TryCatch try_catch;
10186 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10187 Local<Value> result = script->Run();
10188 CHECK(try_catch.HasCaught());
10191 // Check that local variables in current context are not visible in other
10194 Script::Compile(v8_str("(function() { "
10196 " return other.eval('baz');"
10198 result = script->Run();
10199 CHECK(try_catch.HasCaught());
10202 // Check that global variables in the other environment are visible
10203 // when evaluting code.
10204 other->Global()->Set(v8_str("bis"), v8_num(1234));
10205 script = Script::Compile(v8_str("other.eval('bis')"));
10206 CHECK_EQ(1234, script->Run()->Int32Value());
10207 CHECK(!try_catch.HasCaught());
10209 // Check that the 'this' pointer points to the global object evaluating
10211 other->Global()->Set(v8_str("t"), other->Global());
10212 script = Script::Compile(v8_str("other.eval('this == t')"));
10213 result = script->Run();
10214 CHECK(result->IsTrue());
10215 CHECK(!try_catch.HasCaught());
10217 // Check that variables introduced in with-statement are not visible in
10220 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10221 result = script->Run();
10222 CHECK(try_catch.HasCaught());
10225 // Check that you cannot use 'eval.call' with another object than the
10226 // current global object.
10228 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10229 result = script->Run();
10230 CHECK(try_catch.HasCaught());
10234 // Test that calling eval in a context which has been detached from
10235 // its global throws an exception. This behavior is consistent with
10236 // other JavaScript implementations.
10237 THREADED_TEST(EvalInDetachedGlobal) {
10238 v8::Isolate* isolate = CcTest::isolate();
10239 v8::HandleScope scope(isolate);
10241 v8::Local<Context> context0 = Context::New(isolate);
10242 v8::Local<Context> context1 = Context::New(isolate);
10244 // Set up function in context0 that uses eval from context0.
10246 v8::Handle<v8::Value> fun =
10247 CompileRun("var x = 42;"
10250 " return function(s) { return e(s); }"
10254 // Put the function into context1 and call it before and after
10255 // detaching the global. Before detaching, the call succeeds and
10256 // after detaching and exception is thrown.
10258 context1->Global()->Set(v8_str("fun"), fun);
10259 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10260 CHECK_EQ(42, x_value->Int32Value());
10261 context0->DetachGlobal();
10262 v8::TryCatch catcher;
10263 x_value = CompileRun("fun('x')");
10264 CHECK(x_value.IsEmpty());
10265 CHECK(catcher.HasCaught());
10270 THREADED_TEST(CrossLazyLoad) {
10271 v8::HandleScope scope(CcTest::isolate());
10272 LocalContext other;
10273 LocalContext current;
10275 Local<String> token = v8_str("<security token>");
10276 other->SetSecurityToken(token);
10277 current->SetSecurityToken(token);
10279 // Set up reference from current to other.
10280 current->Global()->Set(v8_str("other"), other->Global());
10282 // Trigger lazy loading in other context.
10283 Local<Script> script =
10284 Script::Compile(v8_str("other.eval('new Date(42)')"));
10285 Local<Value> value = script->Run();
10286 CHECK_EQ(42.0, value->NumberValue());
10290 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10291 ApiTestFuzzer::Fuzz();
10292 if (args.IsConstructCall()) {
10293 if (args[0]->IsInt32()) {
10294 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10299 args.GetReturnValue().Set(args[0]);
10303 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10304 args.GetReturnValue().Set(args.This());
10308 // Test that a call handler can be set for objects which will allow
10309 // non-function objects created through the API to be called as
10311 THREADED_TEST(CallAsFunction) {
10312 LocalContext context;
10313 v8::HandleScope scope(context->GetIsolate());
10315 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10316 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10317 instance_template->SetCallAsFunctionHandler(call_as_function);
10318 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10319 context->Global()->Set(v8_str("obj"), instance);
10320 v8::TryCatch try_catch;
10321 Local<Value> value;
10322 CHECK(!try_catch.HasCaught());
10324 value = CompileRun("obj(42)");
10325 CHECK(!try_catch.HasCaught());
10326 CHECK_EQ(42, value->Int32Value());
10328 value = CompileRun("(function(o){return o(49)})(obj)");
10329 CHECK(!try_catch.HasCaught());
10330 CHECK_EQ(49, value->Int32Value());
10332 // test special case of call as function
10333 value = CompileRun("[obj]['0'](45)");
10334 CHECK(!try_catch.HasCaught());
10335 CHECK_EQ(45, value->Int32Value());
10337 value = CompileRun("obj.call = Function.prototype.call;"
10338 "obj.call(null, 87)");
10339 CHECK(!try_catch.HasCaught());
10340 CHECK_EQ(87, value->Int32Value());
10342 // Regression tests for bug #1116356: Calling call through call/apply
10343 // must work for non-function receivers.
10344 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10345 value = CompileRun(apply_99);
10346 CHECK(!try_catch.HasCaught());
10347 CHECK_EQ(99, value->Int32Value());
10349 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10350 value = CompileRun(call_17);
10351 CHECK(!try_catch.HasCaught());
10352 CHECK_EQ(17, value->Int32Value());
10354 // Check that the call-as-function handler can be called through
10356 value = CompileRun("new obj(43)");
10357 CHECK(!try_catch.HasCaught());
10358 CHECK_EQ(-43, value->Int32Value());
10360 // Check that the call-as-function handler can be called through
10362 v8::Handle<Value> args[] = { v8_num(28) };
10363 value = instance->CallAsFunction(instance, 1, args);
10364 CHECK(!try_catch.HasCaught());
10365 CHECK_EQ(28, value->Int32Value());
10368 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10369 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10370 USE(instance_template);
10371 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10372 context->Global()->Set(v8_str("obj2"), instance);
10373 v8::TryCatch try_catch;
10374 Local<Value> value;
10375 CHECK(!try_catch.HasCaught());
10377 // Call an object without call-as-function handler through the JS
10378 value = CompileRun("obj2(28)");
10379 CHECK(value.IsEmpty());
10380 CHECK(try_catch.HasCaught());
10381 String::Utf8Value exception_value1(try_catch.Exception());
10382 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
10383 *exception_value1);
10386 // Call an object without call-as-function handler through the API
10387 value = CompileRun("obj2(28)");
10388 v8::Handle<Value> args[] = { v8_num(28) };
10389 value = instance->CallAsFunction(instance, 1, args);
10390 CHECK(value.IsEmpty());
10391 CHECK(try_catch.HasCaught());
10392 String::Utf8Value exception_value2(try_catch.Exception());
10393 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10397 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10398 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10399 instance_template->SetCallAsFunctionHandler(ThrowValue);
10400 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10401 context->Global()->Set(v8_str("obj3"), instance);
10402 v8::TryCatch try_catch;
10403 Local<Value> value;
10404 CHECK(!try_catch.HasCaught());
10406 // Catch the exception which is thrown by call-as-function handler
10407 value = CompileRun("obj3(22)");
10408 CHECK(try_catch.HasCaught());
10409 String::Utf8Value exception_value1(try_catch.Exception());
10410 CHECK_EQ("22", *exception_value1);
10413 v8::Handle<Value> args[] = { v8_num(23) };
10414 value = instance->CallAsFunction(instance, 1, args);
10415 CHECK(try_catch.HasCaught());
10416 String::Utf8Value exception_value2(try_catch.Exception());
10417 CHECK_EQ("23", *exception_value2);
10421 { v8::Isolate* isolate = context->GetIsolate();
10422 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10423 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10424 instance_template->SetCallAsFunctionHandler(ReturnThis);
10425 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10427 Local<v8::Value> a1 =
10428 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10429 CHECK(a1->StrictEquals(instance));
10430 Local<v8::Value> a2 =
10431 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10432 CHECK(a2->StrictEquals(instance));
10433 Local<v8::Value> a3 =
10434 instance->CallAsFunction(v8_num(42), 0, NULL);
10435 CHECK(a3->StrictEquals(instance));
10436 Local<v8::Value> a4 =
10437 instance->CallAsFunction(v8_str("hello"), 0, NULL);
10438 CHECK(a4->StrictEquals(instance));
10439 Local<v8::Value> a5 =
10440 instance->CallAsFunction(v8::True(isolate), 0, NULL);
10441 CHECK(a5->StrictEquals(instance));
10444 { v8::Isolate* isolate = context->GetIsolate();
10446 "function ReturnThisSloppy() {"
10449 "function ReturnThisStrict() {"
10453 Local<Function> ReturnThisSloppy =
10454 Local<Function>::Cast(
10455 context->Global()->Get(v8_str("ReturnThisSloppy")));
10456 Local<Function> ReturnThisStrict =
10457 Local<Function>::Cast(
10458 context->Global()->Get(v8_str("ReturnThisStrict")));
10460 Local<v8::Value> a1 =
10461 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10462 CHECK(a1->StrictEquals(context->Global()));
10463 Local<v8::Value> a2 =
10464 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10465 CHECK(a2->StrictEquals(context->Global()));
10466 Local<v8::Value> a3 =
10467 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10468 CHECK(a3->IsNumberObject());
10469 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10470 Local<v8::Value> a4 =
10471 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10472 CHECK(a4->IsStringObject());
10473 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10474 Local<v8::Value> a5 =
10475 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10476 CHECK(a5->IsBooleanObject());
10477 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10479 Local<v8::Value> a6 =
10480 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10481 CHECK(a6->IsUndefined());
10482 Local<v8::Value> a7 =
10483 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10484 CHECK(a7->IsNull());
10485 Local<v8::Value> a8 =
10486 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10487 CHECK(a8->StrictEquals(v8_num(42)));
10488 Local<v8::Value> a9 =
10489 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10490 CHECK(a9->StrictEquals(v8_str("hello")));
10491 Local<v8::Value> a10 =
10492 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10493 CHECK(a10->StrictEquals(v8::True(isolate)));
10498 // Check whether a non-function object is callable.
10499 THREADED_TEST(CallableObject) {
10500 LocalContext context;
10501 v8::HandleScope scope(context->GetIsolate());
10503 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10504 instance_template->SetCallAsFunctionHandler(call_as_function);
10505 Local<Object> instance = instance_template->NewInstance();
10506 v8::TryCatch try_catch;
10508 CHECK(instance->IsCallable());
10509 CHECK(!try_catch.HasCaught());
10512 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10513 Local<Object> instance = instance_template->NewInstance();
10514 v8::TryCatch try_catch;
10516 CHECK(!instance->IsCallable());
10517 CHECK(!try_catch.HasCaught());
10520 { Local<FunctionTemplate> function_template =
10521 FunctionTemplate::New(call_as_function);
10522 Local<Function> function = function_template->GetFunction();
10523 Local<Object> instance = function;
10524 v8::TryCatch try_catch;
10526 CHECK(instance->IsCallable());
10527 CHECK(!try_catch.HasCaught());
10530 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
10531 Local<Function> function = function_template->GetFunction();
10532 Local<Object> instance = function;
10533 v8::TryCatch try_catch;
10535 CHECK(instance->IsCallable());
10536 CHECK(!try_catch.HasCaught());
10541 static int CountHandles() {
10542 return v8::HandleScope::NumberOfHandles();
10546 static int Recurse(int depth, int iterations) {
10547 v8::HandleScope scope(CcTest::isolate());
10548 if (depth == 0) return CountHandles();
10549 for (int i = 0; i < iterations; i++) {
10550 Local<v8::Number> n(v8::Integer::New(42));
10552 return Recurse(depth - 1, iterations);
10556 THREADED_TEST(HandleIteration) {
10557 static const int kIterations = 500;
10558 static const int kNesting = 200;
10559 CHECK_EQ(0, CountHandles());
10561 v8::HandleScope scope1(CcTest::isolate());
10562 CHECK_EQ(0, CountHandles());
10563 for (int i = 0; i < kIterations; i++) {
10564 Local<v8::Number> n(v8::Integer::New(42));
10565 CHECK_EQ(i + 1, CountHandles());
10568 CHECK_EQ(kIterations, CountHandles());
10570 v8::HandleScope scope2(CcTest::isolate());
10571 for (int j = 0; j < kIterations; j++) {
10572 Local<v8::Number> n(v8::Integer::New(42));
10573 CHECK_EQ(j + 1 + kIterations, CountHandles());
10576 CHECK_EQ(kIterations, CountHandles());
10578 CHECK_EQ(0, CountHandles());
10579 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
10583 static void InterceptorHasOwnPropertyGetter(
10584 Local<String> name,
10585 const v8::PropertyCallbackInfo<v8::Value>& info) {
10586 ApiTestFuzzer::Fuzz();
10590 THREADED_TEST(InterceptorHasOwnProperty) {
10591 LocalContext context;
10592 v8::HandleScope scope(context->GetIsolate());
10593 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10594 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10595 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
10596 Local<Function> function = fun_templ->GetFunction();
10597 context->Global()->Set(v8_str("constructor"), function);
10598 v8::Handle<Value> value = CompileRun(
10599 "var o = new constructor();"
10600 "o.hasOwnProperty('ostehaps');");
10601 CHECK_EQ(false, value->BooleanValue());
10602 value = CompileRun(
10604 "o.hasOwnProperty('ostehaps');");
10605 CHECK_EQ(true, value->BooleanValue());
10606 value = CompileRun(
10607 "var p = new constructor();"
10608 "p.hasOwnProperty('ostehaps');");
10609 CHECK_EQ(false, value->BooleanValue());
10613 static void InterceptorHasOwnPropertyGetterGC(
10614 Local<String> name,
10615 const v8::PropertyCallbackInfo<v8::Value>& info) {
10616 ApiTestFuzzer::Fuzz();
10617 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
10621 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
10622 LocalContext context;
10623 v8::HandleScope scope(context->GetIsolate());
10624 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10625 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10626 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
10627 Local<Function> function = fun_templ->GetFunction();
10628 context->Global()->Set(v8_str("constructor"), function);
10629 // Let's first make some stuff so we can be sure to get a good GC.
10631 "function makestr(size) {"
10633 " case 1: return 'f';"
10634 " case 2: return 'fo';"
10635 " case 3: return 'foo';"
10637 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
10639 "var x = makestr(12345);"
10640 "x = makestr(31415);"
10641 "x = makestr(23456);");
10642 v8::Handle<Value> value = CompileRun(
10643 "var o = new constructor();"
10644 "o.__proto__ = new String(x);"
10645 "o.hasOwnProperty('ostehaps');");
10646 CHECK_EQ(false, value->BooleanValue());
10650 typedef void (*NamedPropertyGetter)(
10651 Local<String> property,
10652 const v8::PropertyCallbackInfo<v8::Value>& info);
10655 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
10656 const char* source,
10658 v8::HandleScope scope(CcTest::isolate());
10659 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10660 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
10661 LocalContext context;
10662 context->Global()->Set(v8_str("o"), templ->NewInstance());
10663 v8::Handle<Value> value = CompileRun(source);
10664 CHECK_EQ(expected, value->Int32Value());
10668 static void InterceptorLoadICGetter(
10669 Local<String> name,
10670 const v8::PropertyCallbackInfo<v8::Value>& info) {
10671 ApiTestFuzzer::Fuzz();
10672 v8::Isolate* isolate = CcTest::isolate();
10673 CHECK_EQ(isolate, info.GetIsolate());
10674 CHECK_EQ(v8_str("data"), info.Data());
10675 CHECK_EQ(v8_str("x"), name);
10676 info.GetReturnValue().Set(v8::Integer::New(42));
10680 // This test should hit the load IC for the interceptor case.
10681 THREADED_TEST(InterceptorLoadIC) {
10682 CheckInterceptorLoadIC(InterceptorLoadICGetter,
10684 "for (var i = 0; i < 1000; i++) {"
10691 // Below go several tests which verify that JITing for various
10692 // configurations of interceptor and explicit fields works fine
10693 // (those cases are special cased to get better performance).
10695 static void InterceptorLoadXICGetter(
10696 Local<String> name,
10697 const v8::PropertyCallbackInfo<v8::Value>& info) {
10698 ApiTestFuzzer::Fuzz();
10699 info.GetReturnValue().Set(
10700 v8_str("x")->Equals(name) ?
10701 v8::Handle<v8::Value>(v8::Integer::New(42)) :
10702 v8::Handle<v8::Value>());
10706 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
10707 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10710 "for (var i = 0; i < 1000; i++) {"
10717 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
10718 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10720 "o.__proto__ = { 'y': 239 };"
10721 "for (var i = 0; i < 1000; i++) {"
10722 " result = o.y + o.x;"
10728 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
10729 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10731 "o.__proto__.y = 239;"
10732 "for (var i = 0; i < 1000; i++) {"
10733 " result = o.y + o.x;"
10739 THREADED_TEST(InterceptorLoadICUndefined) {
10740 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10742 "for (var i = 0; i < 1000; i++) {"
10743 " result = (o.y == undefined) ? 239 : 42;"
10749 THREADED_TEST(InterceptorLoadICWithOverride) {
10750 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10751 "fst = new Object(); fst.__proto__ = o;"
10752 "snd = new Object(); snd.__proto__ = fst;"
10754 "for (var i = 0; i < 1000; i++) {"
10755 " result1 = snd.x;"
10759 "for (var i = 0; i < 1000; i++) {"
10762 "result + result1",
10767 // Test the case when we stored field into
10768 // a stub, but interceptor produced value on its own.
10769 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
10770 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10771 "proto = new Object();"
10772 "o.__proto__ = proto;"
10774 "for (var i = 0; i < 1000; i++) {"
10776 // Now it should be ICed and keep a reference to x defined on proto
10779 "for (var i = 0; i < 1000; i++) {"
10787 // Test the case when we stored field into
10788 // a stub, but it got invalidated later on.
10789 THREADED_TEST(InterceptorLoadICInvalidatedField) {
10790 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10791 "proto1 = new Object();"
10792 "proto2 = new Object();"
10793 "o.__proto__ = proto1;"
10794 "proto1.__proto__ = proto2;"
10796 "for (var i = 0; i < 1000; i++) {"
10798 // Now it should be ICed and keep a reference to y defined on proto2
10802 "for (var i = 0; i < 1000; i++) {"
10810 static int interceptor_load_not_handled_calls = 0;
10811 static void InterceptorLoadNotHandled(
10812 Local<String> name,
10813 const v8::PropertyCallbackInfo<v8::Value>& info) {
10814 ++interceptor_load_not_handled_calls;
10818 // Test how post-interceptor lookups are done in the non-cacheable
10819 // case: the interceptor should not be invoked during this lookup.
10820 THREADED_TEST(InterceptorLoadICPostInterceptor) {
10821 interceptor_load_not_handled_calls = 0;
10822 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
10823 "receiver = new Object();"
10824 "receiver.__proto__ = o;"
10825 "proto = new Object();"
10826 "/* Make proto a slow-case object. */"
10827 "for (var i = 0; i < 1000; i++) {"
10828 " proto[\"xxxxxxxx\" + i] = [];"
10831 "o.__proto__ = proto;"
10833 "for (var i = 0; i < 1000; i++) {"
10834 " result += receiver.x;"
10838 CHECK_EQ(1000, interceptor_load_not_handled_calls);
10842 // Test the case when we stored field into
10843 // a stub, but it got invalidated later on due to override on
10844 // global object which is between interceptor and fields' holders.
10845 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
10846 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10847 "o.__proto__ = this;" // set a global to be a proto of o.
10848 "this.__proto__.y = 239;"
10849 "for (var i = 0; i < 10; i++) {"
10850 " if (o.y != 239) throw 'oops: ' + o.y;"
10851 // Now it should be ICed and keep a reference to y defined on field_holder.
10853 "this.y = 42;" // Assign on a global.
10855 "for (var i = 0; i < 10; i++) {"
10863 static void SetOnThis(Local<String> name,
10864 Local<Value> value,
10865 const v8::PropertyCallbackInfo<void>& info) {
10866 info.This()->ForceSet(name, value);
10870 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
10871 v8::HandleScope scope(CcTest::isolate());
10872 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10873 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10874 templ->SetAccessor(v8_str("y"), Return239Callback);
10875 LocalContext context;
10876 context->Global()->Set(v8_str("o"), templ->NewInstance());
10878 // Check the case when receiver and interceptor's holder
10879 // are the same objects.
10880 v8::Handle<Value> value = CompileRun(
10882 "for (var i = 0; i < 7; i++) {"
10885 CHECK_EQ(239, value->Int32Value());
10887 // Check the case when interceptor's holder is in proto chain
10889 value = CompileRun(
10890 "r = { __proto__: o };"
10892 "for (var i = 0; i < 7; i++) {"
10895 CHECK_EQ(239, value->Int32Value());
10899 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
10900 v8::HandleScope scope(CcTest::isolate());
10901 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10902 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10903 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10904 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10906 LocalContext context;
10907 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10908 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10910 // Check the case when receiver and interceptor's holder
10911 // are the same objects.
10912 v8::Handle<Value> value = CompileRun(
10915 "for (var i = 0; i < 7; i++) {"
10916 " result = o.x + o.y;"
10918 CHECK_EQ(239 + 42, value->Int32Value());
10920 // Check the case when interceptor's holder is in proto chain
10922 value = CompileRun(
10923 "r = { __proto__: o };"
10925 "for (var i = 0; i < 7; i++) {"
10926 " result = r.x + r.y;"
10928 CHECK_EQ(239 + 42, value->Int32Value());
10932 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
10933 v8::HandleScope scope(CcTest::isolate());
10934 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10935 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10936 templ->SetAccessor(v8_str("y"), Return239Callback);
10938 LocalContext context;
10939 context->Global()->Set(v8_str("o"), templ->NewInstance());
10941 v8::Handle<Value> value = CompileRun(
10942 "fst = new Object(); fst.__proto__ = o;"
10943 "snd = new Object(); snd.__proto__ = fst;"
10945 "for (var i = 0; i < 7; i++) {"
10946 " result1 = snd.x;"
10950 "for (var i = 0; i < 7; i++) {"
10953 "result + result1");
10954 CHECK_EQ(239 + 42, value->Int32Value());
10958 // Test the case when we stored callback into
10959 // a stub, but interceptor produced value on its own.
10960 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
10961 v8::HandleScope scope(CcTest::isolate());
10962 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10963 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10964 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10965 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10967 LocalContext context;
10968 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10969 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10971 v8::Handle<Value> value = CompileRun(
10973 "for (var i = 0; i < 7; i++) {"
10975 // Now it should be ICed and keep a reference to x defined on p
10978 "for (var i = 0; i < 7; i++) {"
10982 CHECK_EQ(42 * 7, value->Int32Value());
10986 // Test the case when we stored callback into
10987 // a stub, but it got invalidated later on.
10988 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
10989 v8::HandleScope scope(CcTest::isolate());
10990 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10991 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10992 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10993 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10995 LocalContext context;
10996 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10997 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10999 v8::Handle<Value> value = CompileRun(
11000 "inbetween = new Object();"
11001 "o.__proto__ = inbetween;"
11002 "inbetween.__proto__ = p;"
11003 "for (var i = 0; i < 10; i++) {"
11005 // Now it should be ICed and keep a reference to y defined on p
11007 "inbetween.y = 42;"
11009 "for (var i = 0; i < 10; i++) {"
11013 CHECK_EQ(42 * 10, value->Int32Value());
11017 // Test the case when we stored callback into
11018 // a stub, but it got invalidated later on due to override on
11019 // global object which is between interceptor and callbacks' holders.
11020 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11021 v8::HandleScope scope(CcTest::isolate());
11022 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11023 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11024 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
11025 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11027 LocalContext context;
11028 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11029 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11031 v8::Handle<Value> value = CompileRun(
11032 "o.__proto__ = this;"
11033 "this.__proto__ = p;"
11034 "for (var i = 0; i < 10; i++) {"
11035 " if (o.y != 239) throw 'oops: ' + o.y;"
11036 // Now it should be ICed and keep a reference to y defined on p
11040 "for (var i = 0; i < 10; i++) {"
11044 CHECK_EQ(42 * 10, value->Int32Value());
11048 static void InterceptorLoadICGetter0(
11049 Local<String> name,
11050 const v8::PropertyCallbackInfo<v8::Value>& info) {
11051 ApiTestFuzzer::Fuzz();
11052 CHECK(v8_str("x")->Equals(name));
11053 info.GetReturnValue().Set(v8::Integer::New(0));
11057 THREADED_TEST(InterceptorReturningZero) {
11058 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11059 "o.x == undefined ? 1 : 0",
11064 static void InterceptorStoreICSetter(
11066 Local<Value> value,
11067 const v8::PropertyCallbackInfo<v8::Value>& info) {
11068 CHECK(v8_str("x")->Equals(key));
11069 CHECK_EQ(42, value->Int32Value());
11070 info.GetReturnValue().Set(value);
11074 // This test should hit the store IC for the interceptor case.
11075 THREADED_TEST(InterceptorStoreIC) {
11076 v8::HandleScope scope(CcTest::isolate());
11077 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11078 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11079 InterceptorStoreICSetter,
11080 0, 0, 0, v8_str("data"));
11081 LocalContext context;
11082 context->Global()->Set(v8_str("o"), templ->NewInstance());
11084 "for (var i = 0; i < 1000; i++) {"
11090 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11091 v8::HandleScope scope(CcTest::isolate());
11092 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11093 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11094 LocalContext context;
11095 context->Global()->Set(v8_str("o"), templ->NewInstance());
11096 v8::Handle<Value> value = CompileRun(
11097 "for (var i = 0; i < 1000; i++) {"
11101 CHECK_EQ(239 + 42, value->Int32Value());
11107 v8::Handle<Value> call_ic_function;
11108 v8::Handle<Value> call_ic_function2;
11109 v8::Handle<Value> call_ic_function3;
11111 static void InterceptorCallICGetter(
11112 Local<String> name,
11113 const v8::PropertyCallbackInfo<v8::Value>& info) {
11114 ApiTestFuzzer::Fuzz();
11115 CHECK(v8_str("x")->Equals(name));
11116 info.GetReturnValue().Set(call_ic_function);
11120 // This test should hit the call IC for the interceptor case.
11121 THREADED_TEST(InterceptorCallIC) {
11122 v8::HandleScope scope(CcTest::isolate());
11123 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11124 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11125 LocalContext context;
11126 context->Global()->Set(v8_str("o"), templ->NewInstance());
11128 v8_compile("function f(x) { return x + 1; }; f")->Run();
11129 v8::Handle<Value> value = CompileRun(
11131 "for (var i = 0; i < 1000; i++) {"
11132 " result = o.x(41);"
11134 CHECK_EQ(42, value->Int32Value());
11138 // This test checks that if interceptor doesn't provide
11139 // a value, we can fetch regular value.
11140 THREADED_TEST(InterceptorCallICSeesOthers) {
11141 v8::HandleScope scope(CcTest::isolate());
11142 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11143 templ->SetNamedPropertyHandler(NoBlockGetterX);
11144 LocalContext context;
11145 context->Global()->Set(v8_str("o"), templ->NewInstance());
11146 v8::Handle<Value> value = CompileRun(
11147 "o.x = function f(x) { return x + 1; };"
11149 "for (var i = 0; i < 7; i++) {"
11150 " result = o.x(41);"
11152 CHECK_EQ(42, value->Int32Value());
11156 static v8::Handle<Value> call_ic_function4;
11157 static void InterceptorCallICGetter4(
11158 Local<String> name,
11159 const v8::PropertyCallbackInfo<v8::Value>& info) {
11160 ApiTestFuzzer::Fuzz();
11161 CHECK(v8_str("x")->Equals(name));
11162 info.GetReturnValue().Set(call_ic_function4);
11166 // This test checks that if interceptor provides a function,
11167 // even if we cached shadowed variant, interceptor's function
11169 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11170 v8::HandleScope scope(CcTest::isolate());
11171 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11172 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11173 LocalContext context;
11174 context->Global()->Set(v8_str("o"), templ->NewInstance());
11175 call_ic_function4 =
11176 v8_compile("function f(x) { return x - 1; }; f")->Run();
11177 v8::Handle<Value> value = CompileRun(
11178 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11180 "for (var i = 0; i < 1000; i++) {"
11181 " result = o.x(42);"
11183 CHECK_EQ(41, value->Int32Value());
11187 // Test the case when we stored cacheable lookup into
11188 // a stub, but it got invalidated later on
11189 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11190 v8::HandleScope scope(CcTest::isolate());
11191 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11192 templ->SetNamedPropertyHandler(NoBlockGetterX);
11193 LocalContext context;
11194 context->Global()->Set(v8_str("o"), templ->NewInstance());
11195 v8::Handle<Value> value = CompileRun(
11196 "proto1 = new Object();"
11197 "proto2 = new Object();"
11198 "o.__proto__ = proto1;"
11199 "proto1.__proto__ = proto2;"
11200 "proto2.y = function(x) { return x + 1; };"
11201 // Invoke it many times to compile a stub
11202 "for (var i = 0; i < 7; i++) {"
11205 "proto1.y = function(x) { return x - 1; };"
11207 "for (var i = 0; i < 7; i++) {"
11208 " result += o.y(42);"
11210 CHECK_EQ(41 * 7, value->Int32Value());
11214 // This test checks that if interceptor doesn't provide a function,
11215 // cached constant function is used
11216 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11217 v8::HandleScope scope(CcTest::isolate());
11218 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11219 templ->SetNamedPropertyHandler(NoBlockGetterX);
11220 LocalContext context;
11221 context->Global()->Set(v8_str("o"), templ->NewInstance());
11222 v8::Handle<Value> value = CompileRun(
11223 "function inc(x) { return x + 1; };"
11227 "for (var i = 0; i < 1000; i++) {"
11228 " result = o.x(42);"
11230 CHECK_EQ(43, value->Int32Value());
11234 static v8::Handle<Value> call_ic_function5;
11235 static void InterceptorCallICGetter5(
11236 Local<String> name,
11237 const v8::PropertyCallbackInfo<v8::Value>& info) {
11238 ApiTestFuzzer::Fuzz();
11239 if (v8_str("x")->Equals(name))
11240 info.GetReturnValue().Set(call_ic_function5);
11244 // This test checks that if interceptor provides a function,
11245 // even if we cached constant function, interceptor's function
11247 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11248 v8::HandleScope scope(CcTest::isolate());
11249 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11250 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11251 LocalContext context;
11252 context->Global()->Set(v8_str("o"), templ->NewInstance());
11253 call_ic_function5 =
11254 v8_compile("function f(x) { return x - 1; }; f")->Run();
11255 v8::Handle<Value> value = CompileRun(
11256 "function inc(x) { return x + 1; };"
11260 "for (var i = 0; i < 1000; i++) {"
11261 " result = o.x(42);"
11263 CHECK_EQ(41, value->Int32Value());
11267 static v8::Handle<Value> call_ic_function6;
11268 static void InterceptorCallICGetter6(
11269 Local<String> name,
11270 const v8::PropertyCallbackInfo<v8::Value>& info) {
11271 ApiTestFuzzer::Fuzz();
11272 if (v8_str("x")->Equals(name))
11273 info.GetReturnValue().Set(call_ic_function6);
11277 // Same test as above, except the code is wrapped in a function
11278 // to test the optimized compiler.
11279 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11280 i::FLAG_allow_natives_syntax = true;
11281 v8::HandleScope scope(CcTest::isolate());
11282 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11283 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11284 LocalContext context;
11285 context->Global()->Set(v8_str("o"), templ->NewInstance());
11286 call_ic_function6 =
11287 v8_compile("function f(x) { return x - 1; }; f")->Run();
11288 v8::Handle<Value> value = CompileRun(
11289 "function inc(x) { return x + 1; };"
11292 "function test() {"
11294 " for (var i = 0; i < 1000; i++) {"
11295 " result = o.x(42);"
11302 "%OptimizeFunctionOnNextCall(test);"
11304 CHECK_EQ(41, value->Int32Value());
11308 // Test the case when we stored constant function into
11309 // a stub, but it got invalidated later on
11310 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11311 v8::HandleScope scope(CcTest::isolate());
11312 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11313 templ->SetNamedPropertyHandler(NoBlockGetterX);
11314 LocalContext context;
11315 context->Global()->Set(v8_str("o"), templ->NewInstance());
11316 v8::Handle<Value> value = CompileRun(
11317 "function inc(x) { return x + 1; };"
11319 "proto1 = new Object();"
11320 "proto2 = new Object();"
11321 "o.__proto__ = proto1;"
11322 "proto1.__proto__ = proto2;"
11324 // Invoke it many times to compile a stub
11325 "for (var i = 0; i < 7; i++) {"
11328 "proto1.y = function(x) { return x - 1; };"
11330 "for (var i = 0; i < 7; i++) {"
11331 " result += o.y(42);"
11333 CHECK_EQ(41 * 7, value->Int32Value());
11337 // Test the case when we stored constant function into
11338 // a stub, but it got invalidated later on due to override on
11339 // global object which is between interceptor and constant function' holders.
11340 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11341 v8::HandleScope scope(CcTest::isolate());
11342 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11343 templ->SetNamedPropertyHandler(NoBlockGetterX);
11344 LocalContext context;
11345 context->Global()->Set(v8_str("o"), templ->NewInstance());
11346 v8::Handle<Value> value = CompileRun(
11347 "function inc(x) { return x + 1; };"
11349 "o.__proto__ = this;"
11350 "this.__proto__.y = inc;"
11351 // Invoke it many times to compile a stub
11352 "for (var i = 0; i < 7; i++) {"
11353 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11355 "this.y = function(x) { return x - 1; };"
11357 "for (var i = 0; i < 7; i++) {"
11358 " result += o.y(42);"
11360 CHECK_EQ(41 * 7, value->Int32Value());
11364 // Test the case when actual function to call sits on global object.
11365 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11366 v8::HandleScope scope(CcTest::isolate());
11367 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11368 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11370 LocalContext context;
11371 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11373 v8::Handle<Value> value = CompileRun(
11375 " o.__proto__ = this;"
11376 " for (var i = 0; i < 10; i++) {"
11377 " var v = o.parseFloat('239');"
11378 " if (v != 239) throw v;"
11379 // Now it should be ICed and keep a reference to parseFloat.
11382 " for (var i = 0; i < 10; i++) {"
11383 " result += o.parseFloat('239');"
11389 CHECK_EQ(239 * 10, value->Int32Value());
11392 static void InterceptorCallICFastApi(
11393 Local<String> name,
11394 const v8::PropertyCallbackInfo<v8::Value>& info) {
11395 ApiTestFuzzer::Fuzz();
11396 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11398 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11400 if ((*call_count) % 20 == 0) {
11401 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11405 static void FastApiCallback_TrivialSignature(
11406 const v8::FunctionCallbackInfo<v8::Value>& args) {
11407 ApiTestFuzzer::Fuzz();
11408 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11409 v8::Isolate* isolate = CcTest::isolate();
11410 CHECK_EQ(isolate, args.GetIsolate());
11411 CHECK_EQ(args.This(), args.Holder());
11412 CHECK(args.Data()->Equals(v8_str("method_data")));
11413 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11416 static void FastApiCallback_SimpleSignature(
11417 const v8::FunctionCallbackInfo<v8::Value>& args) {
11418 ApiTestFuzzer::Fuzz();
11419 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11420 v8::Isolate* isolate = CcTest::isolate();
11421 CHECK_EQ(isolate, args.GetIsolate());
11422 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11423 CHECK(args.Data()->Equals(v8_str("method_data")));
11424 // Note, we're using HasRealNamedProperty instead of Has to avoid
11425 // invoking the interceptor again.
11426 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11427 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11431 // Helper to maximize the odds of object moving.
11432 static void GenerateSomeGarbage() {
11435 "for (var i = 0; i < 1000; i++) {"
11436 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11438 "garbage = undefined;");
11442 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11443 static int count = 0;
11444 if (count++ % 3 == 0) {
11445 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11446 // This should move the stub
11447 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
11452 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11453 LocalContext context;
11454 v8::HandleScope scope(context->GetIsolate());
11455 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11456 nativeobject_templ->Set("callback",
11457 v8::FunctionTemplate::New(DirectApiCallback));
11458 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11459 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11460 // call the api function multiple times to ensure direct call stub creation.
11463 " for (var i = 1; i <= 30; i++) {"
11464 " nativeobject.callback();"
11471 void ThrowingDirectApiCallback(
11472 const v8::FunctionCallbackInfo<v8::Value>& args) {
11473 args.GetIsolate()->ThrowException(v8_str("g"));
11477 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11478 LocalContext context;
11479 v8::HandleScope scope(context->GetIsolate());
11480 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11481 nativeobject_templ->Set("callback",
11482 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
11483 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11484 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11485 // call the api function multiple times to ensure direct call stub creation.
11486 v8::Handle<Value> result = CompileRun(
11489 " for (var i = 1; i <= 5; i++) {"
11490 " try { nativeobject.callback(); } catch (e) { result += e; }"
11494 CHECK_EQ(v8_str("ggggg"), result);
11498 static Handle<Value> DoDirectGetter() {
11499 if (++p_getter_count % 3 == 0) {
11500 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11501 GenerateSomeGarbage();
11503 return v8_str("Direct Getter Result");
11506 static void DirectGetterCallback(
11507 Local<String> name,
11508 const v8::PropertyCallbackInfo<v8::Value>& info) {
11509 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
11510 info.GetReturnValue().Set(DoDirectGetter());
11514 template<typename Accessor>
11515 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
11516 LocalContext context;
11517 v8::HandleScope scope(context->GetIsolate());
11518 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11519 obj->SetAccessor(v8_str("p1"), accessor);
11520 context->Global()->Set(v8_str("o1"), obj->NewInstance());
11521 p_getter_count = 0;
11522 v8::Handle<v8::Value> result = CompileRun(
11524 " for (var i = 0; i < 30; i++) o1.p1;"
11528 CHECK_EQ(v8_str("Direct Getter Result"), result);
11529 CHECK_EQ(31, p_getter_count);
11533 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
11534 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
11538 void ThrowingDirectGetterCallback(
11539 Local<String> name,
11540 const v8::PropertyCallbackInfo<v8::Value>& info) {
11541 info.GetIsolate()->ThrowException(v8_str("g"));
11545 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
11546 LocalContext context;
11547 v8::HandleScope scope(context->GetIsolate());
11548 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11549 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
11550 context->Global()->Set(v8_str("o1"), obj->NewInstance());
11551 v8::Handle<Value> result = CompileRun(
11553 "for (var i = 0; i < 5; i++) {"
11554 " try { o1.p1; } catch (e) { result += e; }"
11557 CHECK_EQ(v8_str("ggggg"), result);
11561 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
11562 int interceptor_call_count = 0;
11563 v8::HandleScope scope(CcTest::isolate());
11564 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11565 v8::Handle<v8::FunctionTemplate> method_templ =
11566 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11567 v8_str("method_data"),
11568 v8::Handle<v8::Signature>());
11569 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11570 proto_templ->Set(v8_str("method"), method_templ);
11571 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11572 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11573 NULL, NULL, NULL, NULL,
11574 v8::External::New(&interceptor_call_count));
11575 LocalContext context;
11576 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11577 GenerateSomeGarbage();
11578 context->Global()->Set(v8_str("o"), fun->NewInstance());
11581 "for (var i = 0; i < 100; i++) {"
11582 " result = o.method(41);"
11584 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11585 CHECK_EQ(100, interceptor_call_count);
11589 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
11590 int interceptor_call_count = 0;
11591 v8::HandleScope scope(CcTest::isolate());
11592 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11593 v8::Handle<v8::FunctionTemplate> method_templ =
11594 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11595 v8_str("method_data"),
11596 v8::Signature::New(fun_templ));
11597 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11598 proto_templ->Set(v8_str("method"), method_templ);
11599 fun_templ->SetHiddenPrototype(true);
11600 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11601 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11602 NULL, NULL, NULL, NULL,
11603 v8::External::New(&interceptor_call_count));
11604 LocalContext context;
11605 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11606 GenerateSomeGarbage();
11607 context->Global()->Set(v8_str("o"), fun->NewInstance());
11610 "var receiver = {};"
11611 "receiver.__proto__ = o;"
11613 "for (var i = 0; i < 100; i++) {"
11614 " result = receiver.method(41);"
11616 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11617 CHECK_EQ(100, interceptor_call_count);
11621 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
11622 int interceptor_call_count = 0;
11623 v8::HandleScope scope(CcTest::isolate());
11624 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11625 v8::Handle<v8::FunctionTemplate> method_templ =
11626 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11627 v8_str("method_data"),
11628 v8::Signature::New(fun_templ));
11629 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11630 proto_templ->Set(v8_str("method"), method_templ);
11631 fun_templ->SetHiddenPrototype(true);
11632 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11633 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11634 NULL, NULL, NULL, NULL,
11635 v8::External::New(&interceptor_call_count));
11636 LocalContext context;
11637 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11638 GenerateSomeGarbage();
11639 context->Global()->Set(v8_str("o"), fun->NewInstance());
11642 "var receiver = {};"
11643 "receiver.__proto__ = o;"
11645 "var saved_result = 0;"
11646 "for (var i = 0; i < 100; i++) {"
11647 " result = receiver.method(41);"
11649 " saved_result = result;"
11650 " receiver = {method: function(x) { return x - 1 }};"
11653 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11654 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11655 CHECK_GE(interceptor_call_count, 50);
11659 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
11660 int interceptor_call_count = 0;
11661 v8::HandleScope scope(CcTest::isolate());
11662 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11663 v8::Handle<v8::FunctionTemplate> method_templ =
11664 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11665 v8_str("method_data"),
11666 v8::Signature::New(fun_templ));
11667 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11668 proto_templ->Set(v8_str("method"), method_templ);
11669 fun_templ->SetHiddenPrototype(true);
11670 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11671 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11672 NULL, NULL, NULL, NULL,
11673 v8::External::New(&interceptor_call_count));
11674 LocalContext context;
11675 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11676 GenerateSomeGarbage();
11677 context->Global()->Set(v8_str("o"), fun->NewInstance());
11680 "var receiver = {};"
11681 "receiver.__proto__ = o;"
11683 "var saved_result = 0;"
11684 "for (var i = 0; i < 100; i++) {"
11685 " result = receiver.method(41);"
11687 " saved_result = result;"
11688 " o.method = function(x) { return x - 1 };"
11691 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11692 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11693 CHECK_GE(interceptor_call_count, 50);
11697 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
11698 int interceptor_call_count = 0;
11699 v8::HandleScope scope(CcTest::isolate());
11700 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11701 v8::Handle<v8::FunctionTemplate> method_templ =
11702 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11703 v8_str("method_data"),
11704 v8::Signature::New(fun_templ));
11705 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11706 proto_templ->Set(v8_str("method"), method_templ);
11707 fun_templ->SetHiddenPrototype(true);
11708 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11709 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11710 NULL, NULL, NULL, NULL,
11711 v8::External::New(&interceptor_call_count));
11712 LocalContext context;
11713 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11714 GenerateSomeGarbage();
11715 context->Global()->Set(v8_str("o"), fun->NewInstance());
11716 v8::TryCatch try_catch;
11719 "var receiver = {};"
11720 "receiver.__proto__ = o;"
11722 "var saved_result = 0;"
11723 "for (var i = 0; i < 100; i++) {"
11724 " result = receiver.method(41);"
11726 " saved_result = result;"
11730 CHECK(try_catch.HasCaught());
11731 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11732 try_catch.Exception()->ToString());
11733 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11734 CHECK_GE(interceptor_call_count, 50);
11738 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
11739 int interceptor_call_count = 0;
11740 v8::HandleScope scope(CcTest::isolate());
11741 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11742 v8::Handle<v8::FunctionTemplate> method_templ =
11743 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11744 v8_str("method_data"),
11745 v8::Signature::New(fun_templ));
11746 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11747 proto_templ->Set(v8_str("method"), method_templ);
11748 fun_templ->SetHiddenPrototype(true);
11749 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11750 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11751 NULL, NULL, NULL, NULL,
11752 v8::External::New(&interceptor_call_count));
11753 LocalContext context;
11754 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11755 GenerateSomeGarbage();
11756 context->Global()->Set(v8_str("o"), fun->NewInstance());
11757 v8::TryCatch try_catch;
11760 "var receiver = {};"
11761 "receiver.__proto__ = o;"
11763 "var saved_result = 0;"
11764 "for (var i = 0; i < 100; i++) {"
11765 " result = receiver.method(41);"
11767 " saved_result = result;"
11768 " receiver = {method: receiver.method};"
11771 CHECK(try_catch.HasCaught());
11772 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11773 try_catch.Exception()->ToString());
11774 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11775 CHECK_GE(interceptor_call_count, 50);
11779 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
11780 v8::HandleScope scope(CcTest::isolate());
11781 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11782 v8::Handle<v8::FunctionTemplate> method_templ =
11783 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11784 v8_str("method_data"),
11785 v8::Handle<v8::Signature>());
11786 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11787 proto_templ->Set(v8_str("method"), method_templ);
11788 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11790 LocalContext context;
11791 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11792 GenerateSomeGarbage();
11793 context->Global()->Set(v8_str("o"), fun->NewInstance());
11796 "for (var i = 0; i < 100; i++) {"
11797 " result = o.method(41);"
11800 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11804 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
11805 v8::HandleScope scope(CcTest::isolate());
11806 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11807 v8::Handle<v8::FunctionTemplate> method_templ =
11808 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11809 v8_str("method_data"),
11810 v8::Signature::New(fun_templ));
11811 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11812 proto_templ->Set(v8_str("method"), method_templ);
11813 fun_templ->SetHiddenPrototype(true);
11814 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11815 CHECK(!templ.IsEmpty());
11816 LocalContext context;
11817 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11818 GenerateSomeGarbage();
11819 context->Global()->Set(v8_str("o"), fun->NewInstance());
11822 "var receiver = {};"
11823 "receiver.__proto__ = o;"
11825 "for (var i = 0; i < 100; i++) {"
11826 " result = receiver.method(41);"
11829 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11833 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
11834 v8::HandleScope scope(CcTest::isolate());
11835 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11836 v8::Handle<v8::FunctionTemplate> method_templ =
11837 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11838 v8_str("method_data"),
11839 v8::Signature::New(fun_templ));
11840 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11841 proto_templ->Set(v8_str("method"), method_templ);
11842 fun_templ->SetHiddenPrototype(true);
11843 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11844 CHECK(!templ.IsEmpty());
11845 LocalContext context;
11846 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11847 GenerateSomeGarbage();
11848 context->Global()->Set(v8_str("o"), fun->NewInstance());
11851 "var receiver = {};"
11852 "receiver.__proto__ = o;"
11854 "var saved_result = 0;"
11855 "for (var i = 0; i < 100; i++) {"
11856 " result = receiver.method(41);"
11858 " saved_result = result;"
11859 " receiver = {method: function(x) { return x - 1 }};"
11862 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11863 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11867 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
11868 v8::HandleScope scope(CcTest::isolate());
11869 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11870 v8::Handle<v8::FunctionTemplate> method_templ =
11871 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11872 v8_str("method_data"),
11873 v8::Signature::New(fun_templ));
11874 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11875 proto_templ->Set(v8_str("method"), method_templ);
11876 fun_templ->SetHiddenPrototype(true);
11877 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11878 CHECK(!templ.IsEmpty());
11879 LocalContext context;
11880 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11881 GenerateSomeGarbage();
11882 context->Global()->Set(v8_str("o"), fun->NewInstance());
11883 v8::TryCatch try_catch;
11886 "var receiver = {};"
11887 "receiver.__proto__ = o;"
11889 "var saved_result = 0;"
11890 "for (var i = 0; i < 100; i++) {"
11891 " result = receiver.method(41);"
11893 " saved_result = result;"
11897 CHECK(try_catch.HasCaught());
11898 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11899 try_catch.Exception()->ToString());
11900 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11904 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
11905 v8::HandleScope scope(CcTest::isolate());
11906 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11907 v8::Handle<v8::FunctionTemplate> method_templ =
11908 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11909 v8_str("method_data"),
11910 v8::Signature::New(fun_templ));
11911 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11912 proto_templ->Set(v8_str("method"), method_templ);
11913 fun_templ->SetHiddenPrototype(true);
11914 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11915 CHECK(!templ.IsEmpty());
11916 LocalContext context;
11917 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11918 GenerateSomeGarbage();
11919 context->Global()->Set(v8_str("o"), fun->NewInstance());
11920 v8::TryCatch try_catch;
11923 "var receiver = {};"
11924 "receiver.__proto__ = o;"
11926 "var saved_result = 0;"
11927 "for (var i = 0; i < 100; i++) {"
11928 " result = receiver.method(41);"
11930 " saved_result = result;"
11931 " receiver = Object.create(receiver);"
11934 CHECK(try_catch.HasCaught());
11935 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11936 try_catch.Exception()->ToString());
11937 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11941 v8::Handle<Value> keyed_call_ic_function;
11943 static void InterceptorKeyedCallICGetter(
11944 Local<String> name,
11945 const v8::PropertyCallbackInfo<v8::Value>& info) {
11946 ApiTestFuzzer::Fuzz();
11947 if (v8_str("x")->Equals(name)) {
11948 info.GetReturnValue().Set(keyed_call_ic_function);
11953 // Test the case when we stored cacheable lookup into
11954 // a stub, but the function name changed (to another cacheable function).
11955 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
11956 v8::HandleScope scope(CcTest::isolate());
11957 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11958 templ->SetNamedPropertyHandler(NoBlockGetterX);
11959 LocalContext context;
11960 context->Global()->Set(v8_str("o"), templ->NewInstance());
11962 "proto = new Object();"
11963 "proto.y = function(x) { return x + 1; };"
11964 "proto.z = function(x) { return x - 1; };"
11965 "o.__proto__ = proto;"
11967 "var method = 'y';"
11968 "for (var i = 0; i < 10; i++) {"
11969 " if (i == 5) { method = 'z'; };"
11970 " result += o[method](41);"
11972 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11976 // Test the case when we stored cacheable lookup into
11977 // a stub, but the function name changed (and the new function is present
11978 // both before and after the interceptor in the prototype chain).
11979 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
11980 v8::HandleScope scope(CcTest::isolate());
11981 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11982 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
11983 LocalContext context;
11984 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
11985 keyed_call_ic_function =
11986 v8_compile("function f(x) { return x - 1; }; f")->Run();
11988 "o = new Object();"
11989 "proto2 = new Object();"
11990 "o.y = function(x) { return x + 1; };"
11991 "proto2.y = function(x) { return x + 2; };"
11992 "o.__proto__ = proto1;"
11993 "proto1.__proto__ = proto2;"
11995 "var method = 'x';"
11996 "for (var i = 0; i < 10; i++) {"
11997 " if (i == 5) { method = 'y'; };"
11998 " result += o[method](41);"
12000 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12004 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12005 // on the global object.
12006 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12007 v8::HandleScope scope(CcTest::isolate());
12008 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12009 templ->SetNamedPropertyHandler(NoBlockGetterX);
12010 LocalContext context;
12011 context->Global()->Set(v8_str("o"), templ->NewInstance());
12013 "function inc(x) { return x + 1; };"
12015 "function dec(x) { return x - 1; };"
12017 "o.__proto__ = this;"
12018 "this.__proto__.x = inc;"
12019 "this.__proto__.y = dec;"
12021 "var method = 'x';"
12022 "for (var i = 0; i < 10; i++) {"
12023 " if (i == 5) { method = 'y'; };"
12024 " result += o[method](41);"
12026 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12030 // Test the case when actual function to call sits on global object.
12031 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12032 v8::HandleScope scope(CcTest::isolate());
12033 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12034 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12035 LocalContext context;
12036 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12039 "function len(x) { return x.length; };"
12040 "o.__proto__ = this;"
12041 "var m = 'parseFloat';"
12043 "for (var i = 0; i < 10; i++) {"
12046 " saved_result = result;"
12048 " result = o[m]('239');"
12050 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12051 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12055 // Test the map transition before the interceptor.
12056 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12057 v8::HandleScope scope(CcTest::isolate());
12058 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12059 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12060 LocalContext context;
12061 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12064 "var o = new Object();"
12065 "o.__proto__ = proto;"
12066 "o.method = function(x) { return x + 1; };"
12067 "var m = 'method';"
12069 "for (var i = 0; i < 10; i++) {"
12070 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12071 " result += o[m](41);"
12073 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12077 // Test the map transition after the interceptor.
12078 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12079 v8::HandleScope scope(CcTest::isolate());
12080 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12081 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12082 LocalContext context;
12083 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12086 "var proto = new Object();"
12087 "o.__proto__ = proto;"
12088 "proto.method = function(x) { return x + 1; };"
12089 "var m = 'method';"
12091 "for (var i = 0; i < 10; i++) {"
12092 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12093 " result += o[m](41);"
12095 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12099 static int interceptor_call_count = 0;
12101 static void InterceptorICRefErrorGetter(
12102 Local<String> name,
12103 const v8::PropertyCallbackInfo<v8::Value>& info) {
12104 ApiTestFuzzer::Fuzz();
12105 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12106 info.GetReturnValue().Set(call_ic_function2);
12111 // This test should hit load and call ICs for the interceptor case.
12112 // Once in a while, the interceptor will reply that a property was not
12113 // found in which case we should get a reference error.
12114 THREADED_TEST(InterceptorICReferenceErrors) {
12115 v8::HandleScope scope(CcTest::isolate());
12116 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12117 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12118 LocalContext context(0, templ, v8::Handle<Value>());
12119 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12120 v8::Handle<Value> value = CompileRun(
12122 " for (var i = 0; i < 1000; i++) {"
12123 " try { x; } catch(e) { return true; }"
12128 CHECK_EQ(true, value->BooleanValue());
12129 interceptor_call_count = 0;
12130 value = CompileRun(
12132 " for (var i = 0; i < 1000; i++) {"
12133 " try { x(42); } catch(e) { return true; }"
12138 CHECK_EQ(true, value->BooleanValue());
12142 static int interceptor_ic_exception_get_count = 0;
12144 static void InterceptorICExceptionGetter(
12145 Local<String> name,
12146 const v8::PropertyCallbackInfo<v8::Value>& info) {
12147 ApiTestFuzzer::Fuzz();
12148 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12149 info.GetReturnValue().Set(call_ic_function3);
12151 if (interceptor_ic_exception_get_count == 20) {
12152 info.GetIsolate()->ThrowException(v8_num(42));
12158 // Test interceptor load/call IC where the interceptor throws an
12159 // exception once in a while.
12160 THREADED_TEST(InterceptorICGetterExceptions) {
12161 interceptor_ic_exception_get_count = 0;
12162 v8::HandleScope scope(CcTest::isolate());
12163 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12164 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12165 LocalContext context(0, templ, v8::Handle<Value>());
12166 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12167 v8::Handle<Value> value = CompileRun(
12169 " for (var i = 0; i < 100; i++) {"
12170 " try { x; } catch(e) { return true; }"
12175 CHECK_EQ(true, value->BooleanValue());
12176 interceptor_ic_exception_get_count = 0;
12177 value = CompileRun(
12179 " for (var i = 0; i < 100; i++) {"
12180 " try { x(42); } catch(e) { return true; }"
12185 CHECK_EQ(true, value->BooleanValue());
12189 static int interceptor_ic_exception_set_count = 0;
12191 static void InterceptorICExceptionSetter(
12193 Local<Value> value,
12194 const v8::PropertyCallbackInfo<v8::Value>& info) {
12195 ApiTestFuzzer::Fuzz();
12196 if (++interceptor_ic_exception_set_count > 20) {
12197 info.GetIsolate()->ThrowException(v8_num(42));
12202 // Test interceptor store IC where the interceptor throws an exception
12203 // once in a while.
12204 THREADED_TEST(InterceptorICSetterExceptions) {
12205 interceptor_ic_exception_set_count = 0;
12206 v8::HandleScope scope(CcTest::isolate());
12207 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12208 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12209 LocalContext context(0, templ, v8::Handle<Value>());
12210 v8::Handle<Value> value = CompileRun(
12212 " for (var i = 0; i < 100; i++) {"
12213 " try { x = 42; } catch(e) { return true; }"
12218 CHECK_EQ(true, value->BooleanValue());
12222 // Test that we ignore null interceptors.
12223 THREADED_TEST(NullNamedInterceptor) {
12224 v8::HandleScope scope(CcTest::isolate());
12225 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12226 templ->SetNamedPropertyHandler(
12227 static_cast<v8::NamedPropertyGetterCallback>(0));
12228 LocalContext context;
12229 templ->Set("x", v8_num(42));
12230 v8::Handle<v8::Object> obj = templ->NewInstance();
12231 context->Global()->Set(v8_str("obj"), obj);
12232 v8::Handle<Value> value = CompileRun("obj.x");
12233 CHECK(value->IsInt32());
12234 CHECK_EQ(42, value->Int32Value());
12238 // Test that we ignore null interceptors.
12239 THREADED_TEST(NullIndexedInterceptor) {
12240 v8::HandleScope scope(CcTest::isolate());
12241 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12242 templ->SetIndexedPropertyHandler(
12243 static_cast<v8::IndexedPropertyGetterCallback>(0));
12244 LocalContext context;
12245 templ->Set("42", v8_num(42));
12246 v8::Handle<v8::Object> obj = templ->NewInstance();
12247 context->Global()->Set(v8_str("obj"), obj);
12248 v8::Handle<Value> value = CompileRun("obj[42]");
12249 CHECK(value->IsInt32());
12250 CHECK_EQ(42, value->Int32Value());
12254 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12255 v8::HandleScope scope(CcTest::isolate());
12256 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12257 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12259 env->Global()->Set(v8_str("obj"),
12260 templ->GetFunction()->NewInstance());
12261 ExpectTrue("obj.x === 42");
12262 ExpectTrue("!obj.propertyIsEnumerable('x')");
12266 static void ThrowingGetter(Local<String> name,
12267 const v8::PropertyCallbackInfo<v8::Value>& info) {
12268 ApiTestFuzzer::Fuzz();
12269 info.GetIsolate()->ThrowException(Handle<Value>());
12270 info.GetReturnValue().SetUndefined();
12274 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12275 LocalContext context;
12276 HandleScope scope(context->GetIsolate());
12278 Local<FunctionTemplate> templ = FunctionTemplate::New();
12279 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12280 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12282 Local<Object> instance = templ->GetFunction()->NewInstance();
12284 Local<Object> another = Object::New();
12285 another->SetPrototype(instance);
12287 Local<Object> with_js_getter = CompileRun(
12289 "o.__defineGetter__('f', function() { throw undefined; });\n"
12290 "o\n").As<Object>();
12291 CHECK(!with_js_getter.IsEmpty());
12293 TryCatch try_catch;
12295 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12296 CHECK(try_catch.HasCaught());
12298 CHECK(result.IsEmpty());
12300 result = another->GetRealNamedProperty(v8_str("f"));
12301 CHECK(try_catch.HasCaught());
12303 CHECK(result.IsEmpty());
12305 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12306 CHECK(try_catch.HasCaught());
12308 CHECK(result.IsEmpty());
12310 result = another->Get(v8_str("f"));
12311 CHECK(try_catch.HasCaught());
12313 CHECK(result.IsEmpty());
12315 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12316 CHECK(try_catch.HasCaught());
12318 CHECK(result.IsEmpty());
12320 result = with_js_getter->Get(v8_str("f"));
12321 CHECK(try_catch.HasCaught());
12323 CHECK(result.IsEmpty());
12327 static void ThrowingCallbackWithTryCatch(
12328 const v8::FunctionCallbackInfo<v8::Value>& args) {
12329 TryCatch try_catch;
12330 // Verboseness is important: it triggers message delivery which can call into
12332 try_catch.SetVerbose(true);
12333 CompileRun("throw 'from JS';");
12334 CHECK(try_catch.HasCaught());
12335 CHECK(!CcTest::i_isolate()->has_pending_exception());
12336 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12340 static int call_depth;
12343 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12344 TryCatch try_catch;
12348 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12349 if (--call_depth) CompileRun("throw 'ThrowInJS';");
12353 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12354 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12358 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12359 Handle<String> errorMessageString = message->Get();
12360 CHECK(!errorMessageString.IsEmpty());
12361 message->GetStackTrace();
12362 message->GetScriptResourceName();
12366 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12367 LocalContext context;
12368 HandleScope scope(context->GetIsolate());
12370 Local<Function> func =
12371 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
12372 context->Global()->Set(v8_str("func"), func);
12374 MessageCallback callbacks[] =
12375 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12376 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12377 MessageCallback callback = callbacks[i];
12378 if (callback != NULL) {
12379 V8::AddMessageListener(callback);
12381 // Some small number to control number of times message handler should
12382 // throw an exception.
12385 "var thrown = false;\n"
12386 "try { func(); } catch(e) { thrown = true; }\n"
12388 if (callback != NULL) {
12389 V8::RemoveMessageListeners(callback);
12395 static void ParentGetter(Local<String> name,
12396 const v8::PropertyCallbackInfo<v8::Value>& info) {
12397 ApiTestFuzzer::Fuzz();
12398 info.GetReturnValue().Set(v8_num(1));
12402 static void ChildGetter(Local<String> name,
12403 const v8::PropertyCallbackInfo<v8::Value>& info) {
12404 ApiTestFuzzer::Fuzz();
12405 info.GetReturnValue().Set(v8_num(42));
12409 THREADED_TEST(Overriding) {
12410 i::FLAG_es5_readonly = true;
12411 LocalContext context;
12412 v8::HandleScope scope(context->GetIsolate());
12414 // Parent template.
12415 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
12416 Local<ObjectTemplate> parent_instance_templ =
12417 parent_templ->InstanceTemplate();
12418 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12420 // Template that inherits from the parent template.
12421 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
12422 Local<ObjectTemplate> child_instance_templ =
12423 child_templ->InstanceTemplate();
12424 child_templ->Inherit(parent_templ);
12425 // Override 'f'. The child version of 'f' should get called for child
12427 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12428 // Add 'g' twice. The 'g' added last should get called for instances.
12429 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12430 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12432 // Add 'h' as an accessor to the proto template with ReadOnly attributes
12433 // so 'h' can be shadowed on the instance object.
12434 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12435 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12436 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12438 // Add 'i' as an accessor to the instance template with ReadOnly attributes
12439 // but the attribute does not have effect because it is duplicated with
12441 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12442 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12446 // Instantiate the child template.
12447 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12449 // Check that the child function overrides the parent one.
12450 context->Global()->Set(v8_str("o"), instance);
12451 Local<Value> value = v8_compile("o.f")->Run();
12452 // Check that the 'g' that was added last is hit.
12453 CHECK_EQ(42, value->Int32Value());
12454 value = v8_compile("o.g")->Run();
12455 CHECK_EQ(42, value->Int32Value());
12457 // Check that 'h' cannot be shadowed.
12458 value = v8_compile("o.h = 3; o.h")->Run();
12459 CHECK_EQ(1, value->Int32Value());
12461 // Check that 'i' cannot be shadowed or changed.
12462 value = v8_compile("o.i = 3; o.i")->Run();
12463 CHECK_EQ(42, value->Int32Value());
12467 static void IsConstructHandler(
12468 const v8::FunctionCallbackInfo<v8::Value>& args) {
12469 ApiTestFuzzer::Fuzz();
12470 args.GetReturnValue().Set(args.IsConstructCall());
12474 THREADED_TEST(IsConstructCall) {
12475 v8::HandleScope scope(CcTest::isolate());
12477 // Function template with call handler.
12478 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12479 templ->SetCallHandler(IsConstructHandler);
12481 LocalContext context;
12483 context->Global()->Set(v8_str("f"), templ->GetFunction());
12484 Local<Value> value = v8_compile("f()")->Run();
12485 CHECK(!value->BooleanValue());
12486 value = v8_compile("new f()")->Run();
12487 CHECK(value->BooleanValue());
12491 THREADED_TEST(ObjectProtoToString) {
12492 v8::HandleScope scope(CcTest::isolate());
12493 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12494 templ->SetClassName(v8_str("MyClass"));
12496 LocalContext context;
12498 Local<String> customized_tostring = v8_str("customized toString");
12500 // Replace Object.prototype.toString
12501 v8_compile("Object.prototype.toString = function() {"
12502 " return 'customized toString';"
12505 // Normal ToString call should call replaced Object.prototype.toString
12506 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
12507 Local<String> value = instance->ToString();
12508 CHECK(value->IsString() && value->Equals(customized_tostring));
12510 // ObjectProtoToString should not call replace toString function.
12511 value = instance->ObjectProtoToString();
12512 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
12515 value = context->Global()->ObjectProtoToString();
12516 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
12518 // Check ordinary object
12519 Local<Value> object = v8_compile("new Object()")->Run();
12520 value = object.As<v8::Object>()->ObjectProtoToString();
12521 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
12525 THREADED_TEST(ObjectGetConstructorName) {
12526 LocalContext context;
12527 v8::HandleScope scope(context->GetIsolate());
12528 v8_compile("function Parent() {};"
12529 "function Child() {};"
12530 "Child.prototype = new Parent();"
12531 "var outer = { inner: function() { } };"
12532 "var p = new Parent();"
12533 "var c = new Child();"
12534 "var x = new outer.inner();")->Run();
12536 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
12537 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
12538 v8_str("Parent")));
12540 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
12541 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
12544 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
12545 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
12546 v8_str("outer.inner")));
12550 bool ApiTestFuzzer::fuzzing_ = false;
12551 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
12552 int ApiTestFuzzer::active_tests_;
12553 int ApiTestFuzzer::tests_being_run_;
12554 int ApiTestFuzzer::current_;
12557 // We are in a callback and want to switch to another thread (if we
12558 // are currently running the thread fuzzing test).
12559 void ApiTestFuzzer::Fuzz() {
12560 if (!fuzzing_) return;
12561 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
12562 test->ContextSwitch();
12566 // Let the next thread go. Since it is also waiting on the V8 lock it may
12567 // not start immediately.
12568 bool ApiTestFuzzer::NextThread() {
12569 int test_position = GetNextTestNumber();
12570 const char* test_name = RegisterThreadedTest::nth(current_)->name();
12571 if (test_position == current_) {
12573 printf("Stay with %s\n", test_name);
12576 if (kLogThreading) {
12577 printf("Switch from %s to %s\n",
12579 RegisterThreadedTest::nth(test_position)->name());
12581 current_ = test_position;
12582 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
12587 void ApiTestFuzzer::Run() {
12588 // When it is our turn...
12591 // ... get the V8 lock and start running the test.
12592 v8::Locker locker(CcTest::isolate());
12595 // This test finished.
12598 // If it was the last then signal that fact.
12599 if (active_tests_ == 0) {
12600 all_tests_done_.Signal();
12602 // Otherwise select a new test and start that.
12608 static unsigned linear_congruential_generator;
12611 void ApiTestFuzzer::SetUp(PartOfTest part) {
12612 linear_congruential_generator = i::FLAG_testing_prng_seed;
12614 int count = RegisterThreadedTest::count();
12615 int start = count * part / (LAST_PART + 1);
12616 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
12617 active_tests_ = tests_being_run_ = end - start + 1;
12618 for (int i = 0; i < tests_being_run_; i++) {
12619 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
12621 for (int i = 0; i < active_tests_; i++) {
12622 RegisterThreadedTest::nth(i)->fuzzer_->Start();
12627 static void CallTestNumber(int test_number) {
12628 (RegisterThreadedTest::nth(test_number)->callback())();
12632 void ApiTestFuzzer::RunAllTests() {
12633 // Set off the first test.
12636 // Wait till they are all done.
12637 all_tests_done_.Wait();
12641 int ApiTestFuzzer::GetNextTestNumber() {
12644 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
12645 linear_congruential_generator *= 1664525u;
12646 linear_congruential_generator += 1013904223u;
12647 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
12652 void ApiTestFuzzer::ContextSwitch() {
12653 // If the new thread is the same as the current thread there is nothing to do.
12654 if (NextThread()) {
12655 // Now it can start.
12656 v8::Unlocker unlocker(CcTest::isolate());
12657 // Wait till someone starts us again.
12664 void ApiTestFuzzer::TearDown() {
12666 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
12667 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
12668 if (fuzzer != NULL) fuzzer->Join();
12673 // Lets not be needlessly self-referential.
12675 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
12676 ApiTestFuzzer::RunAllTests();
12677 ApiTestFuzzer::TearDown();
12682 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
12683 ApiTestFuzzer::RunAllTests();
12684 ApiTestFuzzer::TearDown();
12689 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
12690 ApiTestFuzzer::RunAllTests();
12691 ApiTestFuzzer::TearDown();
12696 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
12697 ApiTestFuzzer::RunAllTests();
12698 ApiTestFuzzer::TearDown();
12702 void ApiTestFuzzer::CallTest() {
12703 v8::Isolate::Scope scope(CcTest::isolate());
12705 printf("Start test %d\n", test_number_);
12706 CallTestNumber(test_number_);
12708 printf("End test %d\n", test_number_);
12712 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
12713 v8::Isolate* isolate = args.GetIsolate();
12714 CHECK(v8::Locker::IsLocked(isolate));
12715 ApiTestFuzzer::Fuzz();
12716 v8::Unlocker unlocker(isolate);
12717 const char* code = "throw 7;";
12719 v8::Locker nested_locker(isolate);
12720 v8::HandleScope scope(isolate);
12721 v8::Handle<Value> exception;
12722 { v8::TryCatch try_catch;
12723 v8::Handle<Value> value = CompileRun(code);
12724 CHECK(value.IsEmpty());
12725 CHECK(try_catch.HasCaught());
12726 // Make sure to wrap the exception in a new handle because
12727 // the handle returned from the TryCatch is destroyed
12728 // when the TryCatch is destroyed.
12729 exception = Local<Value>::New(isolate, try_catch.Exception());
12731 args.GetIsolate()->ThrowException(exception);
12736 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
12737 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12738 ApiTestFuzzer::Fuzz();
12739 v8::Unlocker unlocker(CcTest::isolate());
12740 const char* code = "throw 7;";
12742 v8::Locker nested_locker(CcTest::isolate());
12743 v8::HandleScope scope(args.GetIsolate());
12744 v8::Handle<Value> value = CompileRun(code);
12745 CHECK(value.IsEmpty());
12746 args.GetReturnValue().Set(v8_str("foo"));
12751 // These are locking tests that don't need to be run again
12752 // as part of the locking aggregation tests.
12753 TEST(NestedLockers) {
12754 v8::Locker locker(CcTest::isolate());
12755 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12757 v8::HandleScope scope(env->GetIsolate());
12758 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
12759 Local<Function> fun = fun_templ->GetFunction();
12760 env->Global()->Set(v8_str("throw_in_js"), fun);
12761 Local<Script> script = v8_compile("(function () {"
12769 CHECK_EQ(91, script->Run()->Int32Value());
12773 // These are locking tests that don't need to be run again
12774 // as part of the locking aggregation tests.
12775 TEST(NestedLockersNoTryCatch) {
12776 v8::Locker locker(CcTest::isolate());
12778 v8::HandleScope scope(env->GetIsolate());
12779 Local<v8::FunctionTemplate> fun_templ =
12780 v8::FunctionTemplate::New(ThrowInJSNoCatch);
12781 Local<Function> fun = fun_templ->GetFunction();
12782 env->Global()->Set(v8_str("throw_in_js"), fun);
12783 Local<Script> script = v8_compile("(function () {"
12791 CHECK_EQ(91, script->Run()->Int32Value());
12795 THREADED_TEST(RecursiveLocking) {
12796 v8::Locker locker(CcTest::isolate());
12798 v8::Locker locker2(CcTest::isolate());
12799 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12804 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
12805 ApiTestFuzzer::Fuzz();
12806 v8::Unlocker unlocker(CcTest::isolate());
12810 THREADED_TEST(LockUnlockLock) {
12812 v8::Locker locker(CcTest::isolate());
12813 v8::HandleScope scope(CcTest::isolate());
12815 Local<v8::FunctionTemplate> fun_templ =
12816 v8::FunctionTemplate::New(UnlockForAMoment);
12817 Local<Function> fun = fun_templ->GetFunction();
12818 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12819 Local<Script> script = v8_compile("(function () {"
12820 " unlock_for_a_moment();"
12823 CHECK_EQ(42, script->Run()->Int32Value());
12826 v8::Locker locker(CcTest::isolate());
12827 v8::HandleScope scope(CcTest::isolate());
12829 Local<v8::FunctionTemplate> fun_templ =
12830 v8::FunctionTemplate::New(UnlockForAMoment);
12831 Local<Function> fun = fun_templ->GetFunction();
12832 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12833 Local<Script> script = v8_compile("(function () {"
12834 " unlock_for_a_moment();"
12837 CHECK_EQ(42, script->Run()->Int32Value());
12842 static int GetGlobalObjectsCount() {
12843 CcTest::heap()->EnsureHeapIsIterable();
12845 i::HeapIterator it(CcTest::heap());
12846 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
12847 if (object->IsJSGlobalObject()) count++;
12852 static void CheckSurvivingGlobalObjectsCount(int expected) {
12853 // We need to collect all garbage twice to be sure that everything
12854 // has been collected. This is because inline caches are cleared in
12855 // the first garbage collection but some of the maps have already
12856 // been marked at that point. Therefore some of the maps are not
12857 // collected until the second garbage collection.
12858 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12859 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
12860 int count = GetGlobalObjectsCount();
12862 if (count != expected) CcTest::heap()->TracePathToGlobal();
12864 CHECK_EQ(expected, count);
12868 TEST(DontLeakGlobalObjects) {
12869 // Regression test for issues 1139850 and 1174891.
12871 v8::V8::Initialize();
12873 for (int i = 0; i < 5; i++) {
12874 { v8::HandleScope scope(CcTest::isolate());
12875 LocalContext context;
12877 v8::V8::ContextDisposedNotification();
12878 CheckSurvivingGlobalObjectsCount(0);
12880 { v8::HandleScope scope(CcTest::isolate());
12881 LocalContext context;
12882 v8_compile("Date")->Run();
12884 v8::V8::ContextDisposedNotification();
12885 CheckSurvivingGlobalObjectsCount(0);
12887 { v8::HandleScope scope(CcTest::isolate());
12888 LocalContext context;
12889 v8_compile("/aaa/")->Run();
12891 v8::V8::ContextDisposedNotification();
12892 CheckSurvivingGlobalObjectsCount(0);
12894 { v8::HandleScope scope(CcTest::isolate());
12895 const char* extension_list[] = { "v8/gc" };
12896 v8::ExtensionConfiguration extensions(1, extension_list);
12897 LocalContext context(&extensions);
12898 v8_compile("gc();")->Run();
12900 v8::V8::ContextDisposedNotification();
12901 CheckSurvivingGlobalObjectsCount(0);
12906 TEST(CopyablePersistent) {
12907 LocalContext context;
12908 v8::Isolate* isolate = context->GetIsolate();
12909 i::GlobalHandles* globals =
12910 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12911 int initial_handles = globals->global_handles_count();
12912 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
12915 CopyableObject handle1;
12917 v8::HandleScope scope(isolate);
12918 handle1.Reset(isolate, v8::Object::New());
12920 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
12921 CopyableObject handle2;
12923 CHECK(handle1 == handle2);
12924 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
12925 CopyableObject handle3(handle2);
12926 CHECK(handle1 == handle3);
12927 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
12929 // Verify autodispose
12930 CHECK_EQ(initial_handles, globals->global_handles_count());
12934 static void WeakApiCallback(
12935 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
12936 Local<Value> value = data.GetValue()->Get(v8_str("key"));
12937 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
12938 data.GetParameter()->Reset();
12939 delete data.GetParameter();
12943 TEST(WeakCallbackApi) {
12944 LocalContext context;
12945 v8::Isolate* isolate = context->GetIsolate();
12946 i::GlobalHandles* globals =
12947 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12948 int initial_handles = globals->global_handles_count();
12950 v8::HandleScope scope(isolate);
12951 v8::Local<v8::Object> obj = v8::Object::New();
12952 obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
12953 v8::Persistent<v8::Object>* handle =
12954 new v8::Persistent<v8::Object>(isolate, obj);
12955 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
12958 reinterpret_cast<i::Isolate*>(isolate)->heap()->
12959 CollectAllGarbage(i::Heap::kNoGCFlags);
12960 // Verify disposed.
12961 CHECK_EQ(initial_handles, globals->global_handles_count());
12965 v8::Persistent<v8::Object> some_object;
12966 v8::Persistent<v8::Object> bad_handle;
12968 void NewPersistentHandleCallback(v8::Isolate* isolate,
12969 v8::Persistent<v8::Value>* handle,
12971 v8::HandleScope scope(isolate);
12972 bad_handle.Reset(isolate, some_object);
12977 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
12978 LocalContext context;
12979 v8::Isolate* isolate = context->GetIsolate();
12981 v8::Persistent<v8::Object> handle1, handle2;
12983 v8::HandleScope scope(isolate);
12984 some_object.Reset(isolate, v8::Object::New());
12985 handle1.Reset(isolate, v8::Object::New());
12986 handle2.Reset(isolate, v8::Object::New());
12988 // Note: order is implementation dependent alas: currently
12989 // global handle nodes are processed by PostGarbageCollectionProcessing
12990 // in reverse allocation order, so if second allocated handle is deleted,
12991 // weak callback of the first handle would be able to 'reallocate' it.
12992 handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback);
12994 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12998 v8::Persistent<v8::Object> to_be_disposed;
13000 void DisposeAndForceGcCallback(v8::Isolate* isolate,
13001 v8::Persistent<v8::Value>* handle,
13003 to_be_disposed.Dispose();
13004 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13009 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13010 LocalContext context;
13011 v8::Isolate* isolate = context->GetIsolate();
13013 v8::Persistent<v8::Object> handle1, handle2;
13015 v8::HandleScope scope(isolate);
13016 handle1.Reset(isolate, v8::Object::New());
13017 handle2.Reset(isolate, v8::Object::New());
13019 handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback);
13020 to_be_disposed.Reset(isolate, handle2);
13021 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13024 void DisposingCallback(v8::Isolate* isolate,
13025 v8::Persistent<v8::Value>* handle,
13030 void HandleCreatingCallback(v8::Isolate* isolate,
13031 v8::Persistent<v8::Value>* handle,
13033 v8::HandleScope scope(isolate);
13034 v8::Persistent<v8::Object>(isolate, v8::Object::New());
13039 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13040 LocalContext context;
13041 v8::Isolate* isolate = context->GetIsolate();
13043 v8::Persistent<v8::Object> handle1, handle2, handle3;
13045 v8::HandleScope scope(isolate);
13046 handle3.Reset(isolate, v8::Object::New());
13047 handle2.Reset(isolate, v8::Object::New());
13048 handle1.Reset(isolate, v8::Object::New());
13050 handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback);
13051 handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback);
13052 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13056 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13057 v8::V8::Initialize();
13060 const char* sources[nof] = {
13061 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13065 for (int i = 0; i < nof; i++) {
13066 const char* source = sources[i];
13067 { v8::HandleScope scope(CcTest::isolate());
13068 LocalContext context;
13069 CompileRun(source);
13071 { v8::HandleScope scope(CcTest::isolate());
13072 LocalContext context;
13073 CompileRun(source);
13079 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13080 v8::HandleScope inner(env->GetIsolate());
13082 v8::Handle<Value> three = v8_num(3);
13083 v8::Handle<Value> value = inner.Close(three);
13089 THREADED_TEST(NestedHandleScopeAndContexts) {
13090 v8::Isolate* isolate = CcTest::isolate();
13091 v8::HandleScope outer(isolate);
13092 v8::Local<Context> env = Context::New(isolate);
13094 v8::Handle<Value> value = NestedScope(env);
13095 v8::Handle<String> str(value->ToString());
13096 CHECK(!str.IsEmpty());
13101 static bool MatchPointers(void* key1, void* key2) {
13102 return key1 == key2;
13106 struct SymbolInfo {
13113 class SetFunctionEntryHookTest {
13115 SetFunctionEntryHookTest() {
13116 CHECK(instance_ == NULL);
13119 ~SetFunctionEntryHookTest() {
13120 CHECK(instance_ == this);
13125 symbol_locations_.clear();
13126 invocations_.clear();
13129 void OnJitEvent(const v8::JitCodeEvent* event);
13130 static void JitEvent(const v8::JitCodeEvent* event) {
13131 CHECK(instance_ != NULL);
13132 instance_->OnJitEvent(event);
13135 void OnEntryHook(uintptr_t function,
13136 uintptr_t return_addr_location);
13137 static void EntryHook(uintptr_t function,
13138 uintptr_t return_addr_location) {
13139 CHECK(instance_ != NULL);
13140 instance_->OnEntryHook(function, return_addr_location);
13143 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13144 CHECK(instance_ != NULL);
13145 args.GetReturnValue().Set(v8_num(42));
13147 void RunLoopInNewEnv(v8::Isolate* isolate);
13149 // Records addr as location of symbol.
13150 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13152 // Finds the symbol containing addr
13153 SymbolInfo* FindSymbolForAddr(i::Address addr);
13154 // Returns the number of invocations where the caller name contains
13155 // \p caller_name and the function name contains \p function_name.
13156 int CountInvocations(const char* caller_name,
13157 const char* function_name);
13159 i::Handle<i::JSFunction> foo_func_;
13160 i::Handle<i::JSFunction> bar_func_;
13162 typedef std::map<size_t, SymbolInfo> SymbolMap;
13163 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13164 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13165 SymbolMap symbols_;
13166 SymbolLocationMap symbol_locations_;
13167 InvocationMap invocations_;
13169 static SetFunctionEntryHookTest* instance_;
13171 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13174 // Returns true if addr is in the range [start, start+len).
13175 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13176 if (start <= addr && start + len > addr)
13182 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13183 SymbolInfo* symbol) {
13184 // Insert the symbol at the new location.
13185 SymbolLocationMap::iterator it =
13186 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13187 // Now erase symbols to the left and right that overlap this one.
13188 while (it != symbol_locations_.begin()) {
13189 SymbolLocationMap::iterator left = it;
13191 if (!Overlaps(left->first, left->second->size, addr))
13193 symbol_locations_.erase(left);
13196 // Now erase symbols to the left and right that overlap this one.
13198 SymbolLocationMap::iterator right = it;
13200 if (right == symbol_locations_.end())
13202 if (!Overlaps(addr, symbol->size, right->first))
13204 symbol_locations_.erase(right);
13209 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13210 switch (event->type) {
13211 case v8::JitCodeEvent::CODE_ADDED: {
13212 CHECK(event->code_start != NULL);
13213 CHECK_NE(0, static_cast<int>(event->code_len));
13214 CHECK(event->name.str != NULL);
13215 size_t symbol_id = symbols_.size();
13217 // Record the new symbol.
13218 SymbolInfo& info = symbols_[symbol_id];
13219 info.id = symbol_id;
13220 info.size = event->code_len;
13221 info.name.assign(event->name.str, event->name.str + event->name.len);
13223 // And record it's location.
13224 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13228 case v8::JitCodeEvent::CODE_MOVED: {
13229 // We would like to never see code move that we haven't seen before,
13230 // but the code creation event does not happen until the line endings
13231 // have been calculated (this is so that we can report the line in the
13232 // script at which the function source is found, see
13233 // Compiler::RecordFunctionCompilation) and the line endings
13234 // calculations can cause a GC, which can move the newly created code
13235 // before its existence can be logged.
13236 SymbolLocationMap::iterator it(
13237 symbol_locations_.find(
13238 reinterpret_cast<i::Address>(event->code_start)));
13239 if (it != symbol_locations_.end()) {
13240 // Found a symbol at this location, move it.
13241 SymbolInfo* info = it->second;
13242 symbol_locations_.erase(it);
13243 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13252 void SetFunctionEntryHookTest::OnEntryHook(
13253 uintptr_t function, uintptr_t return_addr_location) {
13254 // Get the function's code object.
13255 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13256 reinterpret_cast<i::Address>(function));
13257 CHECK(function_code != NULL);
13259 // Then try and look up the caller's code object.
13260 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13262 // Count the invocation.
13263 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13264 SymbolInfo* function_symbol =
13265 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13266 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13268 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13269 // Check that we have a symbol for the "bar" function at the right location.
13270 SymbolLocationMap::iterator it(
13271 symbol_locations_.find(function_code->instruction_start()));
13272 CHECK(it != symbol_locations_.end());
13275 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13276 // Check that we have a symbol for "foo" at the right location.
13277 SymbolLocationMap::iterator it(
13278 symbol_locations_.find(function_code->instruction_start()));
13279 CHECK(it != symbol_locations_.end());
13284 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13285 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13286 // Do we have a direct hit on a symbol?
13287 if (it != symbol_locations_.end()) {
13288 if (it->first == addr)
13292 // If not a direct hit, it'll have to be the previous symbol.
13293 if (it == symbol_locations_.begin())
13297 size_t offs = addr - it->first;
13298 if (offs < it->second->size)
13305 int SetFunctionEntryHookTest::CountInvocations(
13306 const char* caller_name, const char* function_name) {
13307 InvocationMap::iterator it(invocations_.begin());
13308 int invocations = 0;
13309 for (; it != invocations_.end(); ++it) {
13310 SymbolInfo* caller = it->first.first;
13311 SymbolInfo* function = it->first.second;
13313 // Filter out non-matching functions.
13314 if (function_name != NULL) {
13315 if (function->name.find(function_name) == std::string::npos)
13319 // Filter out non-matching callers.
13320 if (caller_name != NULL) {
13321 if (caller == NULL)
13323 if (caller->name.find(caller_name) == std::string::npos)
13327 // It matches add the invocation count to the tally.
13328 invocations += it->second;
13331 return invocations;
13335 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13336 v8::HandleScope outer(isolate);
13337 v8::Local<Context> env = Context::New(isolate);
13340 Local<ObjectTemplate> t = ObjectTemplate::New();
13341 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback));
13342 env->Global()->Set(v8_str("obj"), t->NewInstance());
13344 const char* script =
13345 "function bar() {\n"
13347 " for (i = 0; i < 100; ++i)\n"
13351 "function foo(i) { return i * i; }\n"
13352 "// Invoke on the runtime function.\n"
13354 CompileRun(script);
13355 bar_func_ = i::Handle<i::JSFunction>::cast(
13356 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13357 ASSERT(!bar_func_.is_null());
13360 i::Handle<i::JSFunction>::cast(
13361 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13362 ASSERT(!foo_func_.is_null());
13364 v8::Handle<v8::Value> value = CompileRun("bar();");
13365 CHECK(value->IsNumber());
13366 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13368 // Test the optimized codegen path.
13369 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13371 CHECK(value->IsNumber());
13372 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13378 void SetFunctionEntryHookTest::RunTest() {
13379 // Work in a new isolate throughout.
13380 v8::Isolate* isolate = v8::Isolate::New();
13382 // Test setting the entry hook on the new isolate.
13383 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13385 // Replacing the hook, once set should fail.
13386 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13389 v8::Isolate::Scope scope(isolate);
13391 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13393 RunLoopInNewEnv(isolate);
13395 // Check the exepected invocation counts.
13396 CHECK_EQ(2, CountInvocations(NULL, "bar"));
13397 CHECK_EQ(200, CountInvocations("bar", "foo"));
13398 CHECK_EQ(200, CountInvocations(NULL, "foo"));
13400 // Verify that we have an entry hook on some specific stubs.
13401 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13402 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13403 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13405 isolate->Dispose();
13409 // Make sure a second isolate is unaffected by the previous entry hook.
13410 isolate = v8::Isolate::New();
13412 v8::Isolate::Scope scope(isolate);
13414 // Reset the entry count to zero and set the entry hook.
13415 RunLoopInNewEnv(isolate);
13417 // We should record no invocations in this isolate.
13418 CHECK_EQ(0, static_cast<int>(invocations_.size()));
13420 // Since the isolate has been used, we shouldn't be able to set an entry
13422 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13424 isolate->Dispose();
13428 TEST(SetFunctionEntryHook) {
13429 // FunctionEntryHook does not work well with experimental natives.
13430 // Experimental natives are compiled during snapshot deserialization.
13431 // This test breaks because InstallGetter (function from snapshot that
13432 // only gets called from experimental natives) is compiled with entry hooks.
13433 i::FLAG_allow_natives_syntax = true;
13434 i::FLAG_use_inlining = false;
13436 SetFunctionEntryHookTest test;
13441 static i::HashMap* code_map = NULL;
13442 static i::HashMap* jitcode_line_info = NULL;
13443 static int saw_bar = 0;
13444 static int move_events = 0;
13447 static bool FunctionNameIs(const char* expected,
13448 const v8::JitCodeEvent* event) {
13449 // Log lines for functions are of the general form:
13450 // "LazyCompile:<type><function_name>", where the type is one of
13452 static const char kPreamble[] = "LazyCompile:";
13453 static size_t kPreambleLen = sizeof(kPreamble) - 1;
13455 if (event->name.len < sizeof(kPreamble) - 1 ||
13456 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13460 const char* tail = event->name.str + kPreambleLen;
13461 size_t tail_len = event->name.len - kPreambleLen;
13462 size_t expected_len = strlen(expected);
13463 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13468 // Check for tails like 'bar :1'.
13469 if (tail_len > expected_len + 2 &&
13470 tail[expected_len] == ' ' &&
13471 tail[expected_len + 1] == ':' &&
13472 tail[expected_len + 2] &&
13473 !strncmp(tail, expected, expected_len)) {
13477 if (tail_len != expected_len)
13480 return strncmp(tail, expected, expected_len) == 0;
13484 static void event_handler(const v8::JitCodeEvent* event) {
13485 CHECK(event != NULL);
13486 CHECK(code_map != NULL);
13487 CHECK(jitcode_line_info != NULL);
13489 class DummyJitCodeLineInfo {
13492 switch (event->type) {
13493 case v8::JitCodeEvent::CODE_ADDED: {
13494 CHECK(event->code_start != NULL);
13495 CHECK_NE(0, static_cast<int>(event->code_len));
13496 CHECK(event->name.str != NULL);
13497 i::HashMap::Entry* entry =
13498 code_map->Lookup(event->code_start,
13499 i::ComputePointerHash(event->code_start),
13501 entry->value = reinterpret_cast<void*>(event->code_len);
13503 if (FunctionNameIs("bar", event)) {
13509 case v8::JitCodeEvent::CODE_MOVED: {
13510 uint32_t hash = i::ComputePointerHash(event->code_start);
13511 // We would like to never see code move that we haven't seen before,
13512 // but the code creation event does not happen until the line endings
13513 // have been calculated (this is so that we can report the line in the
13514 // script at which the function source is found, see
13515 // Compiler::RecordFunctionCompilation) and the line endings
13516 // calculations can cause a GC, which can move the newly created code
13517 // before its existence can be logged.
13518 i::HashMap::Entry* entry =
13519 code_map->Lookup(event->code_start, hash, false);
13520 if (entry != NULL) {
13523 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
13524 code_map->Remove(event->code_start, hash);
13526 entry = code_map->Lookup(event->new_code_start,
13527 i::ComputePointerHash(event->new_code_start),
13529 CHECK(entry != NULL);
13530 entry->value = reinterpret_cast<void*>(event->code_len);
13535 case v8::JitCodeEvent::CODE_REMOVED:
13536 // Object/code removal events are currently not dispatched from the GC.
13540 // For CODE_START_LINE_INFO_RECORDING event, we will create one
13541 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
13542 // record it in jitcode_line_info.
13543 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
13544 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
13545 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
13546 temp_event->user_data = line_info;
13547 i::HashMap::Entry* entry =
13548 jitcode_line_info->Lookup(line_info,
13549 i::ComputePointerHash(line_info),
13551 entry->value = reinterpret_cast<void*>(line_info);
13554 // For these two events, we will check whether the event->user_data
13555 // data structure is created before during CODE_START_LINE_INFO_RECORDING
13556 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
13557 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
13558 CHECK(event->user_data != NULL);
13559 uint32_t hash = i::ComputePointerHash(event->user_data);
13560 i::HashMap::Entry* entry =
13561 jitcode_line_info->Lookup(event->user_data, hash, false);
13562 CHECK(entry != NULL);
13563 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
13567 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
13568 CHECK(event->user_data != NULL);
13569 uint32_t hash = i::ComputePointerHash(event->user_data);
13570 i::HashMap::Entry* entry =
13571 jitcode_line_info->Lookup(event->user_data, hash, false);
13572 CHECK(entry != NULL);
13577 // Impossible event.
13584 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
13585 i::FLAG_stress_compaction = true;
13586 i::FLAG_incremental_marking = false;
13587 const char* script =
13590 " for (i = 0; i < 100; ++i)"
13594 "function foo(i) { return i * i; };"
13597 // Run this test in a new isolate to make sure we don't
13598 // have remnants of state from other code.
13599 v8::Isolate* isolate = v8::Isolate::New();
13601 i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
13604 v8::HandleScope scope(isolate);
13605 i::HashMap code(MatchPointers);
13608 i::HashMap lineinfo(MatchPointers);
13609 jitcode_line_info = &lineinfo;
13614 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
13616 // Generate new code objects sparsely distributed across several
13617 // different fragmented code-space pages.
13618 const int kIterations = 10;
13619 for (int i = 0; i < kIterations; ++i) {
13620 LocalContext env(isolate);
13621 i::AlwaysAllocateScope always_allocate;
13622 SimulateFullSpace(heap->code_space());
13623 CompileRun(script);
13625 // Keep a strong reference to the code object in the handle scope.
13626 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
13627 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
13628 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
13629 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
13631 // Clear the compilation cache to get more wastage.
13632 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
13635 // Force code movement.
13636 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
13638 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13640 CHECK_LE(kIterations, saw_bar);
13641 CHECK_LT(0, move_events);
13644 jitcode_line_info = NULL;
13648 isolate->Dispose();
13650 // Do this in a new isolate.
13651 isolate = v8::Isolate::New();
13654 // Verify that we get callbacks for existing code objects when we
13655 // request enumeration of existing code.
13657 v8::HandleScope scope(isolate);
13658 LocalContext env(isolate);
13659 CompileRun(script);
13661 // Now get code through initial iteration.
13662 i::HashMap code(MatchPointers);
13665 i::HashMap lineinfo(MatchPointers);
13666 jitcode_line_info = &lineinfo;
13668 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
13669 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13671 jitcode_line_info = NULL;
13672 // We expect that we got some events. Note that if we could get code removal
13673 // notifications, we could compare two collections, one created by listening
13674 // from the time of creation of an isolate, and the other by subscribing
13675 // with EnumExisting.
13676 CHECK_LT(0, code.occupancy());
13682 isolate->Dispose();
13686 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
13689 THREADED_TEST(ExternalAllocatedMemory) {
13690 v8::Isolate* isolate = CcTest::isolate();
13691 v8::HandleScope outer(isolate);
13692 v8::Local<Context> env(Context::New(isolate));
13693 CHECK(!env.IsEmpty());
13694 const intptr_t kSize = 1024*1024;
13695 int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0));
13696 CHECK_EQ(baseline + cast(kSize),
13697 cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)));
13699 cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)));
13703 // Regression test for issue 54, object templates with internal fields
13704 // but no accessors or interceptors did not get their internal field
13705 // count set on instances.
13706 THREADED_TEST(Regress54) {
13707 LocalContext context;
13708 v8::Isolate* isolate = context->GetIsolate();
13709 v8::HandleScope outer(isolate);
13710 static v8::Persistent<v8::ObjectTemplate> templ;
13711 if (templ.IsEmpty()) {
13712 v8::HandleScope inner(isolate);
13713 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
13714 local->SetInternalFieldCount(1);
13715 templ.Reset(isolate, inner.Close(local));
13717 v8::Handle<v8::Object> result =
13718 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
13719 CHECK_EQ(1, result->InternalFieldCount());
13723 // If part of the threaded tests, this test makes ThreadingTest fail
13725 TEST(CatchStackOverflow) {
13726 LocalContext context;
13727 v8::HandleScope scope(context->GetIsolate());
13728 v8::TryCatch try_catch;
13729 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
13735 v8::Handle<v8::Value> result = script->Run();
13736 CHECK(result.IsEmpty());
13740 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
13741 const char* resource_name,
13743 v8::HandleScope scope(CcTest::isolate());
13744 v8::TryCatch try_catch;
13745 v8::Handle<v8::Value> result = script->Run();
13746 CHECK(result.IsEmpty());
13747 CHECK(try_catch.HasCaught());
13748 v8::Handle<v8::Message> message = try_catch.Message();
13749 CHECK(!message.IsEmpty());
13750 CHECK_EQ(10 + line_offset, message->GetLineNumber());
13751 CHECK_EQ(91, message->GetStartPosition());
13752 CHECK_EQ(92, message->GetEndPosition());
13753 CHECK_EQ(2, message->GetStartColumn());
13754 CHECK_EQ(3, message->GetEndColumn());
13755 v8::String::Utf8Value line(message->GetSourceLine());
13756 CHECK_EQ(" throw 'nirk';", *line);
13757 v8::String::Utf8Value name(message->GetScriptResourceName());
13758 CHECK_EQ(resource_name, *name);
13762 THREADED_TEST(TryCatchSourceInfo) {
13763 LocalContext context;
13764 v8::HandleScope scope(context->GetIsolate());
13765 v8::Handle<v8::String> source = v8::String::New(
13766 "function Foo() {\n"
13770 "function Bar() {\n"
13774 "function Baz() {\n"
13780 const char* resource_name;
13781 v8::Handle<v8::Script> script;
13782 resource_name = "test.js";
13783 script = v8::Script::Compile(source, v8::String::New(resource_name));
13784 CheckTryCatchSourceInfo(script, resource_name, 0);
13786 resource_name = "test1.js";
13787 v8::ScriptOrigin origin1(v8::String::New(resource_name));
13788 script = v8::Script::Compile(source, &origin1);
13789 CheckTryCatchSourceInfo(script, resource_name, 0);
13791 resource_name = "test2.js";
13792 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
13793 script = v8::Script::Compile(source, &origin2);
13794 CheckTryCatchSourceInfo(script, resource_name, 7);
13798 THREADED_TEST(CompilationCache) {
13799 LocalContext context;
13800 v8::HandleScope scope(context->GetIsolate());
13801 v8::Handle<v8::String> source0 = v8::String::New("1234");
13802 v8::Handle<v8::String> source1 = v8::String::New("1234");
13803 v8::Handle<v8::Script> script0 =
13804 v8::Script::Compile(source0, v8::String::New("test.js"));
13805 v8::Handle<v8::Script> script1 =
13806 v8::Script::Compile(source1, v8::String::New("test.js"));
13807 v8::Handle<v8::Script> script2 =
13808 v8::Script::Compile(source0); // different origin
13809 CHECK_EQ(1234, script0->Run()->Int32Value());
13810 CHECK_EQ(1234, script1->Run()->Int32Value());
13811 CHECK_EQ(1234, script2->Run()->Int32Value());
13815 static void FunctionNameCallback(
13816 const v8::FunctionCallbackInfo<v8::Value>& args) {
13817 ApiTestFuzzer::Fuzz();
13818 args.GetReturnValue().Set(v8_num(42));
13822 THREADED_TEST(CallbackFunctionName) {
13823 LocalContext context;
13824 v8::HandleScope scope(context->GetIsolate());
13825 Local<ObjectTemplate> t = ObjectTemplate::New();
13826 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
13827 context->Global()->Set(v8_str("obj"), t->NewInstance());
13828 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
13829 CHECK(value->IsString());
13830 v8::String::Utf8Value name(value);
13831 CHECK_EQ("asdf", *name);
13835 THREADED_TEST(DateAccess) {
13836 LocalContext context;
13837 v8::HandleScope scope(context->GetIsolate());
13838 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
13839 CHECK(date->IsDate());
13840 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
13844 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
13845 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13846 v8::Handle<v8::Array> props = obj->GetPropertyNames();
13847 CHECK_EQ(elmc, props->Length());
13848 for (int i = 0; i < elmc; i++) {
13849 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13850 CHECK_EQ(elmv[i], *elm);
13855 void CheckOwnProperties(v8::Handle<v8::Value> val,
13857 const char* elmv[]) {
13858 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13859 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
13860 CHECK_EQ(elmc, props->Length());
13861 for (int i = 0; i < elmc; i++) {
13862 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13863 CHECK_EQ(elmv[i], *elm);
13868 THREADED_TEST(PropertyEnumeration) {
13869 LocalContext context;
13870 v8::HandleScope scope(context->GetIsolate());
13871 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13874 "result[1] = {a: 1, b: 2};"
13875 "result[2] = [1, 2, 3];"
13876 "var proto = {x: 1, y: 2, z: 3};"
13877 "var x = { __proto__: proto, w: 0, z: 1 };"
13879 "result;"))->Run();
13880 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13881 CHECK_EQ(4, elms->Length());
13883 const char** elmv0 = NULL;
13884 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13885 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13887 const char* elmv1[] = {"a", "b"};
13888 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13889 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13891 const char* elmv2[] = {"0", "1", "2"};
13892 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13893 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13895 const char* elmv3[] = {"w", "z", "x", "y"};
13896 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
13898 const char* elmv4[] = {"w", "z"};
13899 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
13903 THREADED_TEST(PropertyEnumeration2) {
13904 LocalContext context;
13905 v8::HandleScope scope(context->GetIsolate());
13906 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13909 "result[1] = {a: 1, b: 2};"
13910 "result[2] = [1, 2, 3];"
13911 "var proto = {x: 1, y: 2, z: 3};"
13912 "var x = { __proto__: proto, w: 0, z: 1 };"
13914 "result;"))->Run();
13915 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13916 CHECK_EQ(4, elms->Length());
13918 const char** elmv0 = NULL;
13919 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13921 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
13922 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
13923 CHECK_EQ(0, props->Length());
13924 for (uint32_t i = 0; i < props->Length(); i++) {
13925 printf("p[%d]\n", i);
13929 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
13931 v8::AccessType type,
13932 Local<Value> data) {
13933 return type != v8::ACCESS_SET;
13937 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
13939 v8::AccessType type,
13940 Local<Value> data) {
13941 return type != v8::ACCESS_SET;
13945 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
13946 LocalContext context;
13947 v8::Isolate* isolate = context->GetIsolate();
13948 v8::HandleScope scope(isolate);
13949 Local<ObjectTemplate> templ = ObjectTemplate::New();
13950 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13951 IndexedSetAccessBlocker);
13952 templ->Set(v8_str("x"), v8::True(isolate));
13953 Local<v8::Object> instance = templ->NewInstance();
13954 context->Global()->Set(v8_str("obj"), instance);
13955 Local<Value> value = CompileRun("obj.x");
13956 CHECK(value->BooleanValue());
13960 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
13962 v8::AccessType type,
13963 Local<Value> data) {
13968 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
13970 v8::AccessType type,
13971 Local<Value> data) {
13977 THREADED_TEST(AccessChecksReenabledCorrectly) {
13978 LocalContext context;
13979 v8::HandleScope scope(context->GetIsolate());
13980 Local<ObjectTemplate> templ = ObjectTemplate::New();
13981 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13982 IndexedGetAccessBlocker);
13983 templ->Set(v8_str("a"), v8_str("a"));
13984 // Add more than 8 (see kMaxFastProperties) properties
13985 // so that the constructor will force copying map.
13986 // Cannot sprintf, gcc complains unsafety.
13988 for (char i = '0'; i <= '9' ; i++) {
13990 for (char j = '0'; j <= '9'; j++) {
13992 for (char k = '0'; k <= '9'; k++) {
13995 templ->Set(v8_str(buf), v8::Number::New(k));
14000 Local<v8::Object> instance_1 = templ->NewInstance();
14001 context->Global()->Set(v8_str("obj_1"), instance_1);
14003 Local<Value> value_1 = CompileRun("obj_1.a");
14004 CHECK(value_1->IsUndefined());
14006 Local<v8::Object> instance_2 = templ->NewInstance();
14007 context->Global()->Set(v8_str("obj_2"), instance_2);
14009 Local<Value> value_2 = CompileRun("obj_2.a");
14010 CHECK(value_2->IsUndefined());
14014 // This tests that access check information remains on the global
14015 // object template when creating contexts.
14016 THREADED_TEST(AccessControlRepeatedContextCreation) {
14017 v8::Isolate* isolate = CcTest::isolate();
14018 v8::HandleScope handle_scope(isolate);
14019 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14020 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14021 IndexedSetAccessBlocker);
14022 i::Handle<i::ObjectTemplateInfo> internal_template =
14023 v8::Utils::OpenHandle(*global_template);
14024 CHECK(!internal_template->constructor()->IsUndefined());
14025 i::Handle<i::FunctionTemplateInfo> constructor(
14026 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14027 CHECK(!constructor->access_check_info()->IsUndefined());
14028 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14029 CHECK(!context0.IsEmpty());
14030 CHECK(!constructor->access_check_info()->IsUndefined());
14034 THREADED_TEST(TurnOnAccessCheck) {
14035 v8::Isolate* isolate = CcTest::isolate();
14036 v8::HandleScope handle_scope(isolate);
14038 // Create an environment with access check to the global object disabled by
14040 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14041 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14042 IndexedGetAccessBlocker,
14043 v8::Handle<v8::Value>(),
14045 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14046 Context::Scope context_scope(context);
14048 // Set up a property and a number of functions.
14049 context->Global()->Set(v8_str("a"), v8_num(1));
14050 CompileRun("function f1() {return a;}"
14051 "function f2() {return a;}"
14052 "function g1() {return h();}"
14053 "function g2() {return h();}"
14054 "function h() {return 1;}");
14055 Local<Function> f1 =
14056 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14057 Local<Function> f2 =
14058 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14059 Local<Function> g1 =
14060 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14061 Local<Function> g2 =
14062 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14063 Local<Function> h =
14064 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14066 // Get the global object.
14067 v8::Handle<v8::Object> global = context->Global();
14069 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14070 // uses the runtime system to retreive property a whereas f2 uses global load
14072 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14073 for (int i = 0; i < 4; i++) {
14074 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14077 // Same for g1 and g2.
14078 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14079 for (int i = 0; i < 4; i++) {
14080 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14083 // Detach the global and turn on access check.
14084 context->DetachGlobal();
14085 context->Global()->TurnOnAccessCheck();
14087 // Failing access check to property get results in undefined.
14088 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14089 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14091 // Failing access check to function call results in exception.
14092 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14093 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14095 // No failing access check when just returning a constant.
14096 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14100 static const char* kPropertyA = "a";
14101 static const char* kPropertyH = "h";
14103 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14105 v8::AccessType type,
14106 Local<Value> data) {
14107 if (!name->IsString()) return false;
14108 i::Handle<i::String> name_handle =
14109 v8::Utils::OpenHandle(String::Cast(*name));
14110 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14111 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14115 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14116 v8::Isolate* isolate = CcTest::isolate();
14117 v8::HandleScope handle_scope(isolate);
14119 // Create an environment with access check to the global object disabled by
14120 // default. When the registered access checker will block access to properties
14122 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14123 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14124 IndexedGetAccessBlocker,
14125 v8::Handle<v8::Value>(),
14127 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14128 Context::Scope context_scope(context);
14130 // Set up a property and a number of functions.
14131 context->Global()->Set(v8_str("a"), v8_num(1));
14132 static const char* source = "function f1() {return a;}"
14133 "function f2() {return a;}"
14134 "function g1() {return h();}"
14135 "function g2() {return h();}"
14136 "function h() {return 1;}";
14138 CompileRun(source);
14139 Local<Function> f1;
14140 Local<Function> f2;
14141 Local<Function> g1;
14142 Local<Function> g2;
14144 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14145 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14146 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14147 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14148 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14150 // Get the global object.
14151 v8::Handle<v8::Object> global = context->Global();
14153 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14154 // uses the runtime system to retreive property a whereas f2 uses global load
14156 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14157 for (int i = 0; i < 4; i++) {
14158 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14161 // Same for g1 and g2.
14162 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14163 for (int i = 0; i < 4; i++) {
14164 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14167 // Detach the global and turn on access check now blocking access to property
14168 // a and function h.
14169 context->DetachGlobal();
14170 context->Global()->TurnOnAccessCheck();
14172 // Failing access check to property get results in undefined.
14173 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14174 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14176 // Failing access check to function call results in exception.
14177 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14178 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14180 // No failing access check when just returning a constant.
14181 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14183 // Now compile the source again. And get the newly compiled functions, except
14184 // for h for which access is blocked.
14185 CompileRun(source);
14186 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14187 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14188 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14189 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14190 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
14192 // Failing access check to property get results in undefined.
14193 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14194 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14196 // Failing access check to function call results in exception.
14197 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14198 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14202 // This test verifies that pre-compilation (aka preparsing) can be called
14203 // without initializing the whole VM. Thus we cannot run this test in a
14204 // multi-threaded setup.
14206 // TODO(155): This test would break without the initialization of V8. This is
14207 // a workaround for now to make this test not fail.
14208 v8::V8::Initialize();
14209 v8::Isolate* isolate = CcTest::isolate();
14210 const char* script = "function foo(a) { return a+1; }";
14211 v8::ScriptData* sd =
14212 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14213 CHECK_NE(sd->Length(), 0);
14214 CHECK_NE(sd->Data(), NULL);
14215 CHECK(!sd->HasError());
14220 TEST(PreCompileWithError) {
14221 v8::V8::Initialize();
14222 v8::Isolate* isolate = CcTest::isolate();
14223 const char* script = "function foo(a) { return 1 * * 2; }";
14224 v8::ScriptData* sd =
14225 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14226 CHECK(sd->HasError());
14231 TEST(Regress31661) {
14232 v8::V8::Initialize();
14233 v8::Isolate* isolate = CcTest::isolate();
14234 const char* script = " The Definintive Guide";
14235 v8::ScriptData* sd =
14236 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14237 CHECK(sd->HasError());
14242 // Tests that ScriptData can be serialized and deserialized.
14243 TEST(PreCompileSerialization) {
14244 v8::V8::Initialize();
14245 v8::Isolate* isolate = CcTest::isolate();
14246 const char* script = "function foo(a) { return a+1; }";
14247 v8::ScriptData* sd =
14248 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14251 int serialized_data_length = sd->Length();
14252 char* serialized_data = i::NewArray<char>(serialized_data_length);
14253 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14256 v8::ScriptData* deserialized_sd =
14257 v8::ScriptData::New(serialized_data, serialized_data_length);
14259 // Verify that the original is the same as the deserialized.
14260 CHECK_EQ(sd->Length(), deserialized_sd->Length());
14261 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14262 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14265 delete deserialized_sd;
14269 // Attempts to deserialize bad data.
14270 TEST(PreCompileDeserializationError) {
14271 v8::V8::Initialize();
14272 const char* data = "DONT CARE";
14273 int invalid_size = 3;
14274 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14276 CHECK_EQ(0, sd->Length());
14282 // Attempts to deserialize bad data.
14283 TEST(PreCompileInvalidPreparseDataError) {
14284 v8::V8::Initialize();
14285 v8::Isolate* isolate = CcTest::isolate();
14286 LocalContext context;
14287 v8::HandleScope scope(context->GetIsolate());
14289 const char* script = "function foo(){ return 5;}\n"
14290 "function bar(){ return 6 + 7;} foo();";
14291 v8::ScriptData* sd =
14292 v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14293 CHECK(!sd->HasError());
14294 // ScriptDataImpl private implementation details
14295 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14296 const int kFunctionEntrySize = i::FunctionEntry::kSize;
14297 const int kFunctionEntryStartOffset = 0;
14298 const int kFunctionEntryEndOffset = 1;
14299 unsigned* sd_data =
14300 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14302 // Overwrite function bar's end position with 0.
14303 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14304 v8::TryCatch try_catch;
14306 Local<String> source = String::New(script);
14307 Local<Script> compiled_script = Script::New(source, NULL, sd);
14308 CHECK(try_catch.HasCaught());
14309 String::Utf8Value exception_value(try_catch.Message()->Get());
14310 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14315 // Overwrite function bar's start position with 200. The function entry
14316 // will not be found when searching for it by position and we should fall
14317 // back on eager compilation.
14318 sd = v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14319 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14320 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14322 compiled_script = Script::New(source, NULL, sd);
14323 CHECK(!try_catch.HasCaught());
14329 // Verifies that the Handle<String> and const char* versions of the API produce
14330 // the same results (at least for one trivial case).
14331 TEST(PreCompileAPIVariationsAreSame) {
14332 v8::V8::Initialize();
14333 v8::Isolate* isolate = CcTest::isolate();
14334 v8::HandleScope scope(isolate);
14336 const char* cstring = "function foo(a) { return a+1; }";
14338 v8::ScriptData* sd_from_cstring =
14339 v8::ScriptData::PreCompile(isolate, cstring, i::StrLength(cstring));
14341 TestAsciiResource* resource = new TestAsciiResource(cstring);
14342 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
14343 v8::String::NewExternal(resource));
14345 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
14346 v8::String::New(cstring));
14348 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
14349 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14350 sd_from_external_string->Data(),
14351 sd_from_cstring->Length()));
14353 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
14354 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14355 sd_from_string->Data(),
14356 sd_from_cstring->Length()));
14359 delete sd_from_cstring;
14360 delete sd_from_external_string;
14361 delete sd_from_string;
14365 // This tests that we do not allow dictionary load/call inline caches
14366 // to use functions that have not yet been compiled. The potential
14367 // problem of loading a function that has not yet been compiled can
14368 // arise because we share code between contexts via the compilation
14370 THREADED_TEST(DictionaryICLoadedFunction) {
14371 v8::HandleScope scope(CcTest::isolate());
14373 for (int i = 0; i < 2; i++) {
14374 LocalContext context;
14375 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14376 context->Global()->Delete(v8_str("tmp"));
14377 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14380 for (int i = 0; i < 2; i++) {
14381 LocalContext context;
14382 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14383 context->Global()->Delete(v8_str("tmp"));
14384 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14389 // Test that cross-context new calls use the context of the callee to
14390 // create the new JavaScript object.
14391 THREADED_TEST(CrossContextNew) {
14392 v8::Isolate* isolate = CcTest::isolate();
14393 v8::HandleScope scope(isolate);
14394 v8::Local<Context> context0 = Context::New(isolate);
14395 v8::Local<Context> context1 = Context::New(isolate);
14397 // Allow cross-domain access.
14398 Local<String> token = v8_str("<security token>");
14399 context0->SetSecurityToken(token);
14400 context1->SetSecurityToken(token);
14402 // Set an 'x' property on the Object prototype and define a
14403 // constructor function in context0.
14405 CompileRun("Object.prototype.x = 42; function C() {};");
14408 // Call the constructor function from context0 and check that the
14409 // result has the 'x' property.
14411 context1->Global()->Set(v8_str("other"), context0->Global());
14412 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14413 CHECK(value->IsInt32());
14414 CHECK_EQ(42, value->Int32Value());
14419 class ApplyInterruptTest {
14421 ApplyInterruptTest() : block_(0) {}
14422 ~ApplyInterruptTest() {}
14425 gc_during_apply_ = 0;
14426 apply_success_ = false;
14427 gc_success_ = false;
14428 GCThread gc_thread(this);
14430 v8::Isolate* isolate = CcTest::isolate();
14431 v8::Locker::StartPreemption(isolate, 1);
14433 LongRunningApply();
14435 v8::Unlocker unlock(isolate);
14438 v8::Locker::StopPreemption(isolate);
14439 CHECK(apply_success_);
14440 CHECK(gc_success_);
14444 // Number of garbage collections required.
14445 static const int kRequiredGCs = 2;
14447 class GCThread : public i::Thread {
14449 explicit GCThread(ApplyInterruptTest* test)
14450 : Thread("GCThread"), test_(test) {}
14451 virtual void Run() {
14452 test_->CollectGarbage();
14455 ApplyInterruptTest* test_;
14458 void CollectGarbage() {
14460 while (gc_during_apply_ < kRequiredGCs) {
14462 v8::Locker lock(CcTest::isolate());
14463 v8::Isolate::Scope isolate_scope(CcTest::isolate());
14464 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14469 gc_success_ = true;
14472 void LongRunningApply() {
14475 while (gc_during_apply_ < kRequiredGCs) {
14476 int gc_before = gc_count_;
14478 const char* c_source =
14479 "function do_very_little(bar) {"
14482 "for (var i = 0; i < 100000; i++) {"
14483 " do_very_little.apply(this, ['bar']);"
14485 Local<String> source = String::New(c_source);
14486 Local<Script> script = Script::Compile(source);
14487 Local<Value> result = script->Run();
14488 // Check that no exception was thrown.
14489 CHECK(!result.IsEmpty());
14491 int gc_after = gc_count_;
14492 gc_during_apply_ += gc_after - gc_before;
14495 apply_success_ = true;
14498 i::Semaphore block_;
14500 int gc_during_apply_;
14501 bool apply_success_;
14506 // Test that nothing bad happens if we get a preemption just when we were
14507 // about to do an apply().
14508 TEST(ApplyInterruption) {
14509 v8::Locker lock(CcTest::isolate());
14510 v8::V8::Initialize();
14511 v8::HandleScope scope(CcTest::isolate());
14512 Local<Context> local_env;
14515 local_env = env.local();
14518 // Local context should still be live.
14519 CHECK(!local_env.IsEmpty());
14520 local_env->Enter();
14522 // Should complete without problems.
14523 ApplyInterruptTest().RunTest();
14529 // Verify that we can clone an object
14530 TEST(ObjectClone) {
14532 v8::HandleScope scope(env->GetIsolate());
14534 const char* sample =
14536 "rv.alpha = 'hello';" \
14540 // Create an object, verify basics.
14541 Local<Value> val = CompileRun(sample);
14542 CHECK(val->IsObject());
14543 Local<v8::Object> obj = val.As<v8::Object>();
14544 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14546 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14547 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14548 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14551 Local<v8::Object> clone = obj->Clone();
14552 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14553 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
14554 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14556 // Set a property on the clone, verify each object.
14557 clone->Set(v8_str("beta"), v8::Integer::New(456));
14558 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14559 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
14563 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14565 explicit AsciiVectorResource(i::Vector<const char> vector)
14567 virtual ~AsciiVectorResource() {}
14568 virtual size_t length() const { return data_.length(); }
14569 virtual const char* data() const { return data_.start(); }
14571 i::Vector<const char> data_;
14575 class UC16VectorResource : public v8::String::ExternalStringResource {
14577 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14579 virtual ~UC16VectorResource() {}
14580 virtual size_t length() const { return data_.length(); }
14581 virtual const i::uc16* data() const { return data_.start(); }
14583 i::Vector<const i::uc16> data_;
14587 static void MorphAString(i::String* string,
14588 AsciiVectorResource* ascii_resource,
14589 UC16VectorResource* uc16_resource) {
14590 CHECK(i::StringShape(string).IsExternal());
14591 if (string->IsOneByteRepresentation()) {
14592 // Check old map is not internalized or long.
14593 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
14594 // Morph external string to be TwoByte string.
14595 string->set_map(CcTest::heap()->external_string_map());
14596 i::ExternalTwoByteString* morphed =
14597 i::ExternalTwoByteString::cast(string);
14598 morphed->set_resource(uc16_resource);
14600 // Check old map is not internalized or long.
14601 CHECK(string->map() == CcTest::heap()->external_string_map());
14602 // Morph external string to be ASCII string.
14603 string->set_map(CcTest::heap()->external_ascii_string_map());
14604 i::ExternalAsciiString* morphed =
14605 i::ExternalAsciiString::cast(string);
14606 morphed->set_resource(ascii_resource);
14611 // Test that we can still flatten a string if the components it is built up
14612 // from have been turned into 16 bit strings in the mean time.
14613 THREADED_TEST(MorphCompositeStringTest) {
14614 char utf_buffer[129];
14615 const char* c_string = "Now is the time for all good men"
14616 " to come to the aid of the party";
14617 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14620 i::Factory* factory = CcTest::i_isolate()->factory();
14621 v8::HandleScope scope(env->GetIsolate());
14622 AsciiVectorResource ascii_resource(
14623 i::Vector<const char>(c_string, i::StrLength(c_string)));
14624 UC16VectorResource uc16_resource(
14625 i::Vector<const uint16_t>(two_byte_string,
14626 i::StrLength(c_string)));
14628 Local<String> lhs(v8::Utils::ToLocal(
14629 factory->NewExternalStringFromAscii(&ascii_resource)));
14630 Local<String> rhs(v8::Utils::ToLocal(
14631 factory->NewExternalStringFromAscii(&ascii_resource)));
14633 env->Global()->Set(v8_str("lhs"), lhs);
14634 env->Global()->Set(v8_str("rhs"), rhs);
14637 "var cons = lhs + rhs;"
14638 "var slice = lhs.substring(1, lhs.length - 1);"
14639 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14641 CHECK(lhs->IsOneByte());
14642 CHECK(rhs->IsOneByte());
14644 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
14645 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
14647 // This should UTF-8 without flattening, since everything is ASCII.
14648 Handle<String> cons = v8_compile("cons")->Run().As<String>();
14649 CHECK_EQ(128, cons->Utf8Length());
14651 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
14652 CHECK_EQ(128, nchars);
14653 CHECK_EQ(0, strcmp(
14655 "Now is the time for all good men to come to the aid of the party"
14656 "Now is the time for all good men to come to the aid of the party"));
14658 // Now do some stuff to make sure the strings are flattened, etc.
14660 "/[^a-z]/.test(cons);"
14661 "/[^a-z]/.test(slice);"
14662 "/[^a-z]/.test(slice_on_cons);");
14663 const char* expected_cons =
14664 "Now is the time for all good men to come to the aid of the party"
14665 "Now is the time for all good men to come to the aid of the party";
14666 const char* expected_slice =
14667 "ow is the time for all good men to come to the aid of the part";
14668 const char* expected_slice_on_cons =
14669 "ow is the time for all good men to come to the aid of the party"
14670 "Now is the time for all good men to come to the aid of the part";
14671 CHECK_EQ(String::New(expected_cons),
14672 env->Global()->Get(v8_str("cons")));
14673 CHECK_EQ(String::New(expected_slice),
14674 env->Global()->Get(v8_str("slice")));
14675 CHECK_EQ(String::New(expected_slice_on_cons),
14676 env->Global()->Get(v8_str("slice_on_cons")));
14678 i::DeleteArray(two_byte_string);
14682 TEST(CompileExternalTwoByteSource) {
14683 LocalContext context;
14684 v8::HandleScope scope(context->GetIsolate());
14686 // This is a very short list of sources, which currently is to check for a
14687 // regression caused by r2703.
14688 const char* ascii_sources[] = {
14690 "-0.5", // This mainly testes PushBack in the Scanner.
14691 "--0.5", // This mainly testes PushBack in the Scanner.
14695 // Compile the sources as external two byte strings.
14696 for (int i = 0; ascii_sources[i] != NULL; i++) {
14697 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
14698 UC16VectorResource uc16_resource(
14699 i::Vector<const uint16_t>(two_byte_string,
14700 i::StrLength(ascii_sources[i])));
14701 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
14702 v8::Script::Compile(source);
14703 i::DeleteArray(two_byte_string);
14708 #ifndef V8_INTERPRETED_REGEXP
14710 struct RegExpInterruptionData {
14712 UC16VectorResource* string_resource;
14713 v8::Persistent<v8::String> string;
14714 } regexp_interruption_data;
14717 class RegExpInterruptionThread : public i::Thread {
14719 explicit RegExpInterruptionThread(v8::Isolate* isolate)
14720 : Thread("TimeoutThread"), isolate_(isolate) {}
14722 virtual void Run() {
14723 for (regexp_interruption_data.loop_count = 0;
14724 regexp_interruption_data.loop_count < 7;
14725 regexp_interruption_data.loop_count++) {
14726 i::OS::Sleep(50); // Wait a bit before requesting GC.
14727 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
14729 i::OS::Sleep(50); // Wait a bit before terminating.
14730 v8::V8::TerminateExecution(isolate_);
14734 v8::Isolate* isolate_;
14738 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
14739 if (regexp_interruption_data.loop_count != 2) return;
14740 v8::HandleScope scope(CcTest::isolate());
14741 v8::Local<v8::String> string = v8::Local<v8::String>::New(
14742 CcTest::isolate(), regexp_interruption_data.string);
14743 string->MakeExternal(regexp_interruption_data.string_resource);
14747 // Test that RegExp execution can be interrupted. Specifically, we test
14748 // * interrupting with GC
14749 // * turn the subject string from one-byte internal to two-byte external string
14750 // * force termination
14751 TEST(RegExpInterruption) {
14752 v8::HandleScope scope(CcTest::isolate());
14755 RegExpInterruptionThread timeout_thread(CcTest::isolate());
14757 v8::V8::AddGCPrologueCallback(RunBeforeGC);
14758 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
14759 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
14760 v8::Local<v8::String> string = v8_str(ascii_content);
14762 CcTest::global()->Set(v8_str("a"), string);
14763 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
14764 regexp_interruption_data.string_resource = new UC16VectorResource(
14765 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
14767 v8::TryCatch try_catch;
14768 timeout_thread.Start();
14770 CompileRun("/((a*)*)*b/.exec(a)");
14771 CHECK(try_catch.HasTerminated());
14773 timeout_thread.Join();
14775 delete regexp_interruption_data.string_resource;
14776 regexp_interruption_data.string.Dispose();
14779 #endif // V8_INTERPRETED_REGEXP
14782 // Test that we cannot set a property on the global object if there
14783 // is a read-only property in the prototype chain.
14784 TEST(ReadOnlyPropertyInGlobalProto) {
14785 i::FLAG_es5_readonly = true;
14786 v8::HandleScope scope(CcTest::isolate());
14787 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14788 LocalContext context(0, templ);
14789 v8::Handle<v8::Object> global = context->Global();
14790 v8::Handle<v8::Object> global_proto =
14791 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
14792 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
14793 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
14794 // Check without 'eval' or 'with'.
14795 v8::Handle<v8::Value> res =
14796 CompileRun("function f() { x = 42; return x; }; f()");
14797 CHECK_EQ(v8::Integer::New(0), res);
14798 // Check with 'eval'.
14799 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
14800 CHECK_EQ(v8::Integer::New(0), res);
14801 // Check with 'with'.
14802 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
14803 CHECK_EQ(v8::Integer::New(0), res);
14806 static int force_set_set_count = 0;
14807 static int force_set_get_count = 0;
14808 bool pass_on_get = false;
14810 static void ForceSetGetter(v8::Local<v8::String> name,
14811 const v8::PropertyCallbackInfo<v8::Value>& info) {
14812 force_set_get_count++;
14816 info.GetReturnValue().Set(3);
14819 static void ForceSetSetter(v8::Local<v8::String> name,
14820 v8::Local<v8::Value> value,
14821 const v8::PropertyCallbackInfo<void>& info) {
14822 force_set_set_count++;
14825 static void ForceSetInterceptSetter(
14826 v8::Local<v8::String> name,
14827 v8::Local<v8::Value> value,
14828 const v8::PropertyCallbackInfo<v8::Value>& info) {
14829 force_set_set_count++;
14830 info.GetReturnValue().SetUndefined();
14835 force_set_get_count = 0;
14836 force_set_set_count = 0;
14837 pass_on_get = false;
14839 v8::HandleScope scope(CcTest::isolate());
14840 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14841 v8::Handle<v8::String> access_property = v8::String::New("a");
14842 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
14843 LocalContext context(NULL, templ);
14844 v8::Handle<v8::Object> global = context->Global();
14846 // Ordinary properties
14847 v8::Handle<v8::String> simple_property = v8::String::New("p");
14848 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
14849 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14850 // This should fail because the property is read-only
14851 global->Set(simple_property, v8::Int32::New(5));
14852 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14853 // This should succeed even though the property is read-only
14854 global->ForceSet(simple_property, v8::Int32::New(6));
14855 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
14858 CHECK_EQ(0, force_set_set_count);
14859 CHECK_EQ(0, force_set_get_count);
14860 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14861 // CHECK_EQ the property shouldn't override it, just call the setter
14862 // which in this case does nothing.
14863 global->Set(access_property, v8::Int32::New(7));
14864 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14865 CHECK_EQ(1, force_set_set_count);
14866 CHECK_EQ(2, force_set_get_count);
14867 // Forcing the property to be set should override the accessor without
14869 global->ForceSet(access_property, v8::Int32::New(8));
14870 CHECK_EQ(8, global->Get(access_property)->Int32Value());
14871 CHECK_EQ(1, force_set_set_count);
14872 CHECK_EQ(2, force_set_get_count);
14876 TEST(ForceSetWithInterceptor) {
14877 force_set_get_count = 0;
14878 force_set_set_count = 0;
14879 pass_on_get = false;
14881 v8::HandleScope scope(CcTest::isolate());
14882 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14883 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
14884 LocalContext context(NULL, templ);
14885 v8::Handle<v8::Object> global = context->Global();
14887 v8::Handle<v8::String> some_property = v8::String::New("a");
14888 CHECK_EQ(0, force_set_set_count);
14889 CHECK_EQ(0, force_set_get_count);
14890 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14891 // Setting the property shouldn't override it, just call the setter
14892 // which in this case does nothing.
14893 global->Set(some_property, v8::Int32::New(7));
14894 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14895 CHECK_EQ(1, force_set_set_count);
14896 CHECK_EQ(2, force_set_get_count);
14897 // Getting the property when the interceptor returns an empty handle
14898 // should yield undefined, since the property isn't present on the
14899 // object itself yet.
14900 pass_on_get = true;
14901 CHECK(global->Get(some_property)->IsUndefined());
14902 CHECK_EQ(1, force_set_set_count);
14903 CHECK_EQ(3, force_set_get_count);
14904 // Forcing the property to be set should cause the value to be
14905 // set locally without calling the interceptor.
14906 global->ForceSet(some_property, v8::Int32::New(8));
14907 CHECK_EQ(8, global->Get(some_property)->Int32Value());
14908 CHECK_EQ(1, force_set_set_count);
14909 CHECK_EQ(4, force_set_get_count);
14910 // Reenabling the interceptor should cause it to take precedence over
14912 pass_on_get = false;
14913 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14914 CHECK_EQ(1, force_set_set_count);
14915 CHECK_EQ(5, force_set_get_count);
14916 // The interceptor should also work for other properties
14917 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
14918 CHECK_EQ(1, force_set_set_count);
14919 CHECK_EQ(6, force_set_get_count);
14923 THREADED_TEST(ForceDelete) {
14924 v8::HandleScope scope(CcTest::isolate());
14925 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14926 LocalContext context(NULL, templ);
14927 v8::Handle<v8::Object> global = context->Global();
14929 // Ordinary properties
14930 v8::Handle<v8::String> simple_property = v8::String::New("p");
14931 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
14932 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14933 // This should fail because the property is dont-delete.
14934 CHECK(!global->Delete(simple_property));
14935 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14936 // This should succeed even though the property is dont-delete.
14937 CHECK(global->ForceDelete(simple_property));
14938 CHECK(global->Get(simple_property)->IsUndefined());
14942 static int force_delete_interceptor_count = 0;
14943 static bool pass_on_delete = false;
14946 static void ForceDeleteDeleter(
14947 v8::Local<v8::String> name,
14948 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
14949 force_delete_interceptor_count++;
14950 if (pass_on_delete) return;
14951 info.GetReturnValue().Set(true);
14955 THREADED_TEST(ForceDeleteWithInterceptor) {
14956 force_delete_interceptor_count = 0;
14957 pass_on_delete = false;
14959 v8::HandleScope scope(CcTest::isolate());
14960 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14961 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
14962 LocalContext context(NULL, templ);
14963 v8::Handle<v8::Object> global = context->Global();
14965 v8::Handle<v8::String> some_property = v8::String::New("a");
14966 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
14968 // Deleting a property should get intercepted and nothing should
14970 CHECK_EQ(0, force_delete_interceptor_count);
14971 CHECK(global->Delete(some_property));
14972 CHECK_EQ(1, force_delete_interceptor_count);
14973 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14974 // Deleting the property when the interceptor returns an empty
14975 // handle should not delete the property since it is DontDelete.
14976 pass_on_delete = true;
14977 CHECK(!global->Delete(some_property));
14978 CHECK_EQ(2, force_delete_interceptor_count);
14979 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14980 // Forcing the property to be deleted should delete the value
14981 // without calling the interceptor.
14982 CHECK(global->ForceDelete(some_property));
14983 CHECK(global->Get(some_property)->IsUndefined());
14984 CHECK_EQ(2, force_delete_interceptor_count);
14988 // Make sure that forcing a delete invalidates any IC stubs, so we
14989 // don't read the hole value.
14990 THREADED_TEST(ForceDeleteIC) {
14991 LocalContext context;
14992 v8::HandleScope scope(context->GetIsolate());
14993 // Create a DontDelete variable on the global object.
14994 CompileRun("this.__proto__ = { foo: 'horse' };"
14995 "var foo = 'fish';"
14996 "function f() { return foo.length; }");
14997 // Initialize the IC for foo in f.
14998 CompileRun("for (var i = 0; i < 4; i++) f();");
14999 // Make sure the value of foo is correct before the deletion.
15000 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15001 // Force the deletion of foo.
15002 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15003 // Make sure the value for foo is read from the prototype, and that
15004 // we don't get in trouble with reading the deleted cell value
15006 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15010 TEST(InlinedFunctionAcrossContexts) {
15011 i::FLAG_allow_natives_syntax = true;
15012 v8::Isolate* isolate = CcTest::isolate();
15013 v8::HandleScope outer_scope(isolate);
15014 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15015 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15019 v8::HandleScope inner_scope(CcTest::isolate());
15020 CompileRun("var G = 42; function foo() { return G; }");
15021 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15023 ctx2->Global()->Set(v8_str("o"), foo);
15024 v8::Local<v8::Value> res = CompileRun(
15025 "function f() { return o(); }"
15026 "for (var i = 0; i < 10; ++i) f();"
15027 "%OptimizeFunctionOnNextCall(f);"
15029 CHECK_EQ(42, res->Int32Value());
15031 v8::Handle<v8::String> G_property = v8::String::New("G");
15032 CHECK(ctx1->Global()->ForceDelete(G_property));
15039 " return e.toString();"
15042 "ReferenceError: G is not defined");
15049 static v8::Local<Context> calling_context0;
15050 static v8::Local<Context> calling_context1;
15051 static v8::Local<Context> calling_context2;
15054 // Check that the call to the callback is initiated in
15055 // calling_context2, the directly calling context is calling_context1
15056 // and the callback itself is in calling_context0.
15057 static void GetCallingContextCallback(
15058 const v8::FunctionCallbackInfo<v8::Value>& args) {
15059 ApiTestFuzzer::Fuzz();
15060 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15061 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15062 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15063 args.GetReturnValue().Set(42);
15067 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15068 i::Isolate* isolate = CcTest::i_isolate();
15069 CHECK(isolate != NULL);
15070 CHECK(isolate->context() == NULL);
15071 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15072 v8::HandleScope scope(v8_isolate);
15073 // The following should not crash, but return an empty handle.
15074 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15075 CHECK(current.IsEmpty());
15079 THREADED_TEST(GetCallingContext) {
15080 v8::Isolate* isolate = CcTest::isolate();
15081 v8::HandleScope scope(isolate);
15083 Local<Context> calling_context0(Context::New(isolate));
15084 Local<Context> calling_context1(Context::New(isolate));
15085 Local<Context> calling_context2(Context::New(isolate));
15086 ::calling_context0 = calling_context0;
15087 ::calling_context1 = calling_context1;
15088 ::calling_context2 = calling_context2;
15090 // Allow cross-domain access.
15091 Local<String> token = v8_str("<security token>");
15092 calling_context0->SetSecurityToken(token);
15093 calling_context1->SetSecurityToken(token);
15094 calling_context2->SetSecurityToken(token);
15096 // Create an object with a C++ callback in context0.
15097 calling_context0->Enter();
15098 Local<v8::FunctionTemplate> callback_templ =
15099 v8::FunctionTemplate::New(GetCallingContextCallback);
15100 calling_context0->Global()->Set(v8_str("callback"),
15101 callback_templ->GetFunction());
15102 calling_context0->Exit();
15104 // Expose context0 in context1 and set up a function that calls the
15105 // callback function.
15106 calling_context1->Enter();
15107 calling_context1->Global()->Set(v8_str("context0"),
15108 calling_context0->Global());
15109 CompileRun("function f() { context0.callback() }");
15110 calling_context1->Exit();
15112 // Expose context1 in context2 and call the callback function in
15113 // context0 indirectly through f in context1.
15114 calling_context2->Enter();
15115 calling_context2->Global()->Set(v8_str("context1"),
15116 calling_context1->Global());
15117 CompileRun("context1.f()");
15118 calling_context2->Exit();
15119 ::calling_context0.Clear();
15120 ::calling_context1.Clear();
15121 ::calling_context2.Clear();
15125 // Check that a variable declaration with no explicit initialization
15126 // value does shadow an existing property in the prototype chain.
15127 THREADED_TEST(InitGlobalVarInProtoChain) {
15128 i::FLAG_es52_globals = true;
15129 LocalContext context;
15130 v8::HandleScope scope(context->GetIsolate());
15131 // Introduce a variable in the prototype chain.
15132 CompileRun("__proto__.x = 42");
15133 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15134 CHECK(!result->IsUndefined());
15135 CHECK_EQ(43, result->Int32Value());
15139 // Regression test for issue 398.
15140 // If a function is added to an object, creating a constant function
15141 // field, and the result is cloned, replacing the constant function on the
15142 // original should not affect the clone.
15143 // See http://code.google.com/p/v8/issues/detail?id=398
15144 THREADED_TEST(ReplaceConstantFunction) {
15145 LocalContext context;
15146 v8::HandleScope scope(context->GetIsolate());
15147 v8::Handle<v8::Object> obj = v8::Object::New();
15148 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
15149 v8::Handle<v8::String> foo_string = v8::String::New("foo");
15150 obj->Set(foo_string, func_templ->GetFunction());
15151 v8::Handle<v8::Object> obj_clone = obj->Clone();
15152 obj_clone->Set(foo_string, v8::String::New("Hello"));
15153 CHECK(!obj->Get(foo_string)->IsUndefined());
15157 // Regression test for http://crbug.com/16276.
15158 THREADED_TEST(Regress16276) {
15159 LocalContext context;
15160 v8::HandleScope scope(context->GetIsolate());
15161 // Force the IC in f to be a dictionary load IC.
15162 CompileRun("function f(obj) { return obj.x; }\n"
15163 "var obj = { x: { foo: 42 }, y: 87 };\n"
15166 "for (var i = 0; i < 5; i++) f(obj);");
15167 // Detach the global object to make 'this' refer directly to the
15168 // global object (not the proxy), and make sure that the dictionary
15169 // load IC doesn't mess up loading directly from the global object.
15170 context->DetachGlobal();
15171 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
15174 static void CheckElementValue(i::Isolate* isolate,
15176 i::Handle<i::Object> obj,
15178 i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15179 CHECK_EQ(expected, i::Smi::cast(element)->value());
15183 THREADED_TEST(PixelArray) {
15184 LocalContext context;
15185 i::Isolate* isolate = CcTest::i_isolate();
15186 i::Factory* factory = isolate->factory();
15187 v8::HandleScope scope(context->GetIsolate());
15188 const int kElementCount = 260;
15189 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15190 i::Handle<i::ExternalPixelArray> pixels =
15191 i::Handle<i::ExternalPixelArray>::cast(
15192 factory->NewExternalArray(kElementCount,
15193 v8::kExternalPixelArray,
15195 // Force GC to trigger verification.
15196 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15197 for (int i = 0; i < kElementCount; i++) {
15198 pixels->set(i, i % 256);
15200 // Force GC to trigger verification.
15201 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15202 for (int i = 0; i < kElementCount; i++) {
15203 CHECK_EQ(i % 256, pixels->get_scalar(i));
15204 CHECK_EQ(i % 256, pixel_data[i]);
15207 v8::Handle<v8::Object> obj = v8::Object::New();
15208 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15209 // Set the elements to be the pixels.
15210 // jsobj->set_elements(*pixels);
15211 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15212 CheckElementValue(isolate, 1, jsobj, 1);
15213 obj->Set(v8_str("field"), v8::Int32::New(1503));
15214 context->Global()->Set(v8_str("pixels"), obj);
15215 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15216 CHECK_EQ(1503, result->Int32Value());
15217 result = CompileRun("pixels[1]");
15218 CHECK_EQ(1, result->Int32Value());
15220 result = CompileRun("var sum = 0;"
15221 "for (var i = 0; i < 8; i++) {"
15222 " sum += pixels[i] = pixels[i] = -i;"
15225 CHECK_EQ(-28, result->Int32Value());
15227 result = CompileRun("var sum = 0;"
15228 "for (var i = 0; i < 8; i++) {"
15229 " sum += pixels[i] = pixels[i] = 0;"
15232 CHECK_EQ(0, result->Int32Value());
15234 result = CompileRun("var sum = 0;"
15235 "for (var i = 0; i < 8; i++) {"
15236 " sum += pixels[i] = pixels[i] = 255;"
15239 CHECK_EQ(8 * 255, result->Int32Value());
15241 result = CompileRun("var sum = 0;"
15242 "for (var i = 0; i < 8; i++) {"
15243 " sum += pixels[i] = pixels[i] = 256 + i;"
15246 CHECK_EQ(2076, result->Int32Value());
15248 result = CompileRun("var sum = 0;"
15249 "for (var i = 0; i < 8; i++) {"
15250 " sum += pixels[i] = pixels[i] = i;"
15253 CHECK_EQ(28, result->Int32Value());
15255 result = CompileRun("var sum = 0;"
15256 "for (var i = 0; i < 8; i++) {"
15257 " sum += pixels[i];"
15260 CHECK_EQ(28, result->Int32Value());
15262 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15263 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15264 i::Handle<i::Object> no_failure;
15266 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15267 ASSERT(!no_failure.is_null());
15268 i::USE(no_failure);
15269 CheckElementValue(isolate, 2, jsobj, 1);
15270 *value.location() = i::Smi::FromInt(256);
15272 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15273 ASSERT(!no_failure.is_null());
15274 i::USE(no_failure);
15275 CheckElementValue(isolate, 255, jsobj, 1);
15276 *value.location() = i::Smi::FromInt(-1);
15278 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15279 ASSERT(!no_failure.is_null());
15280 i::USE(no_failure);
15281 CheckElementValue(isolate, 0, jsobj, 1);
15283 result = CompileRun("for (var i = 0; i < 8; i++) {"
15284 " pixels[i] = (i * 65) - 109;"
15286 "pixels[1] + pixels[6];");
15287 CHECK_EQ(255, result->Int32Value());
15288 CheckElementValue(isolate, 0, jsobj, 0);
15289 CheckElementValue(isolate, 0, jsobj, 1);
15290 CheckElementValue(isolate, 21, jsobj, 2);
15291 CheckElementValue(isolate, 86, jsobj, 3);
15292 CheckElementValue(isolate, 151, jsobj, 4);
15293 CheckElementValue(isolate, 216, jsobj, 5);
15294 CheckElementValue(isolate, 255, jsobj, 6);
15295 CheckElementValue(isolate, 255, jsobj, 7);
15296 result = CompileRun("var sum = 0;"
15297 "for (var i = 0; i < 8; i++) {"
15298 " sum += pixels[i];"
15301 CHECK_EQ(984, result->Int32Value());
15303 result = CompileRun("for (var i = 0; i < 8; i++) {"
15304 " pixels[i] = (i * 1.1);"
15306 "pixels[1] + pixels[6];");
15307 CHECK_EQ(8, result->Int32Value());
15308 CheckElementValue(isolate, 0, jsobj, 0);
15309 CheckElementValue(isolate, 1, jsobj, 1);
15310 CheckElementValue(isolate, 2, jsobj, 2);
15311 CheckElementValue(isolate, 3, jsobj, 3);
15312 CheckElementValue(isolate, 4, jsobj, 4);
15313 CheckElementValue(isolate, 6, jsobj, 5);
15314 CheckElementValue(isolate, 7, jsobj, 6);
15315 CheckElementValue(isolate, 8, jsobj, 7);
15317 result = CompileRun("for (var i = 0; i < 8; i++) {"
15318 " pixels[7] = undefined;"
15321 CHECK_EQ(0, result->Int32Value());
15322 CheckElementValue(isolate, 0, jsobj, 7);
15324 result = CompileRun("for (var i = 0; i < 8; i++) {"
15325 " pixels[6] = '2.3';"
15328 CHECK_EQ(2, result->Int32Value());
15329 CheckElementValue(isolate, 2, jsobj, 6);
15331 result = CompileRun("for (var i = 0; i < 8; i++) {"
15332 " pixels[5] = NaN;"
15335 CHECK_EQ(0, result->Int32Value());
15336 CheckElementValue(isolate, 0, jsobj, 5);
15338 result = CompileRun("for (var i = 0; i < 8; i++) {"
15339 " pixels[8] = Infinity;"
15342 CHECK_EQ(255, result->Int32Value());
15343 CheckElementValue(isolate, 255, jsobj, 8);
15345 result = CompileRun("for (var i = 0; i < 8; i++) {"
15346 " pixels[9] = -Infinity;"
15349 CHECK_EQ(0, result->Int32Value());
15350 CheckElementValue(isolate, 0, jsobj, 9);
15352 result = CompileRun("pixels[3] = 33;"
15353 "delete pixels[3];"
15355 CHECK_EQ(33, result->Int32Value());
15357 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15358 "pixels[2] = 12; pixels[3] = 13;"
15359 "pixels.__defineGetter__('2',"
15360 "function() { return 120; });"
15362 CHECK_EQ(12, result->Int32Value());
15364 result = CompileRun("var js_array = new Array(40);"
15365 "js_array[0] = 77;"
15367 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15369 result = CompileRun("pixels[1] = 23;"
15370 "pixels.__proto__ = [];"
15371 "js_array.__proto__ = pixels;"
15372 "js_array.concat(pixels);");
15373 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15374 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15376 result = CompileRun("pixels[1] = 23;");
15377 CHECK_EQ(23, result->Int32Value());
15379 // Test for index greater than 255. Regression test for:
15380 // http://code.google.com/p/chromium/issues/detail?id=26337.
15381 result = CompileRun("pixels[256] = 255;");
15382 CHECK_EQ(255, result->Int32Value());
15383 result = CompileRun("var i = 0;"
15384 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15386 CHECK_EQ(255, result->Int32Value());
15388 // Make sure that pixel array ICs recognize when a non-pixel array
15389 // is passed to it.
15390 result = CompileRun("function pa_load(p) {"
15392 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15395 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15396 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15397 "just_ints = new Object();"
15398 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15399 "for (var i = 0; i < 10; ++i) {"
15400 " result = pa_load(just_ints);"
15403 CHECK_EQ(32640, result->Int32Value());
15405 // Make sure that pixel array ICs recognize out-of-bound accesses.
15406 result = CompileRun("function pa_load(p, start) {"
15408 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15411 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15412 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15413 "for (var i = 0; i < 10; ++i) {"
15414 " result = pa_load(pixels,-10);"
15417 CHECK_EQ(0, result->Int32Value());
15419 // Make sure that generic ICs properly handles a pixel array.
15420 result = CompileRun("function pa_load(p) {"
15422 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15425 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15426 "just_ints = new Object();"
15427 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15428 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15429 "for (var i = 0; i < 10; ++i) {"
15430 " result = pa_load(pixels);"
15433 CHECK_EQ(32640, result->Int32Value());
15435 // Make sure that generic load ICs recognize out-of-bound accesses in
15437 result = CompileRun("function pa_load(p, start) {"
15439 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15442 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15443 "just_ints = new Object();"
15444 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15445 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15446 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15447 "for (var i = 0; i < 10; ++i) {"
15448 " result = pa_load(pixels,-10);"
15451 CHECK_EQ(0, result->Int32Value());
15453 // Make sure that generic ICs properly handles other types than pixel
15454 // arrays (that the inlined fast pixel array test leaves the right information
15455 // in the right registers).
15456 result = CompileRun("function pa_load(p) {"
15458 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15461 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15462 "just_ints = new Object();"
15463 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15464 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15465 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15466 "sparse_array = new Object();"
15467 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15468 "sparse_array[1000000] = 3;"
15469 "for (var i = 0; i < 10; ++i) {"
15470 " result = pa_load(sparse_array);"
15473 CHECK_EQ(32640, result->Int32Value());
15475 // Make sure that pixel array store ICs clamp values correctly.
15476 result = CompileRun("function pa_store(p) {"
15477 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15479 "pa_store(pixels);"
15481 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15483 CHECK_EQ(48896, result->Int32Value());
15485 // Make sure that pixel array stores correctly handle accesses outside
15486 // of the pixel array..
15487 result = CompileRun("function pa_store(p,start) {"
15488 " for (var j = 0; j < 256; j++) {"
15489 " p[j+start] = j * 2;"
15492 "pa_store(pixels,0);"
15493 "pa_store(pixels,-128);"
15495 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15497 CHECK_EQ(65280, result->Int32Value());
15499 // Make sure that the generic store stub correctly handle accesses outside
15500 // of the pixel array..
15501 result = CompileRun("function pa_store(p,start) {"
15502 " for (var j = 0; j < 256; j++) {"
15503 " p[j+start] = j * 2;"
15506 "pa_store(pixels,0);"
15507 "just_ints = new Object();"
15508 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15509 "pa_store(just_ints, 0);"
15510 "pa_store(pixels,-128);"
15512 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15514 CHECK_EQ(65280, result->Int32Value());
15516 // Make sure that the generic keyed store stub clamps pixel array values
15518 result = CompileRun("function pa_store(p) {"
15519 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15521 "pa_store(pixels);"
15522 "just_ints = new Object();"
15523 "pa_store(just_ints);"
15524 "pa_store(pixels);"
15526 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15528 CHECK_EQ(48896, result->Int32Value());
15530 // Make sure that pixel array loads are optimized by crankshaft.
15531 result = CompileRun("function pa_load(p) {"
15533 " for (var i=0; i<256; ++i) {"
15538 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15539 "for (var i = 0; i < 5000; ++i) {"
15540 " result = pa_load(pixels);"
15543 CHECK_EQ(32640, result->Int32Value());
15545 // Make sure that pixel array stores are optimized by crankshaft.
15546 result = CompileRun("function pa_init(p) {"
15547 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15549 "function pa_load(p) {"
15551 " for (var i=0; i<256; ++i) {"
15556 "for (var i = 0; i < 5000; ++i) {"
15557 " pa_init(pixels);"
15559 "result = pa_load(pixels);"
15561 CHECK_EQ(32640, result->Int32Value());
15567 THREADED_TEST(PixelArrayInfo) {
15568 LocalContext context;
15569 v8::HandleScope scope(context->GetIsolate());
15570 for (int size = 0; size < 100; size += 10) {
15571 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15572 v8::Handle<v8::Object> obj = v8::Object::New();
15573 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15574 CHECK(obj->HasIndexedPropertiesInPixelData());
15575 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15576 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15582 static void NotHandledIndexedPropertyGetter(
15584 const v8::PropertyCallbackInfo<v8::Value>& info) {
15585 ApiTestFuzzer::Fuzz();
15589 static void NotHandledIndexedPropertySetter(
15591 Local<Value> value,
15592 const v8::PropertyCallbackInfo<v8::Value>& info) {
15593 ApiTestFuzzer::Fuzz();
15597 THREADED_TEST(PixelArrayWithInterceptor) {
15598 LocalContext context;
15599 i::Factory* factory = CcTest::i_isolate()->factory();
15600 v8::HandleScope scope(context->GetIsolate());
15601 const int kElementCount = 260;
15602 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15603 i::Handle<i::ExternalPixelArray> pixels =
15604 i::Handle<i::ExternalPixelArray>::cast(
15605 factory->NewExternalArray(kElementCount,
15606 v8::kExternalPixelArray,
15608 for (int i = 0; i < kElementCount; i++) {
15609 pixels->set(i, i % 256);
15611 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
15612 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
15613 NotHandledIndexedPropertySetter);
15614 v8::Handle<v8::Object> obj = templ->NewInstance();
15615 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15616 context->Global()->Set(v8_str("pixels"), obj);
15617 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
15618 CHECK_EQ(1, result->Int32Value());
15619 result = CompileRun("var sum = 0;"
15620 "for (var i = 0; i < 8; i++) {"
15621 " sum += pixels[i] = pixels[i] = -i;"
15624 CHECK_EQ(-28, result->Int32Value());
15625 result = CompileRun("pixels.hasOwnProperty('1')");
15626 CHECK(result->BooleanValue());
15631 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
15632 switch (array_type) {
15633 case v8::kExternalByteArray:
15634 case v8::kExternalUnsignedByteArray:
15635 case v8::kExternalPixelArray:
15638 case v8::kExternalShortArray:
15639 case v8::kExternalUnsignedShortArray:
15642 case v8::kExternalIntArray:
15643 case v8::kExternalUnsignedIntArray:
15644 case v8::kExternalFloatArray:
15647 case v8::kExternalDoubleArray:
15659 template <class ExternalArrayClass, class ElementType>
15660 static void ObjectWithExternalArrayTestHelper(
15661 Handle<Context> context,
15662 v8::Handle<Object> obj,
15664 v8::ExternalArrayType array_type,
15665 int64_t low, int64_t high) {
15666 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15667 i::Isolate* isolate = jsobj->GetIsolate();
15668 obj->Set(v8_str("field"), v8::Int32::New(1503));
15669 context->Global()->Set(v8_str("ext_array"), obj);
15670 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
15671 CHECK_EQ(1503, result->Int32Value());
15672 result = CompileRun("ext_array[1]");
15673 CHECK_EQ(1, result->Int32Value());
15675 // Check pass through of assigned smis
15676 result = CompileRun("var sum = 0;"
15677 "for (var i = 0; i < 8; i++) {"
15678 " sum += ext_array[i] = ext_array[i] = -i;"
15681 CHECK_EQ(-28, result->Int32Value());
15683 // Check assigned smis
15684 result = CompileRun("for (var i = 0; i < 8; i++) {"
15685 " ext_array[i] = i;"
15688 "for (var i = 0; i < 8; i++) {"
15689 " sum += ext_array[i];"
15692 CHECK_EQ(28, result->Int32Value());
15694 // Check assigned smis in reverse order
15695 result = CompileRun("for (var i = 8; --i >= 0; ) {"
15696 " ext_array[i] = i;"
15699 "for (var i = 0; i < 8; i++) {"
15700 " sum += ext_array[i];"
15703 CHECK_EQ(28, result->Int32Value());
15705 // Check pass through of assigned HeapNumbers
15706 result = CompileRun("var sum = 0;"
15707 "for (var i = 0; i < 16; i+=2) {"
15708 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15711 CHECK_EQ(-28, result->Int32Value());
15713 // Check assigned HeapNumbers
15714 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15715 " ext_array[i] = (i * 0.5);"
15718 "for (var i = 0; i < 16; i+=2) {"
15719 " sum += ext_array[i];"
15722 CHECK_EQ(28, result->Int32Value());
15724 // Check assigned HeapNumbers in reverse order
15725 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15726 " ext_array[i] = (i * 0.5);"
15729 "for (var i = 0; i < 16; i+=2) {"
15730 " sum += ext_array[i];"
15733 CHECK_EQ(28, result->Int32Value());
15735 i::ScopedVector<char> test_buf(1024);
15737 // Check legal boundary conditions.
15738 // The repeated loads and stores ensure the ICs are exercised.
15739 const char* boundary_program =
15741 "for (var i = 0; i < 16; i++) {"
15742 " ext_array[i] = %lld;"
15744 " res = ext_array[i];"
15748 i::OS::SNPrintF(test_buf,
15751 result = CompileRun(test_buf.start());
15752 CHECK_EQ(low, result->IntegerValue());
15754 i::OS::SNPrintF(test_buf,
15757 result = CompileRun(test_buf.start());
15758 CHECK_EQ(high, result->IntegerValue());
15760 // Check misprediction of type in IC.
15761 result = CompileRun("var tmp_array = ext_array;"
15763 "for (var i = 0; i < 8; i++) {"
15764 " tmp_array[i] = i;"
15765 " sum += tmp_array[i];"
15771 // Force GC to trigger verification.
15772 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15773 CHECK_EQ(28, result->Int32Value());
15775 // Make sure out-of-range loads do not throw.
15776 i::OS::SNPrintF(test_buf,
15777 "var caught_exception = false;"
15781 " caught_exception = true;"
15783 "caught_exception;",
15785 result = CompileRun(test_buf.start());
15786 CHECK_EQ(false, result->BooleanValue());
15788 // Make sure out-of-range stores do not throw.
15789 i::OS::SNPrintF(test_buf,
15790 "var caught_exception = false;"
15792 " ext_array[%d] = 1;"
15794 " caught_exception = true;"
15796 "caught_exception;",
15798 result = CompileRun(test_buf.start());
15799 CHECK_EQ(false, result->BooleanValue());
15801 // Check other boundary conditions, values and operations.
15802 result = CompileRun("for (var i = 0; i < 8; i++) {"
15803 " ext_array[7] = undefined;"
15806 CHECK_EQ(0, result->Int32Value());
15807 if (array_type == v8::kExternalDoubleArray ||
15808 array_type == v8::kExternalFloatArray) {
15809 CHECK_EQ(static_cast<int>(i::OS::nan_value()),
15811 jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
15813 CheckElementValue(isolate, 0, jsobj, 7);
15816 result = CompileRun("for (var i = 0; i < 8; i++) {"
15817 " ext_array[6] = '2.3';"
15820 CHECK_EQ(2, result->Int32Value());
15823 jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
15825 if (array_type != v8::kExternalFloatArray &&
15826 array_type != v8::kExternalDoubleArray) {
15827 // Though the specification doesn't state it, be explicit about
15828 // converting NaNs and +/-Infinity to zero.
15829 result = CompileRun("for (var i = 0; i < 8; i++) {"
15830 " ext_array[i] = 5;"
15832 "for (var i = 0; i < 8; i++) {"
15833 " ext_array[i] = NaN;"
15836 CHECK_EQ(0, result->Int32Value());
15837 CheckElementValue(isolate, 0, jsobj, 5);
15839 result = CompileRun("for (var i = 0; i < 8; i++) {"
15840 " ext_array[i] = 5;"
15842 "for (var i = 0; i < 8; i++) {"
15843 " ext_array[i] = Infinity;"
15846 int expected_value =
15847 (array_type == v8::kExternalPixelArray) ? 255 : 0;
15848 CHECK_EQ(expected_value, result->Int32Value());
15849 CheckElementValue(isolate, expected_value, jsobj, 5);
15851 result = CompileRun("for (var i = 0; i < 8; i++) {"
15852 " ext_array[i] = 5;"
15854 "for (var i = 0; i < 8; i++) {"
15855 " ext_array[i] = -Infinity;"
15858 CHECK_EQ(0, result->Int32Value());
15859 CheckElementValue(isolate, 0, jsobj, 5);
15861 // Check truncation behavior of integral arrays.
15862 const char* unsigned_data =
15863 "var source_data = [0.6, 10.6];"
15864 "var expected_results = [0, 10];";
15865 const char* signed_data =
15866 "var source_data = [0.6, 10.6, -0.6, -10.6];"
15867 "var expected_results = [0, 10, 0, -10];";
15868 const char* pixel_data =
15869 "var source_data = [0.6, 10.6];"
15870 "var expected_results = [1, 11];";
15872 (array_type == v8::kExternalUnsignedByteArray ||
15873 array_type == v8::kExternalUnsignedShortArray ||
15874 array_type == v8::kExternalUnsignedIntArray);
15875 bool is_pixel_data = array_type == v8::kExternalPixelArray;
15877 i::OS::SNPrintF(test_buf,
15879 "var all_passed = true;"
15880 "for (var i = 0; i < source_data.length; i++) {"
15881 " for (var j = 0; j < 8; j++) {"
15882 " ext_array[j] = source_data[i];"
15884 " all_passed = all_passed &&"
15885 " (ext_array[5] == expected_results[i]);"
15890 (is_pixel_data ? pixel_data : signed_data)));
15891 result = CompileRun(test_buf.start());
15892 CHECK_EQ(true, result->BooleanValue());
15895 i::Handle<ExternalArrayClass> array(
15896 ExternalArrayClass::cast(jsobj->elements()));
15897 for (int i = 0; i < element_count; i++) {
15898 array->set(i, static_cast<ElementType>(i));
15901 // Test complex assignments
15902 result = CompileRun("function ee_op_test_complex_func(sum) {"
15903 " for (var i = 0; i < 40; ++i) {"
15904 " sum += (ext_array[i] += 1);"
15905 " sum += (ext_array[i] -= 1);"
15910 "for (var i=0;i<10000;++i) {"
15911 " sum=ee_op_test_complex_func(sum);"
15914 CHECK_EQ(16000000, result->Int32Value());
15916 // Test count operations
15917 result = CompileRun("function ee_op_test_count_func(sum) {"
15918 " for (var i = 0; i < 40; ++i) {"
15919 " sum += (++ext_array[i]);"
15920 " sum += (--ext_array[i]);"
15925 "for (var i=0;i<10000;++i) {"
15926 " sum=ee_op_test_count_func(sum);"
15929 CHECK_EQ(16000000, result->Int32Value());
15931 result = CompileRun("ext_array[3] = 33;"
15932 "delete ext_array[3];"
15934 CHECK_EQ(33, result->Int32Value());
15936 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
15937 "ext_array[2] = 12; ext_array[3] = 13;"
15938 "ext_array.__defineGetter__('2',"
15939 "function() { return 120; });"
15941 CHECK_EQ(12, result->Int32Value());
15943 result = CompileRun("var js_array = new Array(40);"
15944 "js_array[0] = 77;"
15946 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15948 result = CompileRun("ext_array[1] = 23;"
15949 "ext_array.__proto__ = [];"
15950 "js_array.__proto__ = ext_array;"
15951 "js_array.concat(ext_array);");
15952 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15953 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15955 result = CompileRun("ext_array[1] = 23;");
15956 CHECK_EQ(23, result->Int32Value());
15960 template <class ExternalArrayClass, class ElementType>
15961 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
15964 LocalContext context;
15965 i::Isolate* isolate = CcTest::i_isolate();
15966 i::Factory* factory = isolate->factory();
15967 v8::HandleScope scope(context->GetIsolate());
15968 const int kElementCount = 40;
15969 int element_size = ExternalArrayElementSize(array_type);
15970 ElementType* array_data =
15971 static_cast<ElementType*>(malloc(kElementCount * element_size));
15972 i::Handle<ExternalArrayClass> array =
15973 i::Handle<ExternalArrayClass>::cast(
15974 factory->NewExternalArray(kElementCount, array_type, array_data));
15975 // Force GC to trigger verification.
15976 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15977 for (int i = 0; i < kElementCount; i++) {
15978 array->set(i, static_cast<ElementType>(i));
15980 // Force GC to trigger verification.
15981 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15982 for (int i = 0; i < kElementCount; i++) {
15983 CHECK_EQ(static_cast<int64_t>(i),
15984 static_cast<int64_t>(array->get_scalar(i)));
15985 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
15988 v8::Handle<v8::Object> obj = v8::Object::New();
15989 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15990 // Set the elements to be the external array.
15991 obj->SetIndexedPropertiesToExternalArrayData(array_data,
15996 jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
15998 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15999 context.local(), obj, kElementCount, array_type, low, high);
16001 v8::Handle<v8::Value> result;
16003 // Test more complex manipulations which cause eax to contain values
16004 // that won't be completely overwritten by loads from the arrays.
16005 // This catches bugs in the instructions used for the KeyedLoadIC
16006 // for byte and word types.
16008 const int kXSize = 300;
16009 const int kYSize = 300;
16010 const int kLargeElementCount = kXSize * kYSize * 4;
16011 ElementType* large_array_data =
16012 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16013 v8::Handle<v8::Object> large_obj = v8::Object::New();
16014 // Set the elements to be the external array.
16015 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16017 kLargeElementCount);
16018 context->Global()->Set(v8_str("large_array"), large_obj);
16019 // Initialize contents of a few rows.
16020 for (int x = 0; x < 300; x++) {
16022 int offset = row * 300 * 4;
16023 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16024 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16025 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16026 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16028 offset = row * 300 * 4;
16029 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16030 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16031 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16032 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16034 offset = row * 300 * 4;
16035 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16036 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16037 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16038 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16040 // The goal of the code below is to make "offset" large enough
16041 // that the computation of the index (which goes into eax) has
16042 // high bits set which will not be overwritten by a byte or short
16044 result = CompileRun("var failed = false;"
16046 "for (var i = 0; i < 300; i++) {"
16047 " if (large_array[4 * i] != 127 ||"
16048 " large_array[4 * i + 1] != 0 ||"
16049 " large_array[4 * i + 2] != 0 ||"
16050 " large_array[4 * i + 3] != 127) {"
16054 "offset = 150 * 300 * 4;"
16055 "for (var i = 0; i < 300; i++) {"
16056 " if (large_array[offset + 4 * i] != 127 ||"
16057 " large_array[offset + 4 * i + 1] != 0 ||"
16058 " large_array[offset + 4 * i + 2] != 0 ||"
16059 " large_array[offset + 4 * i + 3] != 127) {"
16063 "offset = 298 * 300 * 4;"
16064 "for (var i = 0; i < 300; i++) {"
16065 " if (large_array[offset + 4 * i] != 127 ||"
16066 " large_array[offset + 4 * i + 1] != 0 ||"
16067 " large_array[offset + 4 * i + 2] != 0 ||"
16068 " large_array[offset + 4 * i + 3] != 127) {"
16073 CHECK_EQ(true, result->BooleanValue());
16074 free(large_array_data);
16077 // The "" property descriptor is overloaded to store information about
16078 // the external array. Ensure that setting and accessing the "" property
16079 // works (it should overwrite the information cached about the external
16080 // array in the DescriptorArray) in various situations.
16081 result = CompileRun("ext_array[''] = 23; ext_array['']");
16082 CHECK_EQ(23, result->Int32Value());
16084 // Property "" set after the external array is associated with the object.
16086 v8::Handle<v8::Object> obj2 = v8::Object::New();
16087 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
16088 obj2->Set(v8_str(""), v8::Int32::New(1503));
16089 // Set the elements to be the external array.
16090 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16093 context->Global()->Set(v8_str("ext_array"), obj2);
16094 result = CompileRun("ext_array['']");
16095 CHECK_EQ(1503, result->Int32Value());
16098 // Property "" set after the external array is associated with the object.
16100 v8::Handle<v8::Object> obj2 = v8::Object::New();
16101 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16102 // Set the elements to be the external array.
16103 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16106 obj2->Set(v8_str(""), v8::Int32::New(1503));
16107 context->Global()->Set(v8_str("ext_array"), obj2);
16108 result = CompileRun("ext_array['']");
16109 CHECK_EQ(1503, result->Int32Value());
16112 // Should reuse the map from previous test.
16114 v8::Handle<v8::Object> obj2 = v8::Object::New();
16115 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16116 // Set the elements to be the external array. Should re-use the map
16117 // from previous test.
16118 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16121 context->Global()->Set(v8_str("ext_array"), obj2);
16122 result = CompileRun("ext_array['']");
16125 // Property "" is a constant function that shouldn't not be interfered with
16126 // when an external array is set.
16128 v8::Handle<v8::Object> obj2 = v8::Object::New();
16130 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16132 // Add a constant function to an object.
16133 context->Global()->Set(v8_str("ext_array"), obj2);
16134 result = CompileRun("ext_array[''] = function() {return 1503;};"
16135 "ext_array['']();");
16137 // Add an external array transition to the same map that
16138 // has the constant transition.
16139 v8::Handle<v8::Object> obj3 = v8::Object::New();
16140 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16141 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16144 context->Global()->Set(v8_str("ext_array"), obj3);
16147 // If a external array transition is in the map, it should get clobbered
16148 // by a constant function.
16150 // Add an external array transition.
16151 v8::Handle<v8::Object> obj3 = v8::Object::New();
16152 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16153 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16157 // Add a constant function to the same map that just got an external array
16159 v8::Handle<v8::Object> obj2 = v8::Object::New();
16160 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16161 context->Global()->Set(v8_str("ext_array"), obj2);
16162 result = CompileRun("ext_array[''] = function() {return 1503;};"
16163 "ext_array['']();");
16170 THREADED_TEST(ExternalByteArray) {
16171 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
16172 v8::kExternalByteArray,
16178 THREADED_TEST(ExternalUnsignedByteArray) {
16179 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
16180 v8::kExternalUnsignedByteArray,
16186 THREADED_TEST(ExternalPixelArray) {
16187 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
16188 v8::kExternalPixelArray,
16194 THREADED_TEST(ExternalShortArray) {
16195 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
16196 v8::kExternalShortArray,
16202 THREADED_TEST(ExternalUnsignedShortArray) {
16203 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
16204 v8::kExternalUnsignedShortArray,
16210 THREADED_TEST(ExternalIntArray) {
16211 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
16212 v8::kExternalIntArray,
16213 INT_MIN, // -2147483648
16214 INT_MAX); // 2147483647
16218 THREADED_TEST(ExternalUnsignedIntArray) {
16219 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
16220 v8::kExternalUnsignedIntArray,
16222 UINT_MAX); // 4294967295
16226 THREADED_TEST(ExternalFloatArray) {
16227 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
16228 v8::kExternalFloatArray,
16234 THREADED_TEST(ExternalDoubleArray) {
16235 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
16236 v8::kExternalDoubleArray,
16242 THREADED_TEST(ExternalArrays) {
16243 TestExternalByteArray();
16244 TestExternalUnsignedByteArray();
16245 TestExternalShortArray();
16246 TestExternalUnsignedShortArray();
16247 TestExternalIntArray();
16248 TestExternalUnsignedIntArray();
16249 TestExternalFloatArray();
16253 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16254 LocalContext context;
16255 v8::HandleScope scope(context->GetIsolate());
16256 for (int size = 0; size < 100; size += 10) {
16257 int element_size = ExternalArrayElementSize(array_type);
16258 void* external_data = malloc(size * element_size);
16259 v8::Handle<v8::Object> obj = v8::Object::New();
16260 obj->SetIndexedPropertiesToExternalArrayData(
16261 external_data, array_type, size);
16262 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16263 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16264 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16265 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16266 free(external_data);
16271 THREADED_TEST(ExternalArrayInfo) {
16272 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
16273 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
16274 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
16275 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
16276 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
16277 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
16278 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
16279 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
16280 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
16284 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
16285 v8::Handle<v8::Object> obj = v8::Object::New();
16286 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16287 last_location = last_message = NULL;
16288 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16289 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16290 CHECK_NE(NULL, last_location);
16291 CHECK_NE(NULL, last_message);
16295 TEST(ExternalArrayLimits) {
16296 LocalContext context;
16297 v8::HandleScope scope(context->GetIsolate());
16298 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
16299 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
16300 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
16301 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
16302 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
16303 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
16304 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
16305 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
16306 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
16307 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
16308 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
16309 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
16310 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
16311 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
16312 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
16313 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
16314 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
16315 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
16319 template <typename ElementType, typename TypedArray,
16320 class ExternalArrayClass>
16321 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16322 int64_t low, int64_t high) {
16323 const int kElementCount = 50;
16325 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16328 v8::Isolate* isolate = env->GetIsolate();
16329 v8::HandleScope handle_scope(isolate);
16331 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16332 backing_store.start(), (kElementCount+2)*sizeof(ElementType));
16333 Local<TypedArray> ta =
16334 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16335 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16336 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16337 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16338 CHECK_EQ(kElementCount*sizeof(ElementType),
16339 static_cast<int>(ta->ByteLength()));
16340 CHECK_EQ(ab, ta->Buffer());
16342 ElementType* data = backing_store.start() + 2;
16343 for (int i = 0; i < kElementCount; i++) {
16344 data[i] = static_cast<ElementType>(i);
16347 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16348 env.local(), ta, kElementCount, array_type, low, high);
16352 THREADED_TEST(Uint8Array) {
16353 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>(
16354 v8::kExternalUnsignedByteArray, 0, 0xFF);
16358 THREADED_TEST(Int8Array) {
16359 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>(
16360 v8::kExternalByteArray, -0x80, 0x7F);
16364 THREADED_TEST(Uint16Array) {
16365 TypedArrayTestHelper<uint16_t,
16367 i::ExternalUnsignedShortArray>(
16368 v8::kExternalUnsignedShortArray, 0, 0xFFFF);
16372 THREADED_TEST(Int16Array) {
16373 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>(
16374 v8::kExternalShortArray, -0x8000, 0x7FFF);
16378 THREADED_TEST(Uint32Array) {
16379 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>(
16380 v8::kExternalUnsignedIntArray, 0, UINT_MAX);
16384 THREADED_TEST(Int32Array) {
16385 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>(
16386 v8::kExternalIntArray, INT_MIN, INT_MAX);
16390 THREADED_TEST(Float32Array) {
16391 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>(
16392 v8::kExternalFloatArray, -500, 500);
16396 THREADED_TEST(Float64Array) {
16397 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>(
16398 v8::kExternalDoubleArray, -500, 500);
16402 THREADED_TEST(Uint8ClampedArray) {
16403 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>(
16404 v8::kExternalPixelArray, 0, 0xFF);
16408 THREADED_TEST(DataView) {
16409 const int kSize = 50;
16411 i::ScopedVector<uint8_t> backing_store(kSize+2);
16414 v8::Isolate* isolate = env->GetIsolate();
16415 v8::HandleScope handle_scope(isolate);
16417 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16418 backing_store.start(), 2 + kSize);
16419 Local<v8::DataView> dv =
16420 v8::DataView::New(ab, 2, kSize);
16421 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16422 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16423 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16424 CHECK_EQ(ab, dv->Buffer());
16428 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16429 THREADED_TEST(Is##View) { \
16430 LocalContext env; \
16431 v8::Isolate* isolate = env->GetIsolate(); \
16432 v8::HandleScope handle_scope(isolate); \
16434 Handle<Value> result = CompileRun( \
16435 "var ab = new ArrayBuffer(128);" \
16436 "new " #View "(ab)"); \
16437 CHECK(result->IsArrayBufferView()); \
16438 CHECK(result->Is##View()); \
16439 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16442 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16443 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16444 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16445 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16446 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16447 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16448 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16449 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16450 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16451 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16453 #undef IS_ARRAY_BUFFER_VIEW_TEST
16457 THREADED_TEST(ScriptContextDependence) {
16459 v8::HandleScope scope(c1->GetIsolate());
16460 const char *source = "foo";
16461 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
16462 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
16463 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
16464 CHECK_EQ(dep->Run()->Int32Value(), 100);
16465 CHECK_EQ(indep->Run()->Int32Value(), 100);
16467 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
16468 CHECK_EQ(dep->Run()->Int32Value(), 100);
16469 CHECK_EQ(indep->Run()->Int32Value(), 101);
16473 THREADED_TEST(StackTrace) {
16474 LocalContext context;
16475 v8::HandleScope scope(context->GetIsolate());
16476 v8::TryCatch try_catch;
16477 const char *source = "function foo() { FAIL.FAIL; }; foo();";
16478 v8::Handle<v8::String> src = v8::String::New(source);
16479 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
16480 v8::Script::New(src, origin)->Run();
16481 CHECK(try_catch.HasCaught());
16482 v8::String::Utf8Value stack(try_catch.StackTrace());
16483 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16487 // Checks that a StackFrame has certain expected values.
16488 void checkStackFrame(const char* expected_script_name,
16489 const char* expected_func_name, int expected_line_number,
16490 int expected_column, bool is_eval, bool is_constructor,
16491 v8::Handle<v8::StackFrame> frame) {
16492 v8::HandleScope scope(CcTest::isolate());
16493 v8::String::Utf8Value func_name(frame->GetFunctionName());
16494 v8::String::Utf8Value script_name(frame->GetScriptName());
16495 if (*script_name == NULL) {
16496 // The situation where there is no associated script, like for evals.
16497 CHECK(expected_script_name == NULL);
16499 CHECK(strstr(*script_name, expected_script_name) != NULL);
16501 CHECK(strstr(*func_name, expected_func_name) != NULL);
16502 CHECK_EQ(expected_line_number, frame->GetLineNumber());
16503 CHECK_EQ(expected_column, frame->GetColumn());
16504 CHECK_EQ(is_eval, frame->IsEval());
16505 CHECK_EQ(is_constructor, frame->IsConstructor());
16509 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16510 v8::HandleScope scope(args.GetIsolate());
16511 const char* origin = "capture-stack-trace-test";
16512 const int kOverviewTest = 1;
16513 const int kDetailedTest = 2;
16515 ASSERT(args.Length() == 1);
16517 int testGroup = args[0]->Int32Value();
16518 if (testGroup == kOverviewTest) {
16519 v8::Handle<v8::StackTrace> stackTrace =
16520 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
16521 CHECK_EQ(4, stackTrace->GetFrameCount());
16522 checkStackFrame(origin, "bar", 2, 10, false, false,
16523 stackTrace->GetFrame(0));
16524 checkStackFrame(origin, "foo", 6, 3, false, false,
16525 stackTrace->GetFrame(1));
16526 // This is the source string inside the eval which has the call to foo.
16527 checkStackFrame(NULL, "", 1, 5, false, false,
16528 stackTrace->GetFrame(2));
16529 // The last frame is an anonymous function which has the initial eval call.
16530 checkStackFrame(origin, "", 8, 7, false, false,
16531 stackTrace->GetFrame(3));
16533 CHECK(stackTrace->AsArray()->IsArray());
16534 } else if (testGroup == kDetailedTest) {
16535 v8::Handle<v8::StackTrace> stackTrace =
16536 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16537 CHECK_EQ(4, stackTrace->GetFrameCount());
16538 checkStackFrame(origin, "bat", 4, 22, false, false,
16539 stackTrace->GetFrame(0));
16540 checkStackFrame(origin, "baz", 8, 3, false, true,
16541 stackTrace->GetFrame(1));
16542 #ifdef ENABLE_DEBUGGER_SUPPORT
16543 bool is_eval = true;
16544 #else // ENABLE_DEBUGGER_SUPPORT
16545 bool is_eval = false;
16546 #endif // ENABLE_DEBUGGER_SUPPORT
16548 // This is the source string inside the eval which has the call to baz.
16549 checkStackFrame(NULL, "", 1, 5, is_eval, false,
16550 stackTrace->GetFrame(2));
16551 // The last frame is an anonymous function which has the initial eval call.
16552 checkStackFrame(origin, "", 10, 1, false, false,
16553 stackTrace->GetFrame(3));
16555 CHECK(stackTrace->AsArray()->IsArray());
16560 // Tests the C++ StackTrace API.
16561 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16562 // THREADED_TEST(CaptureStackTrace) {
16563 TEST(CaptureStackTrace) {
16564 v8::HandleScope scope(CcTest::isolate());
16565 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
16566 Local<ObjectTemplate> templ = ObjectTemplate::New();
16567 templ->Set(v8_str("AnalyzeStackInNativeCode"),
16568 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
16569 LocalContext context(0, templ);
16571 // Test getting OVERVIEW information. Should ignore information that is not
16572 // script name, function name, line number, and column offset.
16573 const char *overview_source =
16574 "function bar() {\n"
16575 " var y; AnalyzeStackInNativeCode(1);\n"
16577 "function foo() {\n"
16581 "var x;eval('new foo();');";
16582 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
16583 v8::Handle<Value> overview_result(
16584 v8::Script::New(overview_src, origin)->Run());
16585 CHECK(!overview_result.IsEmpty());
16586 CHECK(overview_result->IsObject());
16588 // Test getting DETAILED information.
16589 const char *detailed_source =
16590 "function bat() {AnalyzeStackInNativeCode(2);\n"
16593 "function baz() {\n"
16596 "eval('new baz();');";
16597 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
16598 // Make the script using a non-zero line and column offset.
16599 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
16600 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
16601 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16602 v8::Handle<v8::Script> detailed_script(
16603 v8::Script::New(detailed_src, &detailed_origin));
16604 v8::Handle<Value> detailed_result(detailed_script->Run());
16605 CHECK(!detailed_result.IsEmpty());
16606 CHECK(detailed_result->IsObject());
16610 static void StackTraceForUncaughtExceptionListener(
16611 v8::Handle<v8::Message> message,
16612 v8::Handle<Value>) {
16613 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16614 CHECK_EQ(2, stack_trace->GetFrameCount());
16615 checkStackFrame("origin", "foo", 2, 3, false, false,
16616 stack_trace->GetFrame(0));
16617 checkStackFrame("origin", "bar", 5, 3, false, false,
16618 stack_trace->GetFrame(1));
16622 TEST(CaptureStackTraceForUncaughtException) {
16625 v8::HandleScope scope(env->GetIsolate());
16626 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
16627 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16629 Script::Compile(v8_str("function foo() {\n"
16632 "function bar() {\n"
16635 v8_str("origin"))->Run();
16636 v8::Local<v8::Object> global = env->Global();
16637 Local<Value> trouble = global->Get(v8_str("bar"));
16638 CHECK(trouble->IsFunction());
16639 Function::Cast(*trouble)->Call(global, 0, NULL);
16640 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16641 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16645 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16647 v8::HandleScope scope(env->GetIsolate());
16648 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
16650 v8::StackTrace::kDetailed);
16653 "var setters = ['column', 'lineNumber', 'scriptName',\n"
16654 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16655 " 'isConstructor'];\n"
16656 "for (var i = 0; i < setters.length; i++) {\n"
16657 " var prop = setters[i];\n"
16658 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16660 CompileRun("throw 'exception';");
16661 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16665 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
16666 v8::Handle<v8::Value> data) {
16667 // Use the frame where JavaScript is called from.
16668 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16669 CHECK(!stack_trace.IsEmpty());
16670 int frame_count = stack_trace->GetFrameCount();
16671 CHECK_EQ(3, frame_count);
16672 int line_number[] = {1, 2, 5};
16673 for (int i = 0; i < frame_count; i++) {
16674 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16679 // Test that we only return the stack trace at the site where the exception
16680 // is first thrown (not where it is rethrown).
16681 TEST(RethrowStackTrace) {
16683 v8::HandleScope scope(env->GetIsolate());
16684 // We make sure that
16685 // - the stack trace of the ReferenceError in g() is reported.
16686 // - the stack trace is not overwritten when e1 is rethrown by t().
16687 // - the stack trace of e2 does not overwrite that of e1.
16688 const char* source =
16689 "function g() { error; } \n"
16690 "function f() { g(); } \n"
16691 "function t(e) { throw e; } \n"
16694 "} catch (e1) { \n"
16697 " } catch (e2) { \n"
16701 v8::V8::AddMessageListener(RethrowStackTraceHandler);
16702 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16703 CompileRun(source);
16704 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16705 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
16709 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
16710 v8::Handle<v8::Value> data) {
16711 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16712 CHECK(!stack_trace.IsEmpty());
16713 int frame_count = stack_trace->GetFrameCount();
16714 CHECK_EQ(2, frame_count);
16715 int line_number[] = {3, 7};
16716 for (int i = 0; i < frame_count; i++) {
16717 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16722 // Test that we do not recognize identity for primitive exceptions.
16723 TEST(RethrowPrimitiveStackTrace) {
16725 v8::HandleScope scope(env->GetIsolate());
16726 // We do not capture stack trace for non Error objects on creation time.
16727 // Instead, we capture the stack trace on last throw.
16728 const char* source =
16729 "function g() { throw 404; } \n"
16730 "function f() { g(); } \n"
16731 "function t(e) { throw e; } \n"
16734 "} catch (e1) { \n"
16737 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
16738 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16739 CompileRun(source);
16740 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16741 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16745 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
16746 v8::Handle<v8::Value> data) {
16747 // Use the frame where JavaScript is called from.
16748 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16749 CHECK(!stack_trace.IsEmpty());
16750 CHECK_EQ(1, stack_trace->GetFrameCount());
16751 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
16755 // Test that the stack trace is captured when the error object is created and
16756 // not where it is thrown.
16757 TEST(RethrowExistingStackTrace) {
16759 v8::HandleScope scope(env->GetIsolate());
16760 const char* source =
16761 "var e = new Error(); \n"
16763 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
16764 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16765 CompileRun(source);
16766 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16767 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
16771 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
16772 v8::Handle<v8::Value> data) {
16773 // Use the frame where JavaScript is called from.
16774 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16775 CHECK(!stack_trace.IsEmpty());
16776 CHECK_EQ(1, stack_trace->GetFrameCount());
16777 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
16781 // Test that the stack trace is captured where the bogus Error object is thrown.
16782 TEST(RethrowBogusErrorStackTrace) {
16784 v8::HandleScope scope(env->GetIsolate());
16785 const char* source =
16786 "var e = {__proto__: new Error()} \n"
16788 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
16789 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16790 CompileRun(source);
16791 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16792 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16796 void AnalyzeStackOfEvalWithSourceURL(
16797 const v8::FunctionCallbackInfo<v8::Value>& args) {
16798 v8::HandleScope scope(args.GetIsolate());
16799 v8::Handle<v8::StackTrace> stackTrace =
16800 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16801 CHECK_EQ(5, stackTrace->GetFrameCount());
16802 v8::Handle<v8::String> url = v8_str("eval_url");
16803 for (int i = 0; i < 3; i++) {
16804 v8::Handle<v8::String> name =
16805 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16806 CHECK(!name.IsEmpty());
16807 CHECK_EQ(url, name);
16812 TEST(SourceURLInStackTrace) {
16813 v8::HandleScope scope(CcTest::isolate());
16814 Local<ObjectTemplate> templ = ObjectTemplate::New();
16815 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
16816 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
16817 LocalContext context(0, templ);
16819 const char *source =
16820 "function outer() {\n"
16821 "function bar() {\n"
16822 " AnalyzeStackOfEvalWithSourceURL();\n"
16824 "function foo() {\n"
16830 "eval('(' + outer +')()%s');";
16832 i::ScopedVector<char> code(1024);
16833 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
16834 CHECK(CompileRun(code.start())->IsUndefined());
16835 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
16836 CHECK(CompileRun(code.start())->IsUndefined());
16840 static int scriptIdInStack[2];
16842 void AnalyzeScriptIdInStack(
16843 const v8::FunctionCallbackInfo<v8::Value>& args) {
16844 v8::HandleScope scope(args.GetIsolate());
16845 v8::Handle<v8::StackTrace> stackTrace =
16846 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kScriptId);
16847 CHECK_EQ(2, stackTrace->GetFrameCount());
16848 for (int i = 0; i < 2; i++) {
16849 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
16854 TEST(ScriptIdInStackTrace) {
16855 v8::HandleScope scope(CcTest::isolate());
16856 Local<ObjectTemplate> templ = ObjectTemplate::New();
16857 templ->Set(v8_str("AnalyzeScriptIdInStack"),
16858 v8::FunctionTemplate::New(AnalyzeScriptIdInStack));
16859 LocalContext context(0, templ);
16861 v8::Handle<v8::String> scriptSource = v8::String::New(
16862 "function foo() {\n"
16863 " AnalyzeScriptIdInStack();"
16866 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
16867 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16869 for (int i = 0; i < 2; i++) {
16870 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
16871 CHECK_EQ(scriptIdInStack[i], script->GetId());
16876 void AnalyzeStackOfInlineScriptWithSourceURL(
16877 const v8::FunctionCallbackInfo<v8::Value>& args) {
16878 v8::HandleScope scope(args.GetIsolate());
16879 v8::Handle<v8::StackTrace> stackTrace =
16880 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16881 CHECK_EQ(4, stackTrace->GetFrameCount());
16882 v8::Handle<v8::String> url = v8_str("url");
16883 for (int i = 0; i < 3; i++) {
16884 v8::Handle<v8::String> name =
16885 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16886 CHECK(!name.IsEmpty());
16887 CHECK_EQ(url, name);
16892 TEST(InlineScriptWithSourceURLInStackTrace) {
16893 v8::HandleScope scope(CcTest::isolate());
16894 Local<ObjectTemplate> templ = ObjectTemplate::New();
16895 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
16896 v8::FunctionTemplate::New(
16897 AnalyzeStackOfInlineScriptWithSourceURL));
16898 LocalContext context(0, templ);
16900 const char *source =
16901 "function outer() {\n"
16902 "function bar() {\n"
16903 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
16905 "function foo() {\n"
16913 i::ScopedVector<char> code(1024);
16914 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16915 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16916 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16917 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16921 void AnalyzeStackOfDynamicScriptWithSourceURL(
16922 const v8::FunctionCallbackInfo<v8::Value>& args) {
16923 v8::HandleScope scope(args.GetIsolate());
16924 v8::Handle<v8::StackTrace> stackTrace =
16925 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16926 CHECK_EQ(4, stackTrace->GetFrameCount());
16927 v8::Handle<v8::String> url = v8_str("source_url");
16928 for (int i = 0; i < 3; i++) {
16929 v8::Handle<v8::String> name =
16930 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16931 CHECK(!name.IsEmpty());
16932 CHECK_EQ(url, name);
16937 TEST(DynamicWithSourceURLInStackTrace) {
16938 v8::HandleScope scope(CcTest::isolate());
16939 Local<ObjectTemplate> templ = ObjectTemplate::New();
16940 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
16941 v8::FunctionTemplate::New(
16942 AnalyzeStackOfDynamicScriptWithSourceURL));
16943 LocalContext context(0, templ);
16945 const char *source =
16946 "function outer() {\n"
16947 "function bar() {\n"
16948 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
16950 "function foo() {\n"
16958 i::ScopedVector<char> code(1024);
16959 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16960 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16961 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16962 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16966 static void CreateGarbageInOldSpace() {
16967 i::Factory* factory = CcTest::i_isolate()->factory();
16968 v8::HandleScope scope(CcTest::isolate());
16969 i::AlwaysAllocateScope always_allocate;
16970 for (int i = 0; i < 1000; i++) {
16971 factory->NewFixedArray(1000, i::TENURED);
16976 // Test that idle notification can be handled and eventually returns true.
16977 TEST(IdleNotification) {
16978 const intptr_t MB = 1024 * 1024;
16980 v8::HandleScope scope(env->GetIsolate());
16981 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
16982 CreateGarbageInOldSpace();
16983 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
16984 CHECK_GT(size_with_garbage, initial_size + MB);
16985 bool finished = false;
16986 for (int i = 0; i < 200 && !finished; i++) {
16987 finished = v8::V8::IdleNotification();
16989 intptr_t final_size = CcTest::heap()->SizeOfObjects();
16991 CHECK_LT(final_size, initial_size + 1);
16995 // Test that idle notification can be handled and eventually collects garbage.
16996 TEST(IdleNotificationWithSmallHint) {
16997 const intptr_t MB = 1024 * 1024;
16998 const int IdlePauseInMs = 900;
17000 v8::HandleScope scope(env->GetIsolate());
17001 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17002 CreateGarbageInOldSpace();
17003 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17004 CHECK_GT(size_with_garbage, initial_size + MB);
17005 bool finished = false;
17006 for (int i = 0; i < 200 && !finished; i++) {
17007 finished = v8::V8::IdleNotification(IdlePauseInMs);
17009 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17011 CHECK_LT(final_size, initial_size + 1);
17015 // Test that idle notification can be handled and eventually collects garbage.
17016 TEST(IdleNotificationWithLargeHint) {
17017 const intptr_t MB = 1024 * 1024;
17018 const int IdlePauseInMs = 900;
17020 v8::HandleScope scope(env->GetIsolate());
17021 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17022 CreateGarbageInOldSpace();
17023 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17024 CHECK_GT(size_with_garbage, initial_size + MB);
17025 bool finished = false;
17026 for (int i = 0; i < 200 && !finished; i++) {
17027 finished = v8::V8::IdleNotification(IdlePauseInMs);
17029 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17031 CHECK_LT(final_size, initial_size + 1);
17035 TEST(Regress2107) {
17036 const intptr_t MB = 1024 * 1024;
17037 const int kShortIdlePauseInMs = 100;
17038 const int kLongIdlePauseInMs = 1000;
17040 v8::Isolate* isolate = env->GetIsolate();
17041 v8::HandleScope scope(env->GetIsolate());
17042 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17043 // Send idle notification to start a round of incremental GCs.
17044 v8::V8::IdleNotification(kShortIdlePauseInMs);
17045 // Emulate 7 page reloads.
17046 for (int i = 0; i < 7; i++) {
17048 v8::HandleScope inner_scope(env->GetIsolate());
17049 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17051 CreateGarbageInOldSpace();
17054 v8::V8::ContextDisposedNotification();
17055 v8::V8::IdleNotification(kLongIdlePauseInMs);
17057 // Create garbage and check that idle notification still collects it.
17058 CreateGarbageInOldSpace();
17059 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17060 CHECK_GT(size_with_garbage, initial_size + MB);
17061 bool finished = false;
17062 for (int i = 0; i < 200 && !finished; i++) {
17063 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17065 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17066 CHECK_LT(final_size, initial_size + 1);
17069 static uint32_t* stack_limit;
17071 static void GetStackLimitCallback(
17072 const v8::FunctionCallbackInfo<v8::Value>& args) {
17073 stack_limit = reinterpret_cast<uint32_t*>(
17074 CcTest::i_isolate()->stack_guard()->real_climit());
17078 // Uses the address of a local variable to determine the stack top now.
17079 // Given a size, returns an address that is that far from the current
17081 static uint32_t* ComputeStackLimit(uint32_t size) {
17082 uint32_t* answer = &size - (size / sizeof(size));
17083 // If the size is very large and the stack is very near the bottom of
17084 // memory then the calculation above may wrap around and give an address
17085 // that is above the (downwards-growing) stack. In that case we return
17086 // a very low address.
17087 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17092 // We need at least 165kB for an x64 debug build with clang and ASAN.
17093 static const int stack_breathing_room = 256 * i::KB;
17096 TEST(SetResourceConstraints) {
17097 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17099 // Set stack limit.
17100 v8::ResourceConstraints constraints;
17101 constraints.set_stack_limit(set_limit);
17102 CHECK(v8::SetResourceConstraints(&constraints));
17104 // Execute a script.
17106 v8::HandleScope scope(env->GetIsolate());
17107 Local<v8::FunctionTemplate> fun_templ =
17108 v8::FunctionTemplate::New(GetStackLimitCallback);
17109 Local<Function> fun = fun_templ->GetFunction();
17110 env->Global()->Set(v8_str("get_stack_limit"), fun);
17111 CompileRun("get_stack_limit();");
17113 CHECK(stack_limit == set_limit);
17117 TEST(SetResourceConstraintsInThread) {
17118 uint32_t* set_limit;
17120 v8::Locker locker(CcTest::isolate());
17121 set_limit = ComputeStackLimit(stack_breathing_room);
17123 // Set stack limit.
17124 v8::ResourceConstraints constraints;
17125 constraints.set_stack_limit(set_limit);
17126 CHECK(v8::SetResourceConstraints(&constraints));
17128 // Execute a script.
17129 v8::HandleScope scope(CcTest::isolate());
17131 Local<v8::FunctionTemplate> fun_templ =
17132 v8::FunctionTemplate::New(GetStackLimitCallback);
17133 Local<Function> fun = fun_templ->GetFunction();
17134 env->Global()->Set(v8_str("get_stack_limit"), fun);
17135 CompileRun("get_stack_limit();");
17137 CHECK(stack_limit == set_limit);
17140 v8::Locker locker(CcTest::isolate());
17141 CHECK(stack_limit == set_limit);
17146 THREADED_TEST(GetHeapStatistics) {
17148 v8::HandleScope scope(c1->GetIsolate());
17149 v8::HeapStatistics heap_statistics;
17150 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17151 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17152 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17153 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17154 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17158 class VisitorImpl : public v8::ExternalResourceVisitor {
17160 explicit VisitorImpl(TestResource** resource) {
17161 for (int i = 0; i < 4; i++) {
17162 resource_[i] = resource[i];
17163 found_resource_[i] = false;
17166 virtual ~VisitorImpl() {}
17167 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17168 if (!string->IsExternal()) {
17169 CHECK(string->IsExternalAscii());
17172 v8::String::ExternalStringResource* resource =
17173 string->GetExternalStringResource();
17175 for (int i = 0; i < 4; i++) {
17176 if (resource_[i] == resource) {
17177 CHECK(!found_resource_[i]);
17178 found_resource_[i] = true;
17182 void CheckVisitedResources() {
17183 for (int i = 0; i < 4; i++) {
17184 CHECK(found_resource_[i]);
17189 v8::String::ExternalStringResource* resource_[4];
17190 bool found_resource_[4];
17194 TEST(VisitExternalStrings) {
17196 v8::HandleScope scope(env->GetIsolate());
17197 const char* string = "Some string";
17198 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17199 TestResource* resource[4];
17200 resource[0] = new TestResource(two_byte_string);
17201 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
17202 resource[1] = new TestResource(two_byte_string);
17203 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
17205 // Externalized symbol.
17206 resource[2] = new TestResource(two_byte_string);
17207 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
17208 CHECK(string2->MakeExternal(resource[2]));
17210 // Symbolized External.
17211 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17212 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
17213 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17214 // Turn into a symbol.
17215 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17216 CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17217 CHECK(string3_i->IsInternalizedString());
17219 // We need to add usages for string* to avoid warnings in GCC 4.7
17220 CHECK(string0->IsExternal());
17221 CHECK(string1->IsExternal());
17222 CHECK(string2->IsExternal());
17223 CHECK(string3->IsExternal());
17225 VisitorImpl visitor(resource);
17226 v8::V8::VisitExternalResources(&visitor);
17227 visitor.CheckVisitedResources();
17231 static double DoubleFromBits(uint64_t value) {
17233 i::OS::MemCopy(&target, &value, sizeof(target));
17238 static uint64_t DoubleToBits(double value) {
17240 i::OS::MemCopy(&target, &value, sizeof(target));
17245 static double DoubleToDateTime(double input) {
17246 double date_limit = 864e13;
17247 if (std::isnan(input) || input < -date_limit || input > date_limit) {
17248 return i::OS::nan_value();
17250 return (input < 0) ? -(floor(-input)) : floor(input);
17254 // We don't have a consistent way to write 64-bit constants syntactically, so we
17255 // split them into two 32-bit constants and combine them programmatically.
17256 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17257 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17261 THREADED_TEST(QuietSignalingNaNs) {
17262 LocalContext context;
17263 v8::HandleScope scope(context->GetIsolate());
17264 v8::TryCatch try_catch;
17266 // Special double values.
17267 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17268 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17269 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17270 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
17271 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
17272 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
17273 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
17275 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
17276 // on either side of the epoch.
17277 double date_limit = 864e13;
17279 double test_values[] = {
17301 int num_test_values = 20;
17303 for (int i = 0; i < num_test_values; i++) {
17304 double test_value = test_values[i];
17306 // Check that Number::New preserves non-NaNs and quiets SNaNs.
17307 v8::Handle<v8::Value> number = v8::Number::New(test_value);
17308 double stored_number = number->NumberValue();
17309 if (!std::isnan(test_value)) {
17310 CHECK_EQ(test_value, stored_number);
17312 uint64_t stored_bits = DoubleToBits(stored_number);
17313 // Check if quiet nan (bits 51..62 all set).
17314 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17315 // Most significant fraction bit for quiet nan is set to 0
17316 // on MIPS architecture. Allowed by IEEE-754.
17317 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17319 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17323 // Check that Date::New preserves non-NaNs in the date range and
17325 v8::Handle<v8::Value> date = v8::Date::New(test_value);
17326 double expected_stored_date = DoubleToDateTime(test_value);
17327 double stored_date = date->NumberValue();
17328 if (!std::isnan(expected_stored_date)) {
17329 CHECK_EQ(expected_stored_date, stored_date);
17331 uint64_t stored_bits = DoubleToBits(stored_date);
17332 // Check if quiet nan (bits 51..62 all set).
17333 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17334 // Most significant fraction bit for quiet nan is set to 0
17335 // on MIPS architecture. Allowed by IEEE-754.
17336 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17338 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17345 static void SpaghettiIncident(
17346 const v8::FunctionCallbackInfo<v8::Value>& args) {
17347 v8::HandleScope scope(args.GetIsolate());
17349 v8::Handle<v8::String> str(args[0]->ToString());
17351 if (tc.HasCaught())
17356 // Test that an exception can be propagated down through a spaghetti
17357 // stack using ReThrow.
17358 THREADED_TEST(SpaghettiStackReThrow) {
17359 v8::HandleScope scope(CcTest::isolate());
17360 LocalContext context;
17361 context->Global()->Set(
17362 v8::String::New("s"),
17363 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
17364 v8::TryCatch try_catch;
17368 " toString: function () {"
17378 CHECK(try_catch.HasCaught());
17379 v8::String::Utf8Value value(try_catch.Exception());
17380 CHECK_EQ(0, strcmp(*value, "Hey!"));
17385 v8::V8::Initialize();
17386 v8::Isolate* isolate = CcTest::isolate();
17387 v8::HandleScope scope(isolate);
17388 v8::Local<Context> other_context;
17391 // Create a context used to keep the code from aging in the compilation
17393 other_context = Context::New(isolate);
17395 // Context-dependent context data creates reference from the compilation
17396 // cache to the global object.
17397 const char* source_simple = "1";
17399 v8::HandleScope scope(isolate);
17400 v8::Local<Context> context = Context::New(isolate);
17403 Local<v8::String> obj = v8::String::New("");
17404 context->SetEmbedderData(0, obj);
17405 CompileRun(source_simple);
17408 v8::V8::ContextDisposedNotification();
17409 for (gc_count = 1; gc_count < 10; gc_count++) {
17410 other_context->Enter();
17411 CompileRun(source_simple);
17412 other_context->Exit();
17413 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17414 if (GetGlobalObjectsCount() == 1) break;
17416 CHECK_GE(2, gc_count);
17417 CHECK_EQ(1, GetGlobalObjectsCount());
17419 // Eval in a function creates reference from the compilation cache to the
17421 const char* source_eval = "function f(){eval('1')}; f()";
17423 v8::HandleScope scope(isolate);
17424 v8::Local<Context> context = Context::New(isolate);
17427 CompileRun(source_eval);
17430 v8::V8::ContextDisposedNotification();
17431 for (gc_count = 1; gc_count < 10; gc_count++) {
17432 other_context->Enter();
17433 CompileRun(source_eval);
17434 other_context->Exit();
17435 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17436 if (GetGlobalObjectsCount() == 1) break;
17438 CHECK_GE(2, gc_count);
17439 CHECK_EQ(1, GetGlobalObjectsCount());
17441 // Looking up the line number for an exception creates reference from the
17442 // compilation cache to the global object.
17443 const char* source_exception = "function f(){throw 1;} f()";
17445 v8::HandleScope scope(isolate);
17446 v8::Local<Context> context = Context::New(isolate);
17449 v8::TryCatch try_catch;
17450 CompileRun(source_exception);
17451 CHECK(try_catch.HasCaught());
17452 v8::Handle<v8::Message> message = try_catch.Message();
17453 CHECK(!message.IsEmpty());
17454 CHECK_EQ(1, message->GetLineNumber());
17457 v8::V8::ContextDisposedNotification();
17458 for (gc_count = 1; gc_count < 10; gc_count++) {
17459 other_context->Enter();
17460 CompileRun(source_exception);
17461 other_context->Exit();
17462 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17463 if (GetGlobalObjectsCount() == 1) break;
17465 CHECK_GE(2, gc_count);
17466 CHECK_EQ(1, GetGlobalObjectsCount());
17468 v8::V8::ContextDisposedNotification();
17472 THREADED_TEST(ScriptOrigin) {
17474 v8::HandleScope scope(env->GetIsolate());
17475 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17476 v8::Handle<v8::String> script = v8::String::New(
17477 "function f() {}\n\nfunction g() {}");
17478 v8::Script::Compile(script, &origin)->Run();
17479 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17480 env->Global()->Get(v8::String::New("f")));
17481 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17482 env->Global()->Get(v8::String::New("g")));
17484 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
17485 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
17486 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
17488 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
17489 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
17490 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
17494 THREADED_TEST(FunctionGetInferredName) {
17496 v8::HandleScope scope(env->GetIsolate());
17497 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17498 v8::Handle<v8::String> script = v8::String::New(
17499 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
17500 v8::Script::Compile(script, &origin)->Run();
17501 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17502 env->Global()->Get(v8::String::New("f")));
17503 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
17507 THREADED_TEST(FunctionGetDisplayName) {
17509 v8::HandleScope scope(env->GetIsolate());
17510 const char* code = "var error = false;"
17511 "function a() { this.x = 1; };"
17512 "a.displayName = 'display_a';"
17513 "var b = (function() {"
17514 " var f = function() { this.x = 2; };"
17515 " f.displayName = 'display_b';"
17518 "var c = function() {};"
17519 "c.__defineGetter__('displayName', function() {"
17521 " throw new Error();"
17524 "d.__defineGetter__('displayName', function() {"
17526 " return 'wrong_display_name';"
17529 "e.displayName = 'wrong_display_name';"
17530 "e.__defineSetter__('displayName', function() {"
17532 " throw new Error();"
17535 "f.displayName = { 'foo': 6, toString: function() {"
17537 " return 'wrong_display_name';"
17539 "var g = function() {"
17540 " arguments.callee.displayName = 'set_in_runtime';"
17543 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17544 v8::Script::Compile(v8::String::New(code), &origin)->Run();
17545 v8::Local<v8::Value> error = env->Global()->Get(v8::String::New("error"));
17546 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
17547 env->Global()->Get(v8::String::New("a")));
17548 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
17549 env->Global()->Get(v8::String::New("b")));
17550 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
17551 env->Global()->Get(v8::String::New("c")));
17552 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
17553 env->Global()->Get(v8::String::New("d")));
17554 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
17555 env->Global()->Get(v8::String::New("e")));
17556 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17557 env->Global()->Get(v8::String::New("f")));
17558 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17559 env->Global()->Get(v8::String::New("g")));
17560 CHECK_EQ(false, error->BooleanValue());
17561 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
17562 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
17563 CHECK(c->GetDisplayName()->IsUndefined());
17564 CHECK(d->GetDisplayName()->IsUndefined());
17565 CHECK(e->GetDisplayName()->IsUndefined());
17566 CHECK(f->GetDisplayName()->IsUndefined());
17567 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
17571 THREADED_TEST(ScriptLineNumber) {
17573 v8::HandleScope scope(env->GetIsolate());
17574 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17575 v8::Handle<v8::String> script = v8::String::New(
17576 "function f() {}\n\nfunction g() {}");
17577 v8::Script::Compile(script, &origin)->Run();
17578 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17579 env->Global()->Get(v8::String::New("f")));
17580 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17581 env->Global()->Get(v8::String::New("g")));
17582 CHECK_EQ(0, f->GetScriptLineNumber());
17583 CHECK_EQ(2, g->GetScriptLineNumber());
17587 THREADED_TEST(ScriptColumnNumber) {
17589 v8::HandleScope scope(env->GetIsolate());
17590 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17591 v8::Integer::New(3), v8::Integer::New(2));
17592 v8::Handle<v8::String> script = v8::String::New(
17593 "function foo() {}\n\n function bar() {}");
17594 v8::Script::Compile(script, &origin)->Run();
17595 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17596 env->Global()->Get(v8::String::New("foo")));
17597 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17598 env->Global()->Get(v8::String::New("bar")));
17599 CHECK_EQ(14, foo->GetScriptColumnNumber());
17600 CHECK_EQ(17, bar->GetScriptColumnNumber());
17604 THREADED_TEST(FunctionIsBuiltin) {
17606 v8::HandleScope scope(env->GetIsolate());
17607 v8::Local<v8::Function> f;
17608 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
17609 CHECK(f->IsBuiltin());
17610 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
17611 CHECK(f->IsBuiltin());
17612 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
17613 CHECK(f->IsBuiltin());
17614 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
17615 CHECK(f->IsBuiltin());
17616 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
17617 CHECK(!f->IsBuiltin());
17621 THREADED_TEST(FunctionGetScriptId) {
17623 v8::HandleScope scope(env->GetIsolate());
17624 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17625 v8::Integer::New(3), v8::Integer::New(2));
17626 v8::Handle<v8::String> scriptSource = v8::String::New(
17627 "function foo() {}\n\n function bar() {}");
17628 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17630 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17631 env->Global()->Get(v8::String::New("foo")));
17632 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17633 env->Global()->Get(v8::String::New("bar")));
17634 CHECK_EQ(script->Id(), foo->GetScriptId());
17635 CHECK_EQ(script->Id(), bar->GetScriptId());
17639 static void GetterWhichReturns42(
17640 Local<String> name,
17641 const v8::PropertyCallbackInfo<v8::Value>& info) {
17642 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17643 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17644 info.GetReturnValue().Set(v8_num(42));
17648 static void SetterWhichSetsYOnThisTo23(
17649 Local<String> name,
17650 Local<Value> value,
17651 const v8::PropertyCallbackInfo<void>& info) {
17652 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17653 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17654 info.This()->Set(v8_str("y"), v8_num(23));
17658 void FooGetInterceptor(Local<String> name,
17659 const v8::PropertyCallbackInfo<v8::Value>& info) {
17660 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17661 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17662 if (!name->Equals(v8_str("foo"))) return;
17663 info.GetReturnValue().Set(v8_num(42));
17667 void FooSetInterceptor(Local<String> name,
17668 Local<Value> value,
17669 const v8::PropertyCallbackInfo<v8::Value>& info) {
17670 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17671 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17672 if (!name->Equals(v8_str("foo"))) return;
17673 info.This()->Set(v8_str("y"), v8_num(23));
17674 info.GetReturnValue().Set(v8_num(23));
17678 TEST(SetterOnConstructorPrototype) {
17679 v8::HandleScope scope(CcTest::isolate());
17680 Local<ObjectTemplate> templ = ObjectTemplate::New();
17681 templ->SetAccessor(v8_str("x"),
17682 GetterWhichReturns42,
17683 SetterWhichSetsYOnThisTo23);
17684 LocalContext context;
17685 context->Global()->Set(v8_str("P"), templ->NewInstance());
17686 CompileRun("function C1() {"
17689 "C1.prototype = P;"
17693 "C2.prototype = { };"
17694 "C2.prototype.__proto__ = P;");
17696 v8::Local<v8::Script> script;
17697 script = v8::Script::Compile(v8_str("new C1();"));
17698 for (int i = 0; i < 10; i++) {
17699 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17700 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17701 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17704 script = v8::Script::Compile(v8_str("new C2();"));
17705 for (int i = 0; i < 10; i++) {
17706 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17707 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
17708 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
17713 static void NamedPropertyGetterWhichReturns42(
17714 Local<String> name,
17715 const v8::PropertyCallbackInfo<v8::Value>& info) {
17716 info.GetReturnValue().Set(v8_num(42));
17720 static void NamedPropertySetterWhichSetsYOnThisTo23(
17721 Local<String> name,
17722 Local<Value> value,
17723 const v8::PropertyCallbackInfo<v8::Value>& info) {
17724 if (name->Equals(v8_str("x"))) {
17725 info.This()->Set(v8_str("y"), v8_num(23));
17730 THREADED_TEST(InterceptorOnConstructorPrototype) {
17731 v8::HandleScope scope(CcTest::isolate());
17732 Local<ObjectTemplate> templ = ObjectTemplate::New();
17733 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
17734 NamedPropertySetterWhichSetsYOnThisTo23);
17735 LocalContext context;
17736 context->Global()->Set(v8_str("P"), templ->NewInstance());
17737 CompileRun("function C1() {"
17740 "C1.prototype = P;"
17744 "C2.prototype = { };"
17745 "C2.prototype.__proto__ = P;");
17747 v8::Local<v8::Script> script;
17748 script = v8::Script::Compile(v8_str("new C1();"));
17749 for (int i = 0; i < 10; i++) {
17750 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17751 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17752 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17755 script = v8::Script::Compile(v8_str("new C2();"));
17756 for (int i = 0; i < 10; i++) {
17757 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17758 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
17759 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
17765 const char* source = "function C1() {"
17768 "C1.prototype = P;";
17770 LocalContext context;
17771 v8::HandleScope scope(context->GetIsolate());
17772 v8::Local<v8::Script> script;
17774 // Use a simple object as prototype.
17775 v8::Local<v8::Object> prototype = v8::Object::New();
17776 prototype->Set(v8_str("y"), v8_num(42));
17777 context->Global()->Set(v8_str("P"), prototype);
17779 // This compile will add the code to the compilation cache.
17780 CompileRun(source);
17782 script = v8::Script::Compile(v8_str("new C1();"));
17783 // Allow enough iterations for the inobject slack tracking logic
17784 // to finalize instance size and install the fast construct stub.
17785 for (int i = 0; i < 256; i++) {
17786 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17787 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17788 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17791 // Use an API object with accessors as prototype.
17792 Local<ObjectTemplate> templ = ObjectTemplate::New();
17793 templ->SetAccessor(v8_str("x"),
17794 GetterWhichReturns42,
17795 SetterWhichSetsYOnThisTo23);
17796 context->Global()->Set(v8_str("P"), templ->NewInstance());
17798 // This compile will get the code from the compilation cache.
17799 CompileRun(source);
17801 script = v8::Script::Compile(v8_str("new C1();"));
17802 for (int i = 0; i < 10; i++) {
17803 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17804 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17805 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17809 v8::Isolate* gc_callbacks_isolate = NULL;
17810 int prologue_call_count = 0;
17811 int epilogue_call_count = 0;
17812 int prologue_call_count_second = 0;
17813 int epilogue_call_count_second = 0;
17815 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
17816 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17817 ++prologue_call_count;
17821 void PrologueCallback(v8::Isolate* isolate,
17823 v8::GCCallbackFlags flags) {
17824 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17825 CHECK_EQ(gc_callbacks_isolate, isolate);
17826 ++prologue_call_count;
17830 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
17831 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17832 ++epilogue_call_count;
17836 void EpilogueCallback(v8::Isolate* isolate,
17838 v8::GCCallbackFlags flags) {
17839 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17840 CHECK_EQ(gc_callbacks_isolate, isolate);
17841 ++epilogue_call_count;
17845 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17846 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17847 ++prologue_call_count_second;
17851 void PrologueCallbackSecond(v8::Isolate* isolate,
17853 v8::GCCallbackFlags flags) {
17854 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17855 CHECK_EQ(gc_callbacks_isolate, isolate);
17856 ++prologue_call_count_second;
17860 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17861 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17862 ++epilogue_call_count_second;
17866 void EpilogueCallbackSecond(v8::Isolate* isolate,
17868 v8::GCCallbackFlags flags) {
17869 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17870 CHECK_EQ(gc_callbacks_isolate, isolate);
17871 ++epilogue_call_count_second;
17875 TEST(GCCallbacksOld) {
17876 LocalContext context;
17878 v8::V8::AddGCPrologueCallback(PrologueCallback);
17879 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17880 CHECK_EQ(0, prologue_call_count);
17881 CHECK_EQ(0, epilogue_call_count);
17882 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17883 CHECK_EQ(1, prologue_call_count);
17884 CHECK_EQ(1, epilogue_call_count);
17885 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17886 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17887 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17888 CHECK_EQ(2, prologue_call_count);
17889 CHECK_EQ(2, epilogue_call_count);
17890 CHECK_EQ(1, prologue_call_count_second);
17891 CHECK_EQ(1, epilogue_call_count_second);
17892 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17893 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17894 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17895 CHECK_EQ(2, prologue_call_count);
17896 CHECK_EQ(2, epilogue_call_count);
17897 CHECK_EQ(2, prologue_call_count_second);
17898 CHECK_EQ(2, epilogue_call_count_second);
17899 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17900 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17901 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17902 CHECK_EQ(2, prologue_call_count);
17903 CHECK_EQ(2, epilogue_call_count);
17904 CHECK_EQ(2, prologue_call_count_second);
17905 CHECK_EQ(2, epilogue_call_count_second);
17909 TEST(GCCallbacks) {
17910 LocalContext context;
17911 v8::Isolate* isolate = context->GetIsolate();
17912 gc_callbacks_isolate = isolate;
17913 isolate->AddGCPrologueCallback(PrologueCallback);
17914 isolate->AddGCEpilogueCallback(EpilogueCallback);
17915 CHECK_EQ(0, prologue_call_count);
17916 CHECK_EQ(0, epilogue_call_count);
17917 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17918 CHECK_EQ(1, prologue_call_count);
17919 CHECK_EQ(1, epilogue_call_count);
17920 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
17921 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
17922 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17923 CHECK_EQ(2, prologue_call_count);
17924 CHECK_EQ(2, epilogue_call_count);
17925 CHECK_EQ(1, prologue_call_count_second);
17926 CHECK_EQ(1, epilogue_call_count_second);
17927 isolate->RemoveGCPrologueCallback(PrologueCallback);
17928 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
17929 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17930 CHECK_EQ(2, prologue_call_count);
17931 CHECK_EQ(2, epilogue_call_count);
17932 CHECK_EQ(2, prologue_call_count_second);
17933 CHECK_EQ(2, epilogue_call_count_second);
17934 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
17935 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17936 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17937 CHECK_EQ(2, prologue_call_count);
17938 CHECK_EQ(2, epilogue_call_count);
17939 CHECK_EQ(2, prologue_call_count_second);
17940 CHECK_EQ(2, epilogue_call_count_second);
17944 THREADED_TEST(AddToJSFunctionResultCache) {
17945 i::FLAG_stress_compaction = false;
17946 i::FLAG_allow_natives_syntax = true;
17947 v8::HandleScope scope(CcTest::isolate());
17949 LocalContext context;
17955 " var r0 = %_GetFromCache(0, key0);"
17956 " var r1 = %_GetFromCache(0, key1);"
17957 " var r0_ = %_GetFromCache(0, key0);"
17959 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17960 " var r1_ = %_GetFromCache(0, key1);"
17962 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17963 " return 'PASSED';"
17965 CcTest::heap()->ClearJSFunctionResultCaches();
17966 ExpectString(code, "PASSED");
17970 static const int k0CacheSize = 16;
17972 THREADED_TEST(FillJSFunctionResultCache) {
17973 i::FLAG_allow_natives_syntax = true;
17974 LocalContext context;
17975 v8::HandleScope scope(context->GetIsolate());
17980 " var r = %_GetFromCache(0, k);"
17981 " for (var i = 0; i < 16; i++) {"
17982 " %_GetFromCache(0, 'a' + i);"
17984 " if (r === %_GetFromCache(0, k))"
17985 " return 'FAILED: k0CacheSize is too small';"
17986 " return 'PASSED';"
17988 CcTest::heap()->ClearJSFunctionResultCaches();
17989 ExpectString(code, "PASSED");
17993 THREADED_TEST(RoundRobinGetFromCache) {
17994 i::FLAG_allow_natives_syntax = true;
17995 LocalContext context;
17996 v8::HandleScope scope(context->GetIsolate());
18001 " for (var i = 0; i < 16; i++) keys.push(i);"
18002 " var values = [];"
18003 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18004 " for (var i = 0; i < 16; i++) {"
18005 " var v = %_GetFromCache(0, keys[i]);"
18006 " if (v.toString() !== values[i].toString())"
18007 " return 'Wrong value for ' + "
18008 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18010 " return 'PASSED';"
18012 CcTest::heap()->ClearJSFunctionResultCaches();
18013 ExpectString(code, "PASSED");
18017 THREADED_TEST(ReverseGetFromCache) {
18018 i::FLAG_allow_natives_syntax = true;
18019 LocalContext context;
18020 v8::HandleScope scope(context->GetIsolate());
18025 " for (var i = 0; i < 16; i++) keys.push(i);"
18026 " var values = [];"
18027 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18028 " for (var i = 15; i >= 16; i--) {"
18029 " var v = %_GetFromCache(0, keys[i]);"
18030 " if (v !== values[i])"
18031 " return 'Wrong value for ' + "
18032 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18034 " return 'PASSED';"
18036 CcTest::heap()->ClearJSFunctionResultCaches();
18037 ExpectString(code, "PASSED");
18041 THREADED_TEST(TestEviction) {
18042 i::FLAG_allow_natives_syntax = true;
18043 LocalContext context;
18044 v8::HandleScope scope(context->GetIsolate());
18048 " for (var i = 0; i < 2*16; i++) {"
18049 " %_GetFromCache(0, 'a' + i);"
18051 " return 'PASSED';"
18053 CcTest::heap()->ClearJSFunctionResultCaches();
18054 ExpectString(code, "PASSED");
18058 THREADED_TEST(TwoByteStringInAsciiCons) {
18059 // See Chromium issue 47824.
18060 LocalContext context;
18061 v8::HandleScope scope(context->GetIsolate());
18063 const char* init_code =
18064 "var str1 = 'abelspendabel';"
18065 "var str2 = str1 + str1 + str1;"
18067 Local<Value> result = CompileRun(init_code);
18069 Local<Value> indexof = CompileRun("str2.indexOf('els')");
18070 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18072 CHECK(result->IsString());
18073 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18074 int length = string->length();
18075 CHECK(string->IsOneByteRepresentation());
18077 FlattenString(string);
18078 i::Handle<i::String> flat_string = FlattenGetString(string);
18080 CHECK(string->IsOneByteRepresentation());
18081 CHECK(flat_string->IsOneByteRepresentation());
18083 // Create external resource.
18084 uint16_t* uc16_buffer = new uint16_t[length + 1];
18086 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18087 uc16_buffer[length] = 0;
18089 TestResource resource(uc16_buffer);
18091 flat_string->MakeExternal(&resource);
18093 CHECK(flat_string->IsTwoByteRepresentation());
18095 // If the cons string has been short-circuited, skip the following checks.
18096 if (!string.is_identical_to(flat_string)) {
18097 // At this point, we should have a Cons string which is flat and ASCII,
18098 // with a first half that is a two-byte string (although it only contains
18099 // ASCII characters). This is a valid sequence of steps, and it can happen
18101 CHECK(string->IsOneByteRepresentation());
18102 i::ConsString* cons = i::ConsString::cast(*string);
18103 CHECK_EQ(0, cons->second()->length());
18104 CHECK(cons->first()->IsTwoByteRepresentation());
18107 // Check that some string operations work.
18110 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18111 CHECK_EQ(6, reresult->Int32Value());
18114 reresult = CompileRun("str2.match(/abe./g).length;");
18115 CHECK_EQ(6, reresult->Int32Value());
18117 reresult = CompileRun("str2.search(/bel/g);");
18118 CHECK_EQ(1, reresult->Int32Value());
18120 reresult = CompileRun("str2.search(/be./g);");
18121 CHECK_EQ(1, reresult->Int32Value());
18123 ExpectTrue("/bel/g.test(str2);");
18125 ExpectTrue("/be./g.test(str2);");
18127 reresult = CompileRun("/bel/g.exec(str2);");
18128 CHECK(!reresult->IsNull());
18130 reresult = CompileRun("/be./g.exec(str2);");
18131 CHECK(!reresult->IsNull());
18133 ExpectString("str2.substring(2, 10);", "elspenda");
18135 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18137 ExpectString("str2.charAt(2);", "e");
18139 ExpectObject("str2.indexOf('els');", indexof);
18141 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18143 reresult = CompileRun("str2.charCodeAt(2);");
18144 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18148 TEST(ContainsOnlyOneByte) {
18149 v8::V8::Initialize();
18150 v8::Isolate* isolate = CcTest::isolate();
18151 v8::HandleScope scope(isolate);
18152 // Make a buffer long enough that it won't automatically be converted.
18153 const int length = 512;
18154 // Ensure word aligned assignment.
18155 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18156 i::SmartArrayPointer<uintptr_t>
18157 aligned_contents(new uintptr_t[aligned_length]);
18158 uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
18159 // Set to contain only one byte.
18160 for (int i = 0; i < length-1; i++) {
18161 string_contents[i] = 0x41;
18163 string_contents[length-1] = 0;
18165 Handle<String> string;
18166 string = String::NewExternal(new TestResource(string_contents));
18167 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18168 // Counter example.
18169 string = String::NewFromTwoByte(isolate, string_contents);
18170 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18171 // Test left right and balanced cons strings.
18172 Handle<String> base = String::NewFromUtf8(isolate, "a");
18173 Handle<String> left = base;
18174 Handle<String> right = base;
18175 for (int i = 0; i < 1000; i++) {
18176 left = String::Concat(base, left);
18177 right = String::Concat(right, base);
18179 Handle<String> balanced = String::Concat(left, base);
18180 balanced = String::Concat(balanced, right);
18181 Handle<String> cons_strings[] = {left, balanced, right};
18182 Handle<String> two_byte =
18183 String::NewExternal(new TestResource(string_contents));
18184 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18185 // Base assumptions.
18186 string = cons_strings[i];
18187 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18188 // Test left and right concatentation.
18189 string = String::Concat(two_byte, cons_strings[i]);
18190 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18191 string = String::Concat(cons_strings[i], two_byte);
18192 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18194 // Set bits in different positions
18195 // for strings of different lengths and alignments.
18196 for (int alignment = 0; alignment < 7; alignment++) {
18197 for (int size = 2; alignment + size < length; size *= 2) {
18198 int zero_offset = size + alignment;
18199 string_contents[zero_offset] = 0;
18200 for (int i = 0; i < size; i++) {
18201 int shift = 8 + (i % 7);
18202 string_contents[alignment + i] = 1 << shift;
18204 String::NewExternal(new TestResource(string_contents + alignment));
18205 CHECK_EQ(size, string->Length());
18206 CHECK(!string->ContainsOnlyOneByte());
18207 string_contents[alignment + i] = 0x41;
18209 string_contents[zero_offset] = 0x41;
18215 // Failed access check callback that performs a GC on each invocation.
18216 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
18217 v8::AccessType type,
18218 Local<v8::Value> data) {
18219 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18223 TEST(GCInFailedAccessCheckCallback) {
18224 // Install a failed access check callback that performs a GC on each
18225 // invocation. Then force the callback to be called from va
18227 v8::V8::Initialize();
18228 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
18230 v8::HandleScope scope(CcTest::isolate());
18232 // Create an ObjectTemplate for global objects and install access
18233 // check callbacks that will block access.
18234 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
18235 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
18236 IndexedGetAccessBlocker,
18237 v8::Handle<v8::Value>(),
18240 // Create a context and set an x property on it's global object.
18241 LocalContext context0(NULL, global_template);
18242 context0->Global()->Set(v8_str("x"), v8_num(42));
18243 v8::Handle<v8::Object> global0 = context0->Global();
18245 // Create a context with a different security token so that the
18246 // failed access check callback will be called on each access.
18247 LocalContext context1(NULL, global_template);
18248 context1->Global()->Set(v8_str("other"), global0);
18250 // Get property with failed access check.
18251 ExpectUndefined("other.x");
18253 // Get element with failed access check.
18254 ExpectUndefined("other[0]");
18256 // Set property with failed access check.
18257 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
18258 CHECK(result->IsObject());
18260 // Set element with failed access check.
18261 result = CompileRun("other[0] = new Object()");
18262 CHECK(result->IsObject());
18264 // Get property attribute with failed access check.
18265 ExpectFalse("\'x\' in other");
18267 // Get property attribute for element with failed access check.
18268 ExpectFalse("0 in other");
18270 // Delete property.
18271 ExpectFalse("delete other.x");
18274 CHECK_EQ(false, global0->Delete(0));
18278 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
18280 // Define JavaScript accessor.
18281 ExpectUndefined("Object.prototype.__defineGetter__.call("
18282 " other, \'x\', function() { return 42; })");
18285 ExpectUndefined("Object.prototype.__lookupGetter__.call("
18288 // HasLocalElement.
18289 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
18291 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
18292 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
18293 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
18295 // Reset the failed access check callback so it does not influence
18296 // the other tests.
18297 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
18301 TEST(IsolateNewDispose) {
18302 v8::Isolate* current_isolate = CcTest::isolate();
18303 v8::Isolate* isolate = v8::Isolate::New();
18304 CHECK(isolate != NULL);
18305 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
18306 CHECK(current_isolate != isolate);
18307 CHECK(current_isolate == CcTest::isolate());
18309 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18310 last_location = last_message = NULL;
18311 isolate->Dispose();
18312 CHECK_EQ(last_location, NULL);
18313 CHECK_EQ(last_message, NULL);
18317 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
18318 v8::Isolate* isolate = v8::Isolate::New();
18321 v8::HandleScope scope(isolate);
18322 LocalContext context(isolate);
18323 // Run something in this isolate.
18324 ExpectTrue("true");
18325 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18326 last_location = last_message = NULL;
18327 // Still entered, should fail.
18328 isolate->Dispose();
18329 CHECK_NE(last_location, NULL);
18330 CHECK_NE(last_message, NULL);
18334 TEST(RunTwoIsolatesOnSingleThread) {
18336 v8::Isolate* isolate1 = v8::Isolate::New();
18338 v8::Persistent<v8::Context> context1;
18340 v8::HandleScope scope(isolate1);
18341 context1.Reset(isolate1, Context::New(isolate1));
18345 v8::HandleScope scope(isolate1);
18346 v8::Local<v8::Context> context =
18347 v8::Local<v8::Context>::New(isolate1, context1);
18348 v8::Context::Scope context_scope(context);
18349 // Run something in new isolate.
18350 CompileRun("var foo = 'isolate 1';");
18351 ExpectString("function f() { return foo; }; f()", "isolate 1");
18355 v8::Isolate* isolate2 = v8::Isolate::New();
18356 v8::Persistent<v8::Context> context2;
18359 v8::Isolate::Scope iscope(isolate2);
18360 v8::HandleScope scope(isolate2);
18361 context2.Reset(isolate2, Context::New(isolate2));
18362 v8::Local<v8::Context> context =
18363 v8::Local<v8::Context>::New(isolate2, context2);
18364 v8::Context::Scope context_scope(context);
18366 // Run something in new isolate.
18367 CompileRun("var foo = 'isolate 2';");
18368 ExpectString("function f() { return foo; }; f()", "isolate 2");
18372 v8::HandleScope scope(isolate1);
18373 v8::Local<v8::Context> context =
18374 v8::Local<v8::Context>::New(isolate1, context1);
18375 v8::Context::Scope context_scope(context);
18376 // Now again in isolate 1
18377 ExpectString("function f() { return foo; }; f()", "isolate 1");
18382 // Run some stuff in default isolate.
18383 v8::Persistent<v8::Context> context_default;
18385 v8::Isolate* isolate = CcTest::isolate();
18386 v8::Isolate::Scope iscope(isolate);
18387 v8::HandleScope scope(isolate);
18388 context_default.Reset(isolate, Context::New(isolate));
18392 v8::HandleScope scope(CcTest::isolate());
18393 v8::Local<v8::Context> context =
18394 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
18395 v8::Context::Scope context_scope(context);
18396 // Variables in other isolates should be not available, verify there
18397 // is an exception.
18398 ExpectTrue("function f() {"
18406 "var isDefaultIsolate = true;"
18413 v8::Isolate::Scope iscope(isolate2);
18414 v8::HandleScope scope(isolate2);
18415 v8::Local<v8::Context> context =
18416 v8::Local<v8::Context>::New(isolate2, context2);
18417 v8::Context::Scope context_scope(context);
18418 ExpectString("function f() { return foo; }; f()", "isolate 2");
18422 v8::HandleScope scope(v8::Isolate::GetCurrent());
18423 v8::Local<v8::Context> context =
18424 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
18425 v8::Context::Scope context_scope(context);
18426 ExpectString("function f() { return foo; }; f()", "isolate 1");
18430 v8::Isolate::Scope iscope(isolate2);
18431 context2.Dispose();
18434 context1.Dispose();
18437 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18438 last_location = last_message = NULL;
18440 isolate1->Dispose();
18441 CHECK_EQ(last_location, NULL);
18442 CHECK_EQ(last_message, NULL);
18444 isolate2->Dispose();
18445 CHECK_EQ(last_location, NULL);
18446 CHECK_EQ(last_message, NULL);
18448 // Check that default isolate still runs.
18450 v8::HandleScope scope(CcTest::isolate());
18451 v8::Local<v8::Context> context =
18452 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
18453 v8::Context::Scope context_scope(context);
18454 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
18459 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
18460 v8::Isolate::Scope isolate_scope(isolate);
18461 v8::HandleScope scope(isolate);
18462 LocalContext context(isolate);
18463 i::ScopedVector<char> code(1024);
18464 i::OS::SNPrintF(code, "function fib(n) {"
18465 " if (n <= 2) return 1;"
18466 " return fib(n-1) + fib(n-2);"
18469 Local<Value> value = CompileRun(code.start());
18470 CHECK(value->IsNumber());
18471 return static_cast<int>(value->NumberValue());
18474 class IsolateThread : public v8::internal::Thread {
18476 IsolateThread(v8::Isolate* isolate, int fib_limit)
18477 : Thread("IsolateThread"),
18479 fib_limit_(fib_limit),
18483 result_ = CalcFibonacci(isolate_, fib_limit_);
18486 int result() { return result_; }
18489 v8::Isolate* isolate_;
18495 TEST(MultipleIsolatesOnIndividualThreads) {
18496 v8::Isolate* isolate1 = v8::Isolate::New();
18497 v8::Isolate* isolate2 = v8::Isolate::New();
18499 IsolateThread thread1(isolate1, 21);
18500 IsolateThread thread2(isolate2, 12);
18502 // Compute some fibonacci numbers on 3 threads in 3 isolates.
18506 int result1 = CalcFibonacci(CcTest::isolate(), 21);
18507 int result2 = CalcFibonacci(CcTest::isolate(), 12);
18512 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
18513 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
18514 CHECK_EQ(result1, 10946);
18515 CHECK_EQ(result2, 144);
18516 CHECK_EQ(result1, thread1.result());
18517 CHECK_EQ(result2, thread2.result());
18519 isolate1->Dispose();
18520 isolate2->Dispose();
18524 TEST(IsolateDifferentContexts) {
18525 v8::Isolate* isolate = v8::Isolate::New();
18526 Local<v8::Context> context;
18528 v8::Isolate::Scope isolate_scope(isolate);
18529 v8::HandleScope handle_scope(isolate);
18530 context = v8::Context::New(isolate);
18531 v8::Context::Scope context_scope(context);
18532 Local<Value> v = CompileRun("2");
18533 CHECK(v->IsNumber());
18534 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
18537 v8::Isolate::Scope isolate_scope(isolate);
18538 v8::HandleScope handle_scope(isolate);
18539 context = v8::Context::New(isolate);
18540 v8::Context::Scope context_scope(context);
18541 Local<Value> v = CompileRun("22");
18542 CHECK(v->IsNumber());
18543 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
18547 class InitDefaultIsolateThread : public v8::internal::Thread {
18551 SetResourceConstraints,
18553 SetCounterFunction,
18554 SetCreateHistogramFunction,
18555 SetAddHistogramSampleFunction
18558 explicit InitDefaultIsolateThread(TestCase testCase)
18559 : Thread("InitDefaultIsolateThread"),
18560 testCase_(testCase),
18564 v8::Isolate* isolate = v8::Isolate::New();
18566 switch (testCase_) {
18568 v8::V8::IgnoreOutOfMemoryException();
18571 case SetResourceConstraints: {
18572 static const int K = 1024;
18573 v8::ResourceConstraints constraints;
18574 constraints.set_max_young_space_size(256 * K);
18575 constraints.set_max_old_space_size(4 * K * K);
18576 v8::SetResourceConstraints(&constraints);
18580 case SetFatalHandler:
18581 v8::V8::SetFatalErrorHandler(NULL);
18584 case SetCounterFunction:
18585 v8::V8::SetCounterFunction(NULL);
18588 case SetCreateHistogramFunction:
18589 v8::V8::SetCreateHistogramFunction(NULL);
18592 case SetAddHistogramSampleFunction:
18593 v8::V8::SetAddHistogramSampleFunction(NULL);
18597 isolate->Dispose();
18601 bool result() { return result_; }
18604 TestCase testCase_;
18609 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
18610 InitDefaultIsolateThread thread(testCase);
18613 CHECK_EQ(thread.result(), true);
18617 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
18618 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
18622 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
18623 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
18627 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
18628 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
18632 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
18633 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
18637 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
18638 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
18642 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
18643 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
18647 TEST(StringCheckMultipleContexts) {
18649 "(function() { return \"a\".charAt(0); })()";
18652 // Run the code twice in the first context to initialize the call IC.
18653 LocalContext context1;
18654 v8::HandleScope scope(context1->GetIsolate());
18655 ExpectString(code, "a");
18656 ExpectString(code, "a");
18660 // Change the String.prototype in the second context and check
18661 // that the right function gets called.
18662 LocalContext context2;
18663 v8::HandleScope scope(context2->GetIsolate());
18664 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
18665 ExpectString(code, "not a");
18670 TEST(NumberCheckMultipleContexts) {
18672 "(function() { return (42).toString(); })()";
18675 // Run the code twice in the first context to initialize the call IC.
18676 LocalContext context1;
18677 v8::HandleScope scope(context1->GetIsolate());
18678 ExpectString(code, "42");
18679 ExpectString(code, "42");
18683 // Change the Number.prototype in the second context and check
18684 // that the right function gets called.
18685 LocalContext context2;
18686 v8::HandleScope scope(context2->GetIsolate());
18687 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
18688 ExpectString(code, "not 42");
18693 TEST(BooleanCheckMultipleContexts) {
18695 "(function() { return true.toString(); })()";
18698 // Run the code twice in the first context to initialize the call IC.
18699 LocalContext context1;
18700 v8::HandleScope scope(context1->GetIsolate());
18701 ExpectString(code, "true");
18702 ExpectString(code, "true");
18706 // Change the Boolean.prototype in the second context and check
18707 // that the right function gets called.
18708 LocalContext context2;
18709 v8::HandleScope scope(context2->GetIsolate());
18710 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
18711 ExpectString(code, "");
18716 TEST(DontDeleteCellLoadIC) {
18717 const char* function_code =
18718 "function readCell() { while (true) { return cell; } }";
18721 // Run the code twice in the first context to initialize the load
18722 // IC for a don't delete cell.
18723 LocalContext context1;
18724 v8::HandleScope scope(context1->GetIsolate());
18725 CompileRun("var cell = \"first\";");
18726 ExpectBoolean("delete cell", false);
18727 CompileRun(function_code);
18728 ExpectString("readCell()", "first");
18729 ExpectString("readCell()", "first");
18733 // Use a deletable cell in the second context.
18734 LocalContext context2;
18735 v8::HandleScope scope(context2->GetIsolate());
18736 CompileRun("cell = \"second\";");
18737 CompileRun(function_code);
18738 ExpectString("readCell()", "second");
18739 ExpectBoolean("delete cell", true);
18740 ExpectString("(function() {"
18742 " return readCell();"
18744 " return e.toString();"
18747 "ReferenceError: cell is not defined");
18748 CompileRun("cell = \"new_second\";");
18749 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18750 ExpectString("readCell()", "new_second");
18751 ExpectString("readCell()", "new_second");
18756 TEST(DontDeleteCellLoadICForceDelete) {
18757 const char* function_code =
18758 "function readCell() { while (true) { return cell; } }";
18760 // Run the code twice to initialize the load IC for a don't delete
18762 LocalContext context;
18763 v8::HandleScope scope(context->GetIsolate());
18764 CompileRun("var cell = \"value\";");
18765 ExpectBoolean("delete cell", false);
18766 CompileRun(function_code);
18767 ExpectString("readCell()", "value");
18768 ExpectString("readCell()", "value");
18770 // Delete the cell using the API and check the inlined code works
18772 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18773 ExpectString("(function() {"
18775 " return readCell();"
18777 " return e.toString();"
18780 "ReferenceError: cell is not defined");
18784 TEST(DontDeleteCellLoadICAPI) {
18785 const char* function_code =
18786 "function readCell() { while (true) { return cell; } }";
18788 // Run the code twice to initialize the load IC for a don't delete
18789 // cell created using the API.
18790 LocalContext context;
18791 v8::HandleScope scope(context->GetIsolate());
18792 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
18793 ExpectBoolean("delete cell", false);
18794 CompileRun(function_code);
18795 ExpectString("readCell()", "value");
18796 ExpectString("readCell()", "value");
18798 // Delete the cell using the API and check the inlined code works
18800 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18801 ExpectString("(function() {"
18803 " return readCell();"
18805 " return e.toString();"
18808 "ReferenceError: cell is not defined");
18812 class Visitor42 : public v8::PersistentHandleVisitor {
18814 explicit Visitor42(v8::Persistent<v8::Object>* object)
18815 : counter_(0), object_(object) { }
18817 virtual void VisitPersistentHandle(Persistent<Value>* value,
18818 uint16_t class_id) {
18819 if (class_id != 42) return;
18820 CHECK_EQ(42, value->WrapperClassId());
18821 v8::Isolate* isolate = CcTest::isolate();
18822 v8::HandleScope handle_scope(isolate);
18823 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
18824 v8::Handle<v8::Value> object =
18825 v8::Local<v8::Object>::New(isolate, *object_);
18826 CHECK(handle->IsObject());
18827 CHECK_EQ(Handle<Object>::Cast(handle), object);
18832 v8::Persistent<v8::Object>* object_;
18836 TEST(PersistentHandleVisitor) {
18837 LocalContext context;
18838 v8::Isolate* isolate = context->GetIsolate();
18839 v8::HandleScope scope(isolate);
18840 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18841 CHECK_EQ(0, object.WrapperClassId());
18842 object.SetWrapperClassId(42);
18843 CHECK_EQ(42, object.WrapperClassId());
18845 Visitor42 visitor(&object);
18846 v8::V8::VisitHandlesWithClassIds(&visitor);
18847 CHECK_EQ(1, visitor.counter_);
18853 TEST(WrapperClassId) {
18854 LocalContext context;
18855 v8::Isolate* isolate = context->GetIsolate();
18856 v8::HandleScope scope(isolate);
18857 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18858 CHECK_EQ(0, object.WrapperClassId());
18859 object.SetWrapperClassId(65535);
18860 CHECK_EQ(65535, object.WrapperClassId());
18865 TEST(PersistentHandleInNewSpaceVisitor) {
18866 LocalContext context;
18867 v8::Isolate* isolate = context->GetIsolate();
18868 v8::HandleScope scope(isolate);
18869 v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
18870 CHECK_EQ(0, object1.WrapperClassId());
18871 object1.SetWrapperClassId(42);
18872 CHECK_EQ(42, object1.WrapperClassId());
18874 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18876 v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
18877 CHECK_EQ(0, object2.WrapperClassId());
18878 object2.SetWrapperClassId(42);
18879 CHECK_EQ(42, object2.WrapperClassId());
18881 Visitor42 visitor(&object2);
18882 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18883 CHECK_EQ(1, visitor.counter_);
18891 LocalContext context;
18892 v8::HandleScope scope(context->GetIsolate());
18894 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18895 CHECK(re->IsRegExp());
18896 CHECK(re->GetSource()->Equals(v8_str("foo")));
18897 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18899 re = v8::RegExp::New(v8_str("bar"),
18900 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18901 v8::RegExp::kGlobal));
18902 CHECK(re->IsRegExp());
18903 CHECK(re->GetSource()->Equals(v8_str("bar")));
18904 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18905 static_cast<int>(re->GetFlags()));
18907 re = v8::RegExp::New(v8_str("baz"),
18908 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18909 v8::RegExp::kMultiline));
18910 CHECK(re->IsRegExp());
18911 CHECK(re->GetSource()->Equals(v8_str("baz")));
18912 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18913 static_cast<int>(re->GetFlags()));
18915 re = CompileRun("/quux/").As<v8::RegExp>();
18916 CHECK(re->IsRegExp());
18917 CHECK(re->GetSource()->Equals(v8_str("quux")));
18918 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18920 re = CompileRun("/quux/gm").As<v8::RegExp>();
18921 CHECK(re->IsRegExp());
18922 CHECK(re->GetSource()->Equals(v8_str("quux")));
18923 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18924 static_cast<int>(re->GetFlags()));
18926 // Override the RegExp constructor and check the API constructor
18928 CompileRun("RegExp = function() {}");
18930 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18931 CHECK(re->IsRegExp());
18932 CHECK(re->GetSource()->Equals(v8_str("foobar")));
18933 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18935 re = v8::RegExp::New(v8_str("foobarbaz"),
18936 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18937 v8::RegExp::kMultiline));
18938 CHECK(re->IsRegExp());
18939 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18940 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18941 static_cast<int>(re->GetFlags()));
18943 context->Global()->Set(v8_str("re"), re);
18944 ExpectTrue("re.test('FoobarbaZ')");
18946 // RegExps are objects on which you can set properties.
18947 re->Set(v8_str("property"), v8::Integer::New(32));
18948 v8::Handle<v8::Value> value(CompileRun("re.property"));
18949 CHECK_EQ(32, value->Int32Value());
18951 v8::TryCatch try_catch;
18952 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18953 CHECK(re.IsEmpty());
18954 CHECK(try_catch.HasCaught());
18955 context->Global()->Set(v8_str("ex"), try_catch.Exception());
18956 ExpectTrue("ex instanceof SyntaxError");
18960 THREADED_TEST(Equals) {
18961 LocalContext localContext;
18962 v8::HandleScope handleScope(localContext->GetIsolate());
18964 v8::Handle<v8::Object> globalProxy = localContext->Global();
18965 v8::Handle<Value> global = globalProxy->GetPrototype();
18967 CHECK(global->StrictEquals(global));
18968 CHECK(!global->StrictEquals(globalProxy));
18969 CHECK(!globalProxy->StrictEquals(global));
18970 CHECK(globalProxy->StrictEquals(globalProxy));
18972 CHECK(global->Equals(global));
18973 CHECK(!global->Equals(globalProxy));
18974 CHECK(!globalProxy->Equals(global));
18975 CHECK(globalProxy->Equals(globalProxy));
18979 static void Getter(v8::Local<v8::String> property,
18980 const v8::PropertyCallbackInfo<v8::Value>& info ) {
18981 info.GetReturnValue().Set(v8_str("42!"));
18985 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18986 v8::Handle<v8::Array> result = v8::Array::New();
18987 result->Set(0, v8_str("universalAnswer"));
18988 info.GetReturnValue().Set(result);
18992 TEST(NamedEnumeratorAndForIn) {
18993 LocalContext context;
18994 v8::HandleScope handle_scope(context->GetIsolate());
18995 v8::Context::Scope context_scope(context.local());
18997 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
18998 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
18999 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19000 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19001 "var result = []; for (var k in o) result.push(k); result"));
19002 CHECK_EQ(1, result->Length());
19003 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19007 TEST(DefinePropertyPostDetach) {
19008 LocalContext context;
19009 v8::HandleScope scope(context->GetIsolate());
19010 v8::Handle<v8::Object> proxy = context->Global();
19011 v8::Handle<v8::Function> define_property =
19012 CompileRun("(function() {"
19013 " Object.defineProperty("
19016 " { configurable: true, enumerable: true, value: 3 });"
19017 "})").As<Function>();
19018 context->DetachGlobal();
19019 define_property->Call(proxy, 0, NULL);
19023 static void InstallContextId(v8::Handle<Context> context, int id) {
19024 Context::Scope scope(context);
19025 CompileRun("Object.prototype").As<Object>()->
19026 Set(v8_str("context_id"), v8::Integer::New(id));
19030 static void CheckContextId(v8::Handle<Object> object, int expected) {
19031 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19035 THREADED_TEST(CreationContext) {
19036 HandleScope handle_scope(CcTest::isolate());
19037 Handle<Context> context1 = Context::New(CcTest::isolate());
19038 InstallContextId(context1, 1);
19039 Handle<Context> context2 = Context::New(CcTest::isolate());
19040 InstallContextId(context2, 2);
19041 Handle<Context> context3 = Context::New(CcTest::isolate());
19042 InstallContextId(context3, 3);
19044 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
19046 Local<Object> object1;
19047 Local<Function> func1;
19049 Context::Scope scope(context1);
19050 object1 = Object::New();
19051 func1 = tmpl->GetFunction();
19054 Local<Object> object2;
19055 Local<Function> func2;
19057 Context::Scope scope(context2);
19058 object2 = Object::New();
19059 func2 = tmpl->GetFunction();
19062 Local<Object> instance1;
19063 Local<Object> instance2;
19066 Context::Scope scope(context3);
19067 instance1 = func1->NewInstance();
19068 instance2 = func2->NewInstance();
19071 CHECK(object1->CreationContext() == context1);
19072 CheckContextId(object1, 1);
19073 CHECK(func1->CreationContext() == context1);
19074 CheckContextId(func1, 1);
19075 CHECK(instance1->CreationContext() == context1);
19076 CheckContextId(instance1, 1);
19077 CHECK(object2->CreationContext() == context2);
19078 CheckContextId(object2, 2);
19079 CHECK(func2->CreationContext() == context2);
19080 CheckContextId(func2, 2);
19081 CHECK(instance2->CreationContext() == context2);
19082 CheckContextId(instance2, 2);
19085 Context::Scope scope(context1);
19086 CHECK(object1->CreationContext() == context1);
19087 CheckContextId(object1, 1);
19088 CHECK(func1->CreationContext() == context1);
19089 CheckContextId(func1, 1);
19090 CHECK(instance1->CreationContext() == context1);
19091 CheckContextId(instance1, 1);
19092 CHECK(object2->CreationContext() == context2);
19093 CheckContextId(object2, 2);
19094 CHECK(func2->CreationContext() == context2);
19095 CheckContextId(func2, 2);
19096 CHECK(instance2->CreationContext() == context2);
19097 CheckContextId(instance2, 2);
19101 Context::Scope scope(context2);
19102 CHECK(object1->CreationContext() == context1);
19103 CheckContextId(object1, 1);
19104 CHECK(func1->CreationContext() == context1);
19105 CheckContextId(func1, 1);
19106 CHECK(instance1->CreationContext() == context1);
19107 CheckContextId(instance1, 1);
19108 CHECK(object2->CreationContext() == context2);
19109 CheckContextId(object2, 2);
19110 CHECK(func2->CreationContext() == context2);
19111 CheckContextId(func2, 2);
19112 CHECK(instance2->CreationContext() == context2);
19113 CheckContextId(instance2, 2);
19118 THREADED_TEST(CreationContextOfJsFunction) {
19119 HandleScope handle_scope(CcTest::isolate());
19120 Handle<Context> context = Context::New(CcTest::isolate());
19121 InstallContextId(context, 1);
19123 Local<Object> function;
19125 Context::Scope scope(context);
19126 function = CompileRun("function foo() {}; foo").As<Object>();
19129 CHECK(function->CreationContext() == context);
19130 CheckContextId(function, 1);
19134 void HasOwnPropertyIndexedPropertyGetter(
19136 const v8::PropertyCallbackInfo<v8::Value>& info) {
19137 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19141 void HasOwnPropertyNamedPropertyGetter(
19142 Local<String> property,
19143 const v8::PropertyCallbackInfo<v8::Value>& info) {
19144 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19148 void HasOwnPropertyIndexedPropertyQuery(
19149 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19150 if (index == 42) info.GetReturnValue().Set(1);
19154 void HasOwnPropertyNamedPropertyQuery(
19155 Local<String> property,
19156 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19157 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19161 void HasOwnPropertyNamedPropertyQuery2(
19162 Local<String> property,
19163 const v8::PropertyCallbackInfo<v8::Integer>& info) {
19164 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19168 void HasOwnPropertyAccessorGetter(
19169 Local<String> property,
19170 const v8::PropertyCallbackInfo<v8::Value>& info) {
19171 info.GetReturnValue().Set(v8_str("yes"));
19175 TEST(HasOwnProperty) {
19177 v8::HandleScope scope(env->GetIsolate());
19178 { // Check normal properties and defined getters.
19179 Handle<Value> value = CompileRun(
19182 " this.__defineGetter__('baz', function() { return 1; });"
19184 "function Bar() { "
19186 " this.__defineGetter__('bla', function() { return 2; });"
19188 "Bar.prototype = new Foo();"
19190 CHECK(value->IsObject());
19191 Handle<Object> object = value->ToObject();
19192 CHECK(object->Has(v8_str("foo")));
19193 CHECK(!object->HasOwnProperty(v8_str("foo")));
19194 CHECK(object->HasOwnProperty(v8_str("bar")));
19195 CHECK(object->Has(v8_str("baz")));
19196 CHECK(!object->HasOwnProperty(v8_str("baz")));
19197 CHECK(object->HasOwnProperty(v8_str("bla")));
19199 { // Check named getter interceptors.
19200 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19201 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19202 Handle<Object> instance = templ->NewInstance();
19203 CHECK(!instance->HasOwnProperty(v8_str("42")));
19204 CHECK(instance->HasOwnProperty(v8_str("foo")));
19205 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19207 { // Check indexed getter interceptors.
19208 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19209 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
19210 Handle<Object> instance = templ->NewInstance();
19211 CHECK(instance->HasOwnProperty(v8_str("42")));
19212 CHECK(!instance->HasOwnProperty(v8_str("43")));
19213 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19215 { // Check named query interceptors.
19216 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19217 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
19218 Handle<Object> instance = templ->NewInstance();
19219 CHECK(instance->HasOwnProperty(v8_str("foo")));
19220 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19222 { // Check indexed query interceptors.
19223 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19224 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
19225 Handle<Object> instance = templ->NewInstance();
19226 CHECK(instance->HasOwnProperty(v8_str("42")));
19227 CHECK(!instance->HasOwnProperty(v8_str("41")));
19229 { // Check callbacks.
19230 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19231 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
19232 Handle<Object> instance = templ->NewInstance();
19233 CHECK(instance->HasOwnProperty(v8_str("foo")));
19234 CHECK(!instance->HasOwnProperty(v8_str("bar")));
19236 { // Check that query wins on disagreement.
19237 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19238 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
19240 HasOwnPropertyNamedPropertyQuery2);
19241 Handle<Object> instance = templ->NewInstance();
19242 CHECK(!instance->HasOwnProperty(v8_str("foo")));
19243 CHECK(instance->HasOwnProperty(v8_str("bar")));
19248 TEST(IndexedInterceptorWithStringProto) {
19249 v8::HandleScope scope(CcTest::isolate());
19250 Handle<ObjectTemplate> templ = ObjectTemplate::New();
19251 templ->SetIndexedPropertyHandler(NULL,
19253 HasOwnPropertyIndexedPropertyQuery);
19254 LocalContext context;
19255 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19256 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
19257 // These should be intercepted.
19258 CHECK(CompileRun("42 in obj")->BooleanValue());
19259 CHECK(CompileRun("'42' in obj")->BooleanValue());
19260 // These should fall through to the String prototype.
19261 CHECK(CompileRun("0 in obj")->BooleanValue());
19262 CHECK(CompileRun("'0' in obj")->BooleanValue());
19263 // And these should both fail.
19264 CHECK(!CompileRun("32 in obj")->BooleanValue());
19265 CHECK(!CompileRun("'32' in obj")->BooleanValue());
19269 void CheckCodeGenerationAllowed() {
19270 Handle<Value> result = CompileRun("eval('42')");
19271 CHECK_EQ(42, result->Int32Value());
19272 result = CompileRun("(function(e) { return e('42'); })(eval)");
19273 CHECK_EQ(42, result->Int32Value());
19274 result = CompileRun("var f = new Function('return 42'); f()");
19275 CHECK_EQ(42, result->Int32Value());
19279 void CheckCodeGenerationDisallowed() {
19280 TryCatch try_catch;
19282 Handle<Value> result = CompileRun("eval('42')");
19283 CHECK(result.IsEmpty());
19284 CHECK(try_catch.HasCaught());
19287 result = CompileRun("(function(e) { return e('42'); })(eval)");
19288 CHECK(result.IsEmpty());
19289 CHECK(try_catch.HasCaught());
19292 result = CompileRun("var f = new Function('return 42'); f()");
19293 CHECK(result.IsEmpty());
19294 CHECK(try_catch.HasCaught());
19298 bool CodeGenerationAllowed(Local<Context> context) {
19299 ApiTestFuzzer::Fuzz();
19304 bool CodeGenerationDisallowed(Local<Context> context) {
19305 ApiTestFuzzer::Fuzz();
19310 THREADED_TEST(AllowCodeGenFromStrings) {
19311 LocalContext context;
19312 v8::HandleScope scope(context->GetIsolate());
19314 // eval and the Function constructor allowed by default.
19315 CHECK(context->IsCodeGenerationFromStringsAllowed());
19316 CheckCodeGenerationAllowed();
19318 // Disallow eval and the Function constructor.
19319 context->AllowCodeGenerationFromStrings(false);
19320 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19321 CheckCodeGenerationDisallowed();
19324 context->AllowCodeGenerationFromStrings(true);
19325 CheckCodeGenerationAllowed();
19327 // Disallow but setting a global callback that will allow the calls.
19328 context->AllowCodeGenerationFromStrings(false);
19329 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
19330 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19331 CheckCodeGenerationAllowed();
19333 // Set a callback that disallows the code generation.
19334 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19335 CHECK(!context->IsCodeGenerationFromStringsAllowed());
19336 CheckCodeGenerationDisallowed();
19340 TEST(SetErrorMessageForCodeGenFromStrings) {
19341 LocalContext context;
19342 v8::HandleScope scope(context->GetIsolate());
19343 TryCatch try_catch;
19345 Handle<String> message = v8_str("Message") ;
19346 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
19347 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19348 context->AllowCodeGenerationFromStrings(false);
19349 context->SetErrorMessageForCodeGenerationFromStrings(message);
19350 Handle<Value> result = CompileRun("eval('42')");
19351 CHECK(result.IsEmpty());
19352 CHECK(try_catch.HasCaught());
19353 Handle<String> actual_message = try_catch.Message()->Get();
19354 CHECK(expected_message->Equals(actual_message));
19358 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
19362 THREADED_TEST(CallAPIFunctionOnNonObject) {
19363 LocalContext context;
19364 v8::HandleScope scope(context->GetIsolate());
19365 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
19366 Handle<Function> function = templ->GetFunction();
19367 context->Global()->Set(v8_str("f"), function);
19368 TryCatch try_catch;
19369 CompileRun("f.call(2)");
19373 // Regression test for issue 1470.
19374 THREADED_TEST(ReadOnlyIndexedProperties) {
19375 v8::HandleScope scope(CcTest::isolate());
19376 Local<ObjectTemplate> templ = ObjectTemplate::New();
19378 LocalContext context;
19379 Local<v8::Object> obj = templ->NewInstance();
19380 context->Global()->Set(v8_str("obj"), obj);
19381 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19382 obj->Set(v8_str("1"), v8_str("foobar"));
19383 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
19384 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
19385 obj->Set(v8_num(2), v8_str("foobar"));
19386 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
19388 // Test non-smi case.
19389 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19390 obj->Set(v8_str("2000000000"), v8_str("foobar"));
19391 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
19395 THREADED_TEST(Regress1516) {
19396 LocalContext context;
19397 v8::HandleScope scope(context->GetIsolate());
19399 { v8::HandleScope temp_scope(context->GetIsolate());
19400 CompileRun("({'a': 0})");
19404 { i::MapCache* map_cache =
19405 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
19406 elements = map_cache->NumberOfElements();
19407 CHECK_LE(1, elements);
19410 CcTest::heap()->CollectAllGarbage(
19411 i::Heap::kAbortIncrementalMarkingMask);
19412 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
19413 if (raw_map_cache != CcTest::heap()->undefined_value()) {
19414 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
19415 CHECK_GT(elements, map_cache->NumberOfElements());
19421 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
19423 v8::AccessType type,
19424 Local<Value> data) {
19425 // Only block read access to __proto__.
19426 if (type == v8::ACCESS_GET &&
19427 name->IsString() &&
19428 name->ToString()->Length() == 9 &&
19429 name->ToString()->Utf8Length() == 9) {
19431 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
19432 return strncmp(buffer, "__proto__", 9) != 0;
19439 THREADED_TEST(Regress93759) {
19440 v8::Isolate* isolate = CcTest::isolate();
19441 HandleScope scope(isolate);
19443 // Template for object with security check.
19444 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
19445 // We don't do indexing, so any callback can be used for that.
19446 no_proto_template->SetAccessCheckCallbacks(
19447 BlockProtoNamedSecurityTestCallback,
19448 IndexedSecurityTestCallback);
19450 // Templates for objects with hidden prototypes and possibly security check.
19451 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
19452 hidden_proto_template->SetHiddenPrototype(true);
19454 Local<FunctionTemplate> protected_hidden_proto_template =
19455 v8::FunctionTemplate::New();
19456 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
19457 BlockProtoNamedSecurityTestCallback,
19458 IndexedSecurityTestCallback);
19459 protected_hidden_proto_template->SetHiddenPrototype(true);
19461 // Context for "foreign" objects used in test.
19462 Local<Context> context = v8::Context::New(isolate);
19465 // Plain object, no security check.
19466 Local<Object> simple_object = Object::New();
19468 // Object with explicit security check.
19469 Local<Object> protected_object =
19470 no_proto_template->NewInstance();
19472 // JSGlobalProxy object, always have security check.
19473 Local<Object> proxy_object =
19476 // Global object, the prototype of proxy_object. No security checks.
19477 Local<Object> global_object =
19478 proxy_object->GetPrototype()->ToObject();
19480 // Hidden prototype without security check.
19481 Local<Object> hidden_prototype =
19482 hidden_proto_template->GetFunction()->NewInstance();
19483 Local<Object> object_with_hidden =
19485 object_with_hidden->SetPrototype(hidden_prototype);
19487 // Hidden prototype with security check on the hidden prototype.
19488 Local<Object> protected_hidden_prototype =
19489 protected_hidden_proto_template->GetFunction()->NewInstance();
19490 Local<Object> object_with_protected_hidden =
19492 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
19496 // Template for object for second context. Values to test are put on it as
19498 Local<ObjectTemplate> global_template = ObjectTemplate::New();
19499 global_template->Set(v8_str("simple"), simple_object);
19500 global_template->Set(v8_str("protected"), protected_object);
19501 global_template->Set(v8_str("global"), global_object);
19502 global_template->Set(v8_str("proxy"), proxy_object);
19503 global_template->Set(v8_str("hidden"), object_with_hidden);
19504 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
19506 LocalContext context2(NULL, global_template);
19508 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
19509 CHECK(result1->Equals(simple_object->GetPrototype()));
19511 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
19512 CHECK(result2->Equals(Undefined(isolate)));
19514 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
19515 CHECK(result3->Equals(global_object->GetPrototype()));
19517 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
19518 CHECK(result4->Equals(Undefined(isolate)));
19520 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
19521 CHECK(result5->Equals(
19522 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
19524 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
19525 CHECK(result6->Equals(Undefined(isolate)));
19529 THREADED_TEST(Regress125988) {
19530 v8::HandleScope scope(CcTest::isolate());
19531 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
19532 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
19534 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
19535 CompileRun("var a = new Object();"
19536 "var b = new Intercept();"
19537 "var c = new Object();"
19541 "for (var i = 0; i < 3; i++) c.x;");
19542 ExpectBoolean("c.hasOwnProperty('x')", false);
19543 ExpectInt32("c.x", 23);
19544 CompileRun("a.y = 42;"
19545 "for (var i = 0; i < 3; i++) c.x;");
19546 ExpectBoolean("c.hasOwnProperty('x')", false);
19547 ExpectInt32("c.x", 23);
19548 ExpectBoolean("c.hasOwnProperty('y')", false);
19549 ExpectInt32("c.y", 42);
19553 static void TestReceiver(Local<Value> expected_result,
19554 Local<Value> expected_receiver,
19555 const char* code) {
19556 Local<Value> result = CompileRun(code);
19557 CHECK(result->IsObject());
19558 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
19559 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
19563 THREADED_TEST(ForeignFunctionReceiver) {
19564 v8::Isolate* isolate = CcTest::isolate();
19565 HandleScope scope(isolate);
19567 // Create two contexts with different "id" properties ('i' and 'o').
19568 // Call a function both from its own context and from a the foreign
19569 // context, and see what "this" is bound to (returning both "this"
19570 // and "this.id" for comparison).
19572 Local<Context> foreign_context = v8::Context::New(isolate);
19573 foreign_context->Enter();
19574 Local<Value> foreign_function =
19575 CompileRun("function func() { return { 0: this.id, "
19577 " toString: function() { "
19584 CHECK(foreign_function->IsFunction());
19585 foreign_context->Exit();
19587 LocalContext context;
19589 Local<String> password = v8_str("Password");
19590 // Don't get hit by security checks when accessing foreign_context's
19591 // global receiver (aka. global proxy).
19592 context->SetSecurityToken(password);
19593 foreign_context->SetSecurityToken(password);
19595 Local<String> i = v8_str("i");
19596 Local<String> o = v8_str("o");
19597 Local<String> id = v8_str("id");
19599 CompileRun("function ownfunc() { return { 0: this.id, "
19601 " toString: function() { "
19608 context->Global()->Set(v8_str("func"), foreign_function);
19610 // Sanity check the contexts.
19611 CHECK(i->Equals(foreign_context->Global()->Get(id)));
19612 CHECK(o->Equals(context->Global()->Get(id)));
19614 // Checking local function's receiver.
19615 // Calling function using its call/apply methods.
19616 TestReceiver(o, context->Global(), "ownfunc.call()");
19617 TestReceiver(o, context->Global(), "ownfunc.apply()");
19618 // Making calls through built-in functions.
19619 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
19620 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
19621 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
19622 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
19623 // Calling with environment record as base.
19624 TestReceiver(o, context->Global(), "ownfunc()");
19625 // Calling with no base.
19626 TestReceiver(o, context->Global(), "(1,ownfunc)()");
19628 // Checking foreign function return value.
19629 // Calling function using its call/apply methods.
19630 TestReceiver(i, foreign_context->Global(), "func.call()");
19631 TestReceiver(i, foreign_context->Global(), "func.apply()");
19632 // Calling function using another context's call/apply methods.
19633 TestReceiver(i, foreign_context->Global(),
19634 "Function.prototype.call.call(func)");
19635 TestReceiver(i, foreign_context->Global(),
19636 "Function.prototype.call.apply(func)");
19637 TestReceiver(i, foreign_context->Global(),
19638 "Function.prototype.apply.call(func)");
19639 TestReceiver(i, foreign_context->Global(),
19640 "Function.prototype.apply.apply(func)");
19641 // Making calls through built-in functions.
19642 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
19643 // ToString(func()) is func()[0], i.e., the returned this.id.
19644 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
19645 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
19646 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
19648 // TODO(1547): Make the following also return "i".
19649 // Calling with environment record as base.
19650 TestReceiver(o, context->Global(), "func()");
19651 // Calling with no base.
19652 TestReceiver(o, context->Global(), "(1,func)()");
19656 uint8_t callback_fired = 0;
19659 void CallCompletedCallback1() {
19660 i::OS::Print("Firing callback 1.\n");
19661 callback_fired ^= 1; // Toggle first bit.
19665 void CallCompletedCallback2() {
19666 i::OS::Print("Firing callback 2.\n");
19667 callback_fired ^= 2; // Toggle second bit.
19671 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
19672 int32_t level = args[0]->Int32Value();
19675 i::OS::Print("Entering recursion level %d.\n", level);
19677 i::Vector<char> script_vector(script, sizeof(script));
19678 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
19679 CompileRun(script_vector.start());
19680 i::OS::Print("Leaving recursion level %d.\n", level);
19681 CHECK_EQ(0, callback_fired);
19683 i::OS::Print("Recursion ends.\n");
19684 CHECK_EQ(0, callback_fired);
19689 TEST(CallCompletedCallback) {
19691 v8::HandleScope scope(env->GetIsolate());
19692 v8::Handle<v8::FunctionTemplate> recursive_runtime =
19693 v8::FunctionTemplate::New(RecursiveCall);
19694 env->Global()->Set(v8_str("recursion"),
19695 recursive_runtime->GetFunction());
19696 // Adding the same callback a second time has no effect.
19697 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19698 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19699 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
19700 i::OS::Print("--- Script (1) ---\n");
19701 Local<Script> script =
19702 v8::Script::Compile(v8::String::New("recursion(0)"));
19704 CHECK_EQ(3, callback_fired);
19706 i::OS::Print("\n--- Script (2) ---\n");
19707 callback_fired = 0;
19708 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
19710 CHECK_EQ(2, callback_fired);
19712 i::OS::Print("\n--- Function ---\n");
19713 callback_fired = 0;
19714 Local<Function> recursive_function =
19715 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
19716 v8::Handle<Value> args[] = { v8_num(0) };
19717 recursive_function->Call(env->Global(), 1, args);
19718 CHECK_EQ(2, callback_fired);
19722 void CallCompletedCallbackNoException() {
19723 v8::HandleScope scope(CcTest::isolate());
19724 CompileRun("1+1;");
19728 void CallCompletedCallbackException() {
19729 v8::HandleScope scope(CcTest::isolate());
19730 CompileRun("throw 'second exception';");
19734 TEST(CallCompletedCallbackOneException) {
19736 v8::HandleScope scope(env->GetIsolate());
19737 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
19738 CompileRun("throw 'exception';");
19742 TEST(CallCompletedCallbackTwoExceptions) {
19744 v8::HandleScope scope(env->GetIsolate());
19745 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
19746 CompileRun("throw 'first exception';");
19750 static int probes_counter = 0;
19751 static int misses_counter = 0;
19752 static int updates_counter = 0;
19755 static int* LookupCounter(const char* name) {
19756 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19757 return &probes_counter;
19758 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19759 return &misses_counter;
19760 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19761 return &updates_counter;
19767 static const char* kMegamorphicTestProgram =
19768 "function ClassA() { };"
19769 "function ClassB() { };"
19770 "ClassA.prototype.foo = function() { };"
19771 "ClassB.prototype.foo = function() { };"
19772 "function fooify(obj) { obj.foo(); };"
19773 "var a = new ClassA();"
19774 "var b = new ClassB();"
19775 "for (var i = 0; i < 10000; i++) {"
19781 static void StubCacheHelper(bool primary) {
19782 V8::SetCounterFunction(LookupCounter);
19783 USE(kMegamorphicTestProgram);
19785 i::FLAG_native_code_counters = true;
19787 i::FLAG_test_primary_stub_cache = true;
19789 i::FLAG_test_secondary_stub_cache = true;
19791 i::FLAG_crankshaft = false;
19793 v8::HandleScope scope(env->GetIsolate());
19794 int initial_probes = probes_counter;
19795 int initial_misses = misses_counter;
19796 int initial_updates = updates_counter;
19797 CompileRun(kMegamorphicTestProgram);
19798 int probes = probes_counter - initial_probes;
19799 int misses = misses_counter - initial_misses;
19800 int updates = updates_counter - initial_updates;
19801 CHECK_LT(updates, 10);
19802 CHECK_LT(misses, 10);
19803 CHECK_GE(probes, 10000);
19808 TEST(SecondaryStubCache) {
19809 StubCacheHelper(true);
19813 TEST(PrimaryStubCache) {
19814 StubCacheHelper(false);
19818 TEST(StaticGetters) {
19819 LocalContext context;
19820 i::Factory* factory = CcTest::i_isolate()->factory();
19821 v8::Isolate* isolate = CcTest::isolate();
19822 v8::HandleScope scope(isolate);
19823 i::Handle<i::Object> undefined_value = factory->undefined_value();
19824 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19825 i::Handle<i::Object> null_value = factory->null_value();
19826 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19827 i::Handle<i::Object> true_value = factory->true_value();
19828 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19829 i::Handle<i::Object> false_value = factory->false_value();
19830 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19834 UNINITIALIZED_TEST(IsolateEmbedderData) {
19835 CcTest::DisableAutomaticDispose();
19836 v8::Isolate* isolate = v8::Isolate::New();
19838 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19839 CHECK_EQ(NULL, isolate->GetData());
19840 CHECK_EQ(NULL, i_isolate->GetData());
19841 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
19842 isolate->SetData(data1);
19843 CHECK_EQ(data1, isolate->GetData());
19844 CHECK_EQ(data1, i_isolate->GetData());
19845 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
19846 i_isolate->SetData(data2);
19847 CHECK_EQ(data2, isolate->GetData());
19848 CHECK_EQ(data2, i_isolate->GetData());
19850 isolate->Dispose();
19854 TEST(StringEmpty) {
19855 LocalContext context;
19856 i::Factory* factory = CcTest::i_isolate()->factory();
19857 v8::Isolate* isolate = CcTest::isolate();
19858 v8::HandleScope scope(isolate);
19859 i::Handle<i::Object> empty_string = factory->empty_string();
19860 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
19861 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19865 static int instance_checked_getter_count = 0;
19866 static void InstanceCheckedGetter(
19867 Local<String> name,
19868 const v8::PropertyCallbackInfo<v8::Value>& info) {
19869 CHECK_EQ(name, v8_str("foo"));
19870 instance_checked_getter_count++;
19871 info.GetReturnValue().Set(v8_num(11));
19875 static int instance_checked_setter_count = 0;
19876 static void InstanceCheckedSetter(Local<String> name,
19877 Local<Value> value,
19878 const v8::PropertyCallbackInfo<void>& info) {
19879 CHECK_EQ(name, v8_str("foo"));
19880 CHECK_EQ(value, v8_num(23));
19881 instance_checked_setter_count++;
19885 static void CheckInstanceCheckedResult(int getters,
19887 bool expects_callbacks,
19888 TryCatch* try_catch) {
19889 if (expects_callbacks) {
19890 CHECK(!try_catch->HasCaught());
19891 CHECK_EQ(getters, instance_checked_getter_count);
19892 CHECK_EQ(setters, instance_checked_setter_count);
19894 CHECK(try_catch->HasCaught());
19895 CHECK_EQ(0, instance_checked_getter_count);
19896 CHECK_EQ(0, instance_checked_setter_count);
19898 try_catch->Reset();
19902 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19903 instance_checked_getter_count = 0;
19904 instance_checked_setter_count = 0;
19905 TryCatch try_catch;
19907 // Test path through generic runtime code.
19908 CompileRun("obj.foo");
19909 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19910 CompileRun("obj.foo = 23");
19911 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19913 // Test path through generated LoadIC and StoredIC.
19914 CompileRun("function test_get(o) { o.foo; }"
19916 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19917 CompileRun("test_get(obj);");
19918 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19919 CompileRun("test_get(obj);");
19920 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19921 CompileRun("function test_set(o) { o.foo = 23; }"
19923 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19924 CompileRun("test_set(obj);");
19925 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19926 CompileRun("test_set(obj);");
19927 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19929 // Test path through optimized code.
19930 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19932 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19933 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19935 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19937 // Cleanup so that closures start out fresh in next check.
19938 CompileRun("%DeoptimizeFunction(test_get);"
19939 "%ClearFunctionTypeFeedback(test_get);"
19940 "%DeoptimizeFunction(test_set);"
19941 "%ClearFunctionTypeFeedback(test_set);");
19945 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19946 v8::internal::FLAG_allow_natives_syntax = true;
19947 LocalContext context;
19948 v8::HandleScope scope(context->GetIsolate());
19950 Local<FunctionTemplate> templ = FunctionTemplate::New();
19951 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19952 inst->SetAccessor(v8_str("foo"),
19953 InstanceCheckedGetter, InstanceCheckedSetter,
19957 v8::AccessorSignature::New(templ));
19958 context->Global()->Set(v8_str("f"), templ->GetFunction());
19960 printf("Testing positive ...\n");
19961 CompileRun("var obj = new f();");
19962 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19963 CheckInstanceCheckedAccessors(true);
19965 printf("Testing negative ...\n");
19966 CompileRun("var obj = {};"
19967 "obj.__proto__ = new f();");
19968 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19969 CheckInstanceCheckedAccessors(false);
19973 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19974 v8::internal::FLAG_allow_natives_syntax = true;
19975 LocalContext context;
19976 v8::HandleScope scope(context->GetIsolate());
19978 Local<FunctionTemplate> templ = FunctionTemplate::New();
19979 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19980 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19981 inst->SetAccessor(v8_str("foo"),
19982 InstanceCheckedGetter, InstanceCheckedSetter,
19986 v8::AccessorSignature::New(templ));
19987 context->Global()->Set(v8_str("f"), templ->GetFunction());
19989 printf("Testing positive ...\n");
19990 CompileRun("var obj = new f();");
19991 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19992 CheckInstanceCheckedAccessors(true);
19994 printf("Testing negative ...\n");
19995 CompileRun("var obj = {};"
19996 "obj.__proto__ = new f();");
19997 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19998 CheckInstanceCheckedAccessors(false);
20002 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20003 v8::internal::FLAG_allow_natives_syntax = true;
20004 LocalContext context;
20005 v8::HandleScope scope(context->GetIsolate());
20007 Local<FunctionTemplate> templ = FunctionTemplate::New();
20008 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20009 proto->SetAccessor(v8_str("foo"),
20010 InstanceCheckedGetter, InstanceCheckedSetter,
20014 v8::AccessorSignature::New(templ));
20015 context->Global()->Set(v8_str("f"), templ->GetFunction());
20017 printf("Testing positive ...\n");
20018 CompileRun("var obj = new f();");
20019 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20020 CheckInstanceCheckedAccessors(true);
20022 printf("Testing negative ...\n");
20023 CompileRun("var obj = {};"
20024 "obj.__proto__ = new f();");
20025 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20026 CheckInstanceCheckedAccessors(false);
20028 printf("Testing positive with modified prototype chain ...\n");
20029 CompileRun("var obj = new f();"
20031 "pro.__proto__ = obj.__proto__;"
20032 "obj.__proto__ = pro;");
20033 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20034 CheckInstanceCheckedAccessors(true);
20038 TEST(TryFinallyMessage) {
20039 LocalContext context;
20040 v8::HandleScope scope(context->GetIsolate());
20042 // Test that the original error message is not lost if there is a
20043 // recursive call into Javascript is done in the finally block, e.g. to
20044 // initialize an IC. (crbug.com/129171)
20045 TryCatch try_catch;
20046 const char* trigger_ic =
20048 " throw new Error('test'); \n"
20051 " x++; \n" // Trigger an IC initialization here.
20053 CompileRun(trigger_ic);
20054 CHECK(try_catch.HasCaught());
20055 Local<Message> message = try_catch.Message();
20056 CHECK(!message.IsEmpty());
20057 CHECK_EQ(2, message->GetLineNumber());
20061 // Test that the original exception message is indeed overwritten if
20062 // a new error is thrown in the finally block.
20063 TryCatch try_catch;
20064 const char* throw_again =
20066 " throw new Error('test'); \n"
20070 " throw new Error('again'); \n" // This is the new uncaught error.
20072 CompileRun(throw_again);
20073 CHECK(try_catch.HasCaught());
20074 Local<Message> message = try_catch.Message();
20075 CHECK(!message.IsEmpty());
20076 CHECK_EQ(6, message->GetLineNumber());
20081 static void Helper137002(bool do_store,
20083 bool remove_accessor,
20084 bool interceptor) {
20085 LocalContext context;
20086 Local<ObjectTemplate> templ = ObjectTemplate::New();
20088 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20090 templ->SetAccessor(v8_str("foo"),
20091 GetterWhichReturns42,
20092 SetterWhichSetsYOnThisTo23);
20094 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20096 // Turn monomorphic on slow object with native accessor, then turn
20097 // polymorphic, finally optimize to create negative lookup and fail.
20098 CompileRun(do_store ?
20099 "function f(x) { x.foo = void 0; }" :
20100 "function f(x) { return x.foo; }");
20101 CompileRun("obj.y = void 0;");
20102 if (!interceptor) {
20103 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20105 CompileRun("obj.__proto__ = null;"
20106 "f(obj); f(obj); f(obj);");
20108 CompileRun("f({});");
20110 CompileRun("obj.y = void 0;"
20111 "%OptimizeFunctionOnNextCall(f);");
20112 if (remove_accessor) {
20113 CompileRun("delete obj.foo;");
20115 CompileRun("var result = f(obj);");
20117 CompileRun("result = obj.y;");
20119 if (remove_accessor && !interceptor) {
20120 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20122 CHECK_EQ(do_store ? 23 : 42,
20123 context->Global()->Get(v8_str("result"))->Int32Value());
20128 THREADED_TEST(Regress137002a) {
20129 i::FLAG_allow_natives_syntax = true;
20130 i::FLAG_compilation_cache = false;
20131 v8::HandleScope scope(CcTest::isolate());
20132 for (int i = 0; i < 16; i++) {
20133 Helper137002(i & 8, i & 4, i & 2, i & 1);
20138 THREADED_TEST(Regress137002b) {
20139 i::FLAG_allow_natives_syntax = true;
20140 LocalContext context;
20141 v8::HandleScope scope(context->GetIsolate());
20142 Local<ObjectTemplate> templ = ObjectTemplate::New();
20143 templ->SetAccessor(v8_str("foo"),
20144 GetterWhichReturns42,
20145 SetterWhichSetsYOnThisTo23);
20146 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20148 // Turn monomorphic on slow object with native accessor, then just
20149 // delete the property and fail.
20150 CompileRun("function load(x) { return x.foo; }"
20151 "function store(x) { x.foo = void 0; }"
20152 "function keyed_load(x, key) { return x[key]; }"
20153 // Second version of function has a different source (add void 0)
20154 // so that it does not share code with the first version. This
20155 // ensures that the ICs are monomorphic.
20156 "function load2(x) { void 0; return x.foo; }"
20157 "function store2(x) { void 0; x.foo = void 0; }"
20158 "function keyed_load2(x, key) { void 0; return x[key]; }"
20161 "obj.__proto__ = null;"
20163 "subobj.y = void 0;"
20164 "subobj.__proto__ = obj;"
20165 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20167 // Make the ICs monomorphic.
20168 "load(obj); load(obj);"
20169 "load2(subobj); load2(subobj);"
20170 "store(obj); store(obj);"
20171 "store2(subobj); store2(subobj);"
20172 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
20173 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
20175 // Actually test the shiny new ICs and better not crash. This
20176 // serves as a regression test for issue 142088 as well.
20181 "keyed_load(obj, 'foo');"
20182 "keyed_load2(subobj, 'foo');"
20184 // Delete the accessor. It better not be called any more now.
20187 "subobj.y = void 0;"
20189 "var load_result = load(obj);"
20190 "var load_result2 = load2(subobj);"
20191 "var keyed_load_result = keyed_load(obj, 'foo');"
20192 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
20195 "var y_from_obj = obj.y;"
20196 "var y_from_subobj = subobj.y;");
20197 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
20198 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
20199 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
20200 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
20201 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
20202 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
20206 THREADED_TEST(Regress142088) {
20207 i::FLAG_allow_natives_syntax = true;
20208 LocalContext context;
20209 v8::HandleScope scope(context->GetIsolate());
20210 Local<ObjectTemplate> templ = ObjectTemplate::New();
20211 templ->SetAccessor(v8_str("foo"),
20212 GetterWhichReturns42,
20213 SetterWhichSetsYOnThisTo23);
20214 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20216 CompileRun("function load(x) { return x.foo; }"
20217 "var o = Object.create(obj);"
20218 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20219 "load(o); load(o); load(o); load(o);");
20223 THREADED_TEST(Regress137496) {
20224 i::FLAG_expose_gc = true;
20225 LocalContext context;
20226 v8::HandleScope scope(context->GetIsolate());
20228 // Compile a try-finally clause where the finally block causes a GC
20229 // while there still is a message pending for external reporting.
20230 TryCatch try_catch;
20231 try_catch.SetVerbose(true);
20232 CompileRun("try { throw new Error(); } finally { gc(); }");
20233 CHECK(try_catch.HasCaught());
20237 THREADED_TEST(Regress149912) {
20238 LocalContext context;
20239 v8::HandleScope scope(context->GetIsolate());
20240 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20241 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20242 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20243 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
20247 THREADED_TEST(Regress157124) {
20248 LocalContext context;
20249 v8::HandleScope scope(context->GetIsolate());
20250 Local<ObjectTemplate> templ = ObjectTemplate::New();
20251 Local<Object> obj = templ->NewInstance();
20252 obj->GetIdentityHash();
20253 obj->DeleteHiddenValue(v8_str("Bug"));
20257 THREADED_TEST(Regress2535) {
20258 i::FLAG_harmony_collections = true;
20259 LocalContext context;
20260 v8::HandleScope scope(context->GetIsolate());
20261 Local<Value> set_value = CompileRun("new Set();");
20262 Local<Object> set_object(Local<Object>::Cast(set_value));
20263 CHECK_EQ(0, set_object->InternalFieldCount());
20264 Local<Value> map_value = CompileRun("new Map();");
20265 Local<Object> map_object(Local<Object>::Cast(map_value));
20266 CHECK_EQ(0, map_object->InternalFieldCount());
20270 THREADED_TEST(Regress2746) {
20271 LocalContext context;
20272 v8::Isolate* isolate = context->GetIsolate();
20273 v8::HandleScope scope(isolate);
20274 Local<Object> obj = Object::New();
20275 Local<String> key = String::New("key");
20276 obj->SetHiddenValue(key, v8::Undefined(isolate));
20277 Local<Value> value = obj->GetHiddenValue(key);
20278 CHECK(!value.IsEmpty());
20279 CHECK(value->IsUndefined());
20283 THREADED_TEST(Regress260106) {
20284 LocalContext context;
20285 v8::HandleScope scope(context->GetIsolate());
20286 Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler);
20287 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
20288 Local<Function> function = templ->GetFunction();
20289 CHECK(!function.IsEmpty());
20290 CHECK(function->IsFunction());
20294 THREADED_TEST(JSONParseObject) {
20295 LocalContext context;
20296 HandleScope scope(context->GetIsolate());
20297 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
20298 Handle<Object> global = context->Global();
20299 global->Set(v8_str("obj"), obj);
20300 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
20304 THREADED_TEST(JSONParseNumber) {
20305 LocalContext context;
20306 HandleScope scope(context->GetIsolate());
20307 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
20308 Handle<Object> global = context->Global();
20309 global->Set(v8_str("obj"), obj);
20310 ExpectString("JSON.stringify(obj)", "42");
20315 class ThreadInterruptTest {
20317 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
20318 ~ThreadInterruptTest() {}
20321 InterruptThread i_thread(this);
20325 CHECK_EQ(kExpectedValue, sem_value_);
20329 static const int kExpectedValue = 1;
20331 class InterruptThread : public i::Thread {
20333 explicit InterruptThread(ThreadInterruptTest* test)
20334 : Thread("InterruptThread"), test_(test) {}
20336 virtual void Run() {
20337 struct sigaction action;
20339 // Ensure that we'll enter waiting condition
20342 // Setup signal handler
20343 memset(&action, 0, sizeof(action));
20344 action.sa_handler = SignalHandler;
20345 sigaction(SIGCHLD, &action, NULL);
20348 kill(getpid(), SIGCHLD);
20350 // Ensure that if wait has returned because of error
20353 // Set value and signal semaphore
20354 test_->sem_value_ = 1;
20355 test_->sem_.Signal();
20358 static void SignalHandler(int signal) {
20362 ThreadInterruptTest* test_;
20366 volatile int sem_value_;
20370 THREADED_TEST(SemaphoreInterruption) {
20371 ThreadInterruptTest().RunTest();
20375 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
20377 v8::AccessType type,
20378 Local<Value> data) {
20379 i::PrintF("Named access blocked.\n");
20384 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
20386 v8::AccessType type,
20387 Local<Value> data) {
20388 i::PrintF("Indexed access blocked.\n");
20393 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20398 TEST(JSONStringifyAccessCheck) {
20399 v8::V8::Initialize();
20400 v8::HandleScope scope(CcTest::isolate());
20402 // Create an ObjectTemplate for global objects and install access
20403 // check callbacks that will block access.
20404 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20405 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20406 IndexAccessAlwaysBlocked);
20408 // Create a context and set an x property on it's global object.
20409 LocalContext context0(NULL, global_template);
20410 v8::Handle<v8::Object> global0 = context0->Global();
20411 global0->Set(v8_str("x"), v8_num(42));
20412 ExpectString("JSON.stringify(this)", "{\"x\":42}");
20414 for (int i = 0; i < 2; i++) {
20416 // Install a toJSON function on the second run.
20417 v8::Handle<v8::FunctionTemplate> toJSON =
20418 v8::FunctionTemplate::New(UnreachableCallback);
20420 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
20422 // Create a context with a different security token so that the
20423 // failed access check callback will be called on each access.
20424 LocalContext context1(NULL, global_template);
20425 context1->Global()->Set(v8_str("other"), global0);
20427 ExpectString("JSON.stringify(other)", "{}");
20428 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
20429 "{\"a\":{},\"b\":[\"c\"]}");
20430 ExpectString("JSON.stringify([other, 'b', 'c'])",
20431 "[{},\"b\",\"c\"]");
20433 v8::Handle<v8::Array> array = v8::Array::New(2);
20434 array->Set(0, v8_str("a"));
20435 array->Set(1, v8_str("b"));
20436 context1->Global()->Set(v8_str("array"), array);
20437 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
20438 array->TurnOnAccessCheck();
20439 ExpectString("JSON.stringify(array)", "[]");
20440 ExpectString("JSON.stringify([array])", "[[]]");
20441 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
20446 bool access_check_fail_thrown = false;
20447 bool catch_callback_called = false;
20450 // Failed access check callback that performs a GC on each invocation.
20451 void FailedAccessCheckThrows(Local<v8::Object> target,
20452 v8::AccessType type,
20453 Local<v8::Value> data) {
20454 access_check_fail_thrown = true;
20455 i::PrintF("Access check failed. Error thrown.\n");
20456 CcTest::isolate()->ThrowException(
20457 v8::Exception::Error(v8_str("cross context")));
20461 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20462 for (int i = 0; i < args.Length(); i++) {
20463 i::PrintF("%s\n", *String::Utf8Value(args[i]));
20465 catch_callback_called = true;
20469 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20470 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
20474 void CheckCorrectThrow(const char* script) {
20475 // Test that the script, when wrapped into a try-catch, triggers the catch
20476 // clause due to failed access check throwing an exception.
20477 // The subsequent try-catch should run without any exception.
20478 access_check_fail_thrown = false;
20479 catch_callback_called = false;
20480 i::ScopedVector<char> source(1024);
20481 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
20482 CompileRun(source.start());
20483 CHECK(access_check_fail_thrown);
20484 CHECK(catch_callback_called);
20486 access_check_fail_thrown = false;
20487 catch_callback_called = false;
20488 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
20489 CHECK(!access_check_fail_thrown);
20490 CHECK(!catch_callback_called);
20494 TEST(AccessCheckThrows) {
20495 i::FLAG_allow_natives_syntax = true;
20496 v8::V8::Initialize();
20497 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
20498 v8::HandleScope scope(CcTest::isolate());
20500 // Create an ObjectTemplate for global objects and install access
20501 // check callbacks that will block access.
20502 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20503 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20504 IndexAccessAlwaysBlocked);
20506 // Create a context and set an x property on it's global object.
20507 LocalContext context0(NULL, global_template);
20508 context0->Global()->Set(v8_str("x"), v8_num(42));
20509 v8::Handle<v8::Object> global0 = context0->Global();
20511 // Create a context with a different security token so that the
20512 // failed access check callback will be called on each access.
20513 LocalContext context1(NULL, global_template);
20514 context1->Global()->Set(v8_str("other"), global0);
20516 v8::Handle<v8::FunctionTemplate> catcher_fun =
20517 v8::FunctionTemplate::New(CatcherCallback);
20518 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
20520 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
20521 v8::FunctionTemplate::New(HasOwnPropertyCallback);
20522 context1->Global()->Set(v8_str("has_own_property"),
20523 has_own_property_fun->GetFunction());
20525 { v8::TryCatch try_catch;
20526 access_check_fail_thrown = false;
20527 CompileRun("other.x;");
20528 CHECK(access_check_fail_thrown);
20529 CHECK(try_catch.HasCaught());
20532 CheckCorrectThrow("other.x");
20533 CheckCorrectThrow("other[1]");
20534 CheckCorrectThrow("JSON.stringify(other)");
20535 CheckCorrectThrow("has_own_property(other, 'x')");
20536 CheckCorrectThrow("%GetProperty(other, 'x')");
20537 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
20538 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
20539 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
20540 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
20541 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
20542 CheckCorrectThrow("%HasProperty(other, 'x')");
20543 CheckCorrectThrow("%HasElement(other, 1)");
20544 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
20545 CheckCorrectThrow("%GetPropertyNames(other)");
20546 CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
20547 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
20548 "other, 'x', null, null, 1)");
20550 // Reset the failed access check callback so it does not influence
20551 // the other tests.
20552 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20556 THREADED_TEST(Regress256330) {
20557 i::FLAG_allow_natives_syntax = true;
20558 LocalContext context;
20559 v8::HandleScope scope(context->GetIsolate());
20560 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20561 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20562 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20563 CompileRun("\"use strict\"; var o = new Bug;"
20564 "function f(o) { o.x = 10; };"
20565 "f(o); f(o); f(o);"
20566 "%OptimizeFunctionOnNextCall(f);"
20568 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
20572 THREADED_TEST(CrankshaftInterceptorSetter) {
20573 i::FLAG_allow_natives_syntax = true;
20574 v8::HandleScope scope(CcTest::isolate());
20575 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20576 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20578 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20579 CompileRun("var obj = new Obj;"
20580 // Initialize fields to avoid transitions later.
20582 "obj.accessor_age = 42;"
20583 "function setter(i) { this.accessor_age = i; };"
20584 "function getter() { return this.accessor_age; };"
20585 "function setAge(i) { obj.age = i; };"
20586 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
20590 "%OptimizeFunctionOnNextCall(setAge);"
20592 // All stores went through the interceptor.
20593 ExpectInt32("obj.interceptor_age", 4);
20594 ExpectInt32("obj.accessor_age", 42);
20598 THREADED_TEST(CrankshaftInterceptorGetter) {
20599 i::FLAG_allow_natives_syntax = true;
20600 v8::HandleScope scope(CcTest::isolate());
20601 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20602 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20604 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20605 CompileRun("var obj = new Obj;"
20606 // Initialize fields to avoid transitions later.
20608 "obj.accessor_age = 42;"
20609 "function getter() { return this.accessor_age; };"
20610 "function getAge() { return obj.interceptor_age; };"
20611 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
20615 "%OptimizeFunctionOnNextCall(getAge);");
20616 // Access through interceptor.
20617 ExpectInt32("getAge()", 1);
20621 THREADED_TEST(CrankshaftInterceptorFieldRead) {
20622 i::FLAG_allow_natives_syntax = true;
20623 v8::HandleScope scope(CcTest::isolate());
20624 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20625 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20627 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20628 CompileRun("var obj = new Obj;"
20629 "obj.__proto__.interceptor_age = 42;"
20631 "function getAge() { return obj.interceptor_age; };");
20632 ExpectInt32("getAge();", 100);
20633 ExpectInt32("getAge();", 100);
20634 ExpectInt32("getAge();", 100);
20635 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
20636 // Access through interceptor.
20637 ExpectInt32("getAge();", 100);
20641 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
20642 i::FLAG_allow_natives_syntax = true;
20643 v8::HandleScope scope(CcTest::isolate());
20644 Handle<FunctionTemplate> templ = FunctionTemplate::New();
20645 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20647 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20648 CompileRun("var obj = new Obj;"
20649 "obj.age = 100000;"
20650 "function setAge(i) { obj.age = i };"
20654 "%OptimizeFunctionOnNextCall(setAge);"
20656 ExpectInt32("obj.age", 100000);
20657 ExpectInt32("obj.interceptor_age", 103);
20661 #endif // V8_OS_POSIX
20664 static Local<Value> function_new_expected_env;
20665 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20666 CHECK_EQ(function_new_expected_env, info.Data());
20667 info.GetReturnValue().Set(17);
20671 THREADED_TEST(FunctionNew) {
20673 v8::Isolate* isolate = env->GetIsolate();
20674 v8::HandleScope scope(isolate);
20675 Local<Object> data = v8::Object::New();
20676 function_new_expected_env = data;
20677 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20678 env->Global()->Set(v8_str("func"), func);
20679 Local<Value> result = CompileRun("func();");
20680 CHECK_EQ(v8::Integer::New(17, isolate), result);
20681 // Verify function not cached
20682 int serial_number =
20683 i::Smi::cast(v8::Utils::OpenHandle(*func)
20684 ->shared()->get_api_func_data()->serial_number())->value();
20685 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20686 i::Object* elm = i_isolate->native_context()->function_cache()
20687 ->GetElementNoExceptionThrown(i_isolate, serial_number);
20688 CHECK(elm->IsUndefined());
20689 // Verify that each Function::New creates a new function instance
20690 Local<Object> data2 = v8::Object::New();
20691 function_new_expected_env = data2;
20692 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
20693 CHECK(!func2->IsNull());
20694 CHECK_NE(func, func2);
20695 env->Global()->Set(v8_str("func2"), func2);
20696 Local<Value> result2 = CompileRun("func2();");
20697 CHECK_EQ(v8::Integer::New(17, isolate), result2);
20701 TEST(EscapeableHandleScope) {
20702 HandleScope outer_scope(CcTest::isolate());
20703 LocalContext context;
20704 const int runs = 10;
20705 Local<String> values[runs];
20706 for (int i = 0; i < runs; i++) {
20707 v8::EscapableHandleScope inner_scope(CcTest::isolate());
20708 Local<String> value;
20709 if (i != 0) value = v8_str("escape value");
20710 values[i] = inner_scope.Escape(value);
20712 for (int i = 0; i < runs; i++) {
20713 Local<String> expected;
20715 CHECK_EQ(v8_str("escape value"), values[i]);
20717 CHECK(values[i].IsEmpty());