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
39 #include "include/v8-util.h"
41 #include "src/arguments.h"
42 #include "src/base/platform/platform.h"
43 #include "src/compilation-cache.h"
44 #include "src/cpu-profiler.h"
45 #include "src/execution.h"
46 #include "src/isolate.h"
47 #include "src/objects.h"
48 #include "src/parser.h"
49 #include "src/snapshot.h"
50 #include "src/unicode-inl.h"
51 #include "src/utils.h"
52 #include "src/vm-state.h"
53 #include "test/cctest/cctest.h"
55 static const bool kLogThreading = false;
58 using ::v8::BooleanObject;
60 using ::v8::Extension;
62 using ::v8::FunctionTemplate;
64 using ::v8::HandleScope;
67 using ::v8::MessageCallback;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
72 using ::v8::StackTrace;
75 using ::v8::Undefined;
81 #define THREADED_PROFILED_TEST(Name) \
82 static void Test##Name(); \
83 TEST(Name##WithProfiler) { \
84 RunWithProfiler(&Test##Name); \
89 void RunWithProfiler(void (*test)()) {
91 v8::HandleScope scope(env->GetIsolate());
92 v8::Local<v8::String> profile_name =
93 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
96 cpu_profiler->StartProfiling(profile_name);
98 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
102 static int signature_callback_count;
103 static Local<Value> signature_expected_receiver;
104 static void IncrementingSignatureCallback(
105 const v8::FunctionCallbackInfo<v8::Value>& args) {
106 ApiTestFuzzer::Fuzz();
107 signature_callback_count++;
108 CHECK_EQ(signature_expected_receiver, args.Holder());
109 CHECK_EQ(signature_expected_receiver, args.This());
110 v8::Handle<v8::Array> result =
111 v8::Array::New(args.GetIsolate(), args.Length());
112 for (int i = 0; i < args.Length(); i++)
113 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
114 args.GetReturnValue().Set(result);
118 static void SignatureCallback(
119 const v8::FunctionCallbackInfo<v8::Value>& args) {
120 ApiTestFuzzer::Fuzz();
121 v8::Handle<v8::Array> result =
122 v8::Array::New(args.GetIsolate(), args.Length());
123 for (int i = 0; i < args.Length(); i++) {
124 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
126 args.GetReturnValue().Set(result);
130 // Tests that call v8::V8::Dispose() cannot be threaded.
131 TEST(InitializeAndDisposeOnce) {
132 CHECK(v8::V8::Initialize());
133 CHECK(v8::V8::Dispose());
137 // Tests that call v8::V8::Dispose() cannot be threaded.
138 TEST(InitializeAndDisposeMultiple) {
139 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
140 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142 // TODO(mstarzinger): This should fail gracefully instead of asserting.
143 // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
148 THREADED_TEST(Handles) {
149 v8::HandleScope scope(CcTest::isolate());
150 Local<Context> local_env;
153 local_env = env.local();
156 // Local context should still be live.
157 CHECK(!local_env.IsEmpty());
160 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
161 CHECK(!undef.IsEmpty());
162 CHECK(undef->IsUndefined());
164 const char* source = "1 + 2 + 3";
165 Local<Script> script = v8_compile(source);
166 CHECK_EQ(6, script->Run()->Int32Value());
172 THREADED_TEST(IsolateOfContext) {
173 v8::HandleScope scope(CcTest::isolate());
174 v8::Handle<Context> env = Context::New(CcTest::isolate());
176 CHECK(!env->GetIsolate()->InContext());
177 CHECK(env->GetIsolate() == CcTest::isolate());
179 CHECK(env->GetIsolate()->InContext());
180 CHECK(env->GetIsolate() == CcTest::isolate());
182 CHECK(!env->GetIsolate()->InContext());
183 CHECK(env->GetIsolate() == CcTest::isolate());
187 static void TestSignature(const char* loop_js, Local<Value> receiver) {
188 i::ScopedVector<char> source(200);
190 "for (var i = 0; i < 10; i++) {"
194 signature_callback_count = 0;
195 signature_expected_receiver = receiver;
196 bool expected_to_throw = receiver.IsEmpty();
197 v8::TryCatch try_catch;
198 CompileRun(source.start());
199 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
200 if (!expected_to_throw) {
201 CHECK_EQ(10, signature_callback_count);
203 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
204 try_catch.Exception()->ToString());
209 THREADED_TEST(ReceiverSignature) {
211 v8::Isolate* isolate = env->GetIsolate();
212 v8::HandleScope scope(isolate);
214 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
215 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
216 v8::Handle<v8::FunctionTemplate> callback_sig =
217 v8::FunctionTemplate::New(
218 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
219 v8::Handle<v8::FunctionTemplate> callback =
220 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
221 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
222 sub_fun->Inherit(fun);
223 v8::Handle<v8::FunctionTemplate> unrel_fun =
224 v8::FunctionTemplate::New(isolate);
225 // Install properties.
226 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
227 fun_proto->Set(v8_str("prop_sig"), callback_sig);
228 fun_proto->Set(v8_str("prop"), callback);
229 fun_proto->SetAccessorProperty(
230 v8_str("accessor_sig"), callback_sig, callback_sig);
231 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
232 // Instantiate templates.
233 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
234 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
235 // Setup global variables.
236 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
237 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
238 env->Global()->Set(v8_str("fun_instance"), fun_instance);
239 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241 "var accessor_sig_key = 'accessor_sig';"
242 "var accessor_key = 'accessor';"
243 "var prop_sig_key = 'prop_sig';"
244 "var prop_key = 'prop';"
246 "function copy_props(obj) {"
247 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
248 " var source = Fun.prototype;"
249 " for (var i in keys) {"
250 " var key = keys[i];"
251 " var desc = Object.getOwnPropertyDescriptor(source, key);"
252 " Object.defineProperty(obj, key, desc);"
258 "var unrel = new UnrelFun();"
259 "copy_props(unrel);");
260 // Test with and without ICs
261 const char* test_objects[] = {
262 "fun_instance", "sub_fun_instance", "obj", "unrel" };
263 unsigned bad_signature_start_offset = 2;
264 for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
265 i::ScopedVector<char> source(200);
267 source, "var test_object = %s; test_object", test_objects[i]);
268 Local<Value> test_object = CompileRun(source.start());
269 TestSignature("test_object.prop();", test_object);
270 TestSignature("test_object.accessor;", test_object);
271 TestSignature("test_object[accessor_key];", test_object);
272 TestSignature("test_object.accessor = 1;", test_object);
273 TestSignature("test_object[accessor_key] = 1;", test_object);
274 if (i >= bad_signature_start_offset) test_object = Local<Value>();
275 TestSignature("test_object.prop_sig();", test_object);
276 TestSignature("test_object.accessor_sig;", test_object);
277 TestSignature("test_object[accessor_sig_key];", test_object);
278 TestSignature("test_object.accessor_sig = 1;", test_object);
279 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
284 THREADED_TEST(ArgumentSignature) {
286 v8::Isolate* isolate = env->GetIsolate();
287 v8::HandleScope scope(isolate);
288 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
289 cons->SetClassName(v8_str("Cons"));
290 v8::Handle<v8::Signature> sig = v8::Signature::New(
291 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
292 v8::Handle<v8::FunctionTemplate> fun =
293 v8::FunctionTemplate::New(isolate,
297 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
298 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
301 CHECK(value1->IsTrue());
303 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
304 CHECK(value2->IsTrue());
306 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
307 CHECK(value3->IsTrue());
309 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
310 cons1->SetClassName(v8_str("Cons1"));
311 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
312 cons2->SetClassName(v8_str("Cons2"));
313 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
314 cons3->SetClassName(v8_str("Cons3"));
316 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
317 v8::Handle<v8::Signature> wsig = v8::Signature::New(
318 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
319 v8::Handle<v8::FunctionTemplate> fun2 =
320 v8::FunctionTemplate::New(isolate,
325 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
326 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
327 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
328 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
329 v8::Handle<Value> value4 = CompileRun(
330 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
331 "'[object Cons1],[object Cons2],[object Cons3]'");
332 CHECK(value4->IsTrue());
334 v8::Handle<Value> value5 = CompileRun(
335 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
336 CHECK(value5->IsTrue());
338 v8::Handle<Value> value6 = CompileRun(
339 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
340 CHECK(value6->IsTrue());
342 v8::Handle<Value> value7 = CompileRun(
343 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
344 "'[object Cons1],[object Cons2],[object Cons3],d';");
345 CHECK(value7->IsTrue());
347 v8::Handle<Value> value8 = CompileRun(
348 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
349 CHECK(value8->IsTrue());
353 THREADED_TEST(HulIgennem) {
355 v8::Isolate* isolate = env->GetIsolate();
356 v8::HandleScope scope(isolate);
357 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
358 Local<String> undef_str = undef->ToString();
359 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
360 undef_str->WriteUtf8(value);
361 CHECK_EQ(0, strcmp(value, "undefined"));
362 i::DeleteArray(value);
366 THREADED_TEST(Access) {
368 v8::Isolate* isolate = env->GetIsolate();
369 v8::HandleScope scope(isolate);
370 Local<v8::Object> obj = v8::Object::New(isolate);
371 Local<Value> foo_before = obj->Get(v8_str("foo"));
372 CHECK(foo_before->IsUndefined());
373 Local<String> bar_str = v8_str("bar");
374 obj->Set(v8_str("foo"), bar_str);
375 Local<Value> foo_after = obj->Get(v8_str("foo"));
376 CHECK(!foo_after->IsUndefined());
377 CHECK(foo_after->IsString());
378 CHECK_EQ(bar_str, foo_after);
382 THREADED_TEST(AccessElement) {
384 v8::HandleScope scope(env->GetIsolate());
385 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
386 Local<Value> before = obj->Get(1);
387 CHECK(before->IsUndefined());
388 Local<String> bar_str = v8_str("bar");
389 obj->Set(1, bar_str);
390 Local<Value> after = obj->Get(1);
391 CHECK(!after->IsUndefined());
392 CHECK(after->IsString());
393 CHECK_EQ(bar_str, after);
395 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
396 CHECK_EQ(v8_str("a"), value->Get(0));
397 CHECK_EQ(v8_str("b"), value->Get(1));
401 THREADED_TEST(Script) {
403 v8::HandleScope scope(env->GetIsolate());
404 const char* source = "1 + 2 + 3";
405 Local<Script> script = v8_compile(source);
406 CHECK_EQ(6, script->Run()->Int32Value());
410 class TestResource: public String::ExternalStringResource {
412 explicit TestResource(uint16_t* data, int* counter = NULL,
413 bool owning_data = true)
414 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
415 while (data[length_]) ++length_;
419 if (owning_data_) i::DeleteArray(data_);
420 if (counter_ != NULL) ++*counter_;
423 const uint16_t* data() const {
427 size_t length() const {
439 class TestAsciiResource: public String::ExternalAsciiStringResource {
441 explicit TestAsciiResource(const char* data, int* counter = NULL,
444 data_(data + offset),
445 length_(strlen(data) - offset),
448 ~TestAsciiResource() {
449 i::DeleteArray(orig_data_);
450 if (counter_ != NULL) ++*counter_;
453 const char* data() const {
457 size_t length() const {
462 const char* orig_data_;
469 THREADED_TEST(ScriptUsingStringResource) {
470 int dispose_count = 0;
471 const char* c_source = "1 + 2 * 3";
472 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
475 v8::HandleScope scope(env->GetIsolate());
476 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
477 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
478 Local<Script> script = v8_compile(source);
479 Local<Value> value = script->Run();
480 CHECK(value->IsNumber());
481 CHECK_EQ(7, value->Int32Value());
482 CHECK(source->IsExternal());
484 static_cast<TestResource*>(source->GetExternalStringResource()));
485 String::Encoding encoding = String::UNKNOWN_ENCODING;
486 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
487 source->GetExternalStringResourceBase(&encoding));
488 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
489 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
490 CHECK_EQ(0, dispose_count);
492 CcTest::i_isolate()->compilation_cache()->Clear();
493 CcTest::heap()->CollectAllAvailableGarbage();
494 CHECK_EQ(1, dispose_count);
498 THREADED_TEST(ScriptUsingAsciiStringResource) {
499 int dispose_count = 0;
500 const char* c_source = "1 + 2 * 3";
503 v8::HandleScope scope(env->GetIsolate());
504 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
506 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
507 CHECK(source->IsExternalAscii());
508 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
509 source->GetExternalAsciiStringResource());
510 String::Encoding encoding = String::UNKNOWN_ENCODING;
511 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
512 source->GetExternalStringResourceBase(&encoding));
513 CHECK_EQ(String::ASCII_ENCODING, encoding);
514 Local<Script> script = v8_compile(source);
515 Local<Value> value = script->Run();
516 CHECK(value->IsNumber());
517 CHECK_EQ(7, value->Int32Value());
518 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
519 CHECK_EQ(0, dispose_count);
521 CcTest::i_isolate()->compilation_cache()->Clear();
522 CcTest::heap()->CollectAllAvailableGarbage();
523 CHECK_EQ(1, dispose_count);
527 THREADED_TEST(ScriptMakingExternalString) {
528 int dispose_count = 0;
529 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
532 v8::HandleScope scope(env->GetIsolate());
533 Local<String> source =
534 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
535 // Trigger GCs so that the newly allocated string moves to old gen.
536 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
537 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
538 CHECK_EQ(source->IsExternal(), false);
539 CHECK_EQ(source->IsExternalAscii(), false);
540 String::Encoding encoding = String::UNKNOWN_ENCODING;
541 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
542 CHECK_EQ(String::ASCII_ENCODING, encoding);
543 bool success = source->MakeExternal(new TestResource(two_byte_source,
546 Local<Script> script = v8_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()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
555 CHECK_EQ(1, dispose_count);
559 THREADED_TEST(ScriptMakingExternalAsciiString) {
560 int dispose_count = 0;
561 const char* c_source = "1 + 2 * 3";
564 v8::HandleScope scope(env->GetIsolate());
565 Local<String> source = v8_str(c_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 bool success = source->MakeExternal(
570 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
572 Local<Script> script = v8_compile(source);
573 Local<Value> value = script->Run();
574 CHECK(value->IsNumber());
575 CHECK_EQ(7, value->Int32Value());
576 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
577 CHECK_EQ(0, dispose_count);
579 CcTest::i_isolate()->compilation_cache()->Clear();
580 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
581 CHECK_EQ(1, dispose_count);
585 TEST(MakingExternalStringConditions) {
587 v8::HandleScope scope(env->GetIsolate());
589 // Free some space in the new space so that we can check freshness.
590 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
591 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
594 Local<String> small_string =
595 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
596 i::DeleteArray(two_byte_string);
598 // We should refuse to externalize newly created small string.
599 CHECK(!small_string->CanMakeExternal());
600 // Trigger GCs so that the newly allocated string moves to old gen.
601 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
602 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
603 // Old space strings should be accepted.
604 CHECK(small_string->CanMakeExternal());
606 two_byte_string = AsciiToTwoByteString("small string 2");
607 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
608 i::DeleteArray(two_byte_string);
610 // We should refuse externalizing newly created small string.
611 CHECK(!small_string->CanMakeExternal());
612 for (int i = 0; i < 100; i++) {
613 String::Value value(small_string);
615 // Frequently used strings should be accepted.
616 CHECK(small_string->CanMakeExternal());
618 const int buf_size = 10 * 1024;
619 char* buf = i::NewArray<char>(buf_size);
620 memset(buf, 'a', buf_size);
621 buf[buf_size - 1] = '\0';
623 two_byte_string = AsciiToTwoByteString(buf);
624 Local<String> large_string =
625 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
627 i::DeleteArray(two_byte_string);
628 // Large strings should be immediately accepted.
629 CHECK(large_string->CanMakeExternal());
633 TEST(MakingExternalAsciiStringConditions) {
635 v8::HandleScope scope(env->GetIsolate());
637 // Free some space in the new space so that we can check freshness.
638 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
639 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
642 // We should refuse to externalize newly created small string.
643 CHECK(!small_string->CanMakeExternal());
644 // Trigger GCs so that the newly allocated string moves to old gen.
645 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
647 // Old space strings should be accepted.
648 CHECK(small_string->CanMakeExternal());
650 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
651 // We should refuse externalizing newly created small string.
652 CHECK(!small_string->CanMakeExternal());
653 for (int i = 0; i < 100; i++) {
654 String::Value value(small_string);
656 // Frequently used strings should be accepted.
657 CHECK(small_string->CanMakeExternal());
659 const int buf_size = 10 * 1024;
660 char* buf = i::NewArray<char>(buf_size);
661 memset(buf, 'a', buf_size);
662 buf[buf_size - 1] = '\0';
663 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
665 // Large strings should be immediately accepted.
666 CHECK(large_string->CanMakeExternal());
670 TEST(MakingExternalUnalignedAsciiString) {
672 v8::HandleScope scope(env->GetIsolate());
674 CompileRun("function cons(a, b) { return a + b; }"
675 "function slice(a) { return a.substring(1); }");
676 // Create a cons string that will land in old pointer space.
677 Local<String> cons = Local<String>::Cast(CompileRun(
678 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
679 // Create a sliced string that will land in old pointer space.
680 Local<String> slice = Local<String>::Cast(CompileRun(
681 "slice('abcdefghijklmnopqrstuvwxyz');"));
683 // Trigger GCs so that the newly allocated string moves to old gen.
684 SimulateFullSpace(CcTest::heap()->old_pointer_space());
685 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
686 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
688 // Turn into external string with unaligned resource data.
689 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
690 bool success = cons->MakeExternal(
691 new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
693 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
694 success = slice->MakeExternal(
695 new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
698 // Trigger GCs and force evacuation.
699 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
700 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
704 THREADED_TEST(UsingExternalString) {
705 i::Factory* factory = CcTest::i_isolate()->factory();
707 v8::HandleScope scope(CcTest::isolate());
708 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
709 Local<String> string = String::NewExternal(
710 CcTest::isolate(), new TestResource(two_byte_string));
711 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
712 // Trigger GCs so that the newly allocated string moves to old gen.
713 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
714 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
715 i::Handle<i::String> isymbol =
716 factory->InternalizeString(istring);
717 CHECK(isymbol->IsInternalizedString());
719 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
720 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
724 THREADED_TEST(UsingExternalAsciiString) {
725 i::Factory* factory = CcTest::i_isolate()->factory();
727 v8::HandleScope scope(CcTest::isolate());
728 const char* one_byte_string = "test string";
729 Local<String> string = String::NewExternal(
730 CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
731 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
732 // Trigger GCs so that the newly allocated string moves to old gen.
733 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
734 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
735 i::Handle<i::String> isymbol =
736 factory->InternalizeString(istring);
737 CHECK(isymbol->IsInternalizedString());
739 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
740 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
744 THREADED_TEST(ScavengeExternalString) {
745 i::FLAG_stress_compaction = false;
746 i::FLAG_gc_global = false;
747 int dispose_count = 0;
748 bool in_new_space = false;
750 v8::HandleScope scope(CcTest::isolate());
751 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
752 Local<String> string = String::NewExternal(
753 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
754 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
755 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
756 in_new_space = CcTest::heap()->InNewSpace(*istring);
757 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
758 CHECK_EQ(0, dispose_count);
760 CcTest::heap()->CollectGarbage(
761 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
762 CHECK_EQ(1, dispose_count);
766 THREADED_TEST(ScavengeExternalAsciiString) {
767 i::FLAG_stress_compaction = false;
768 i::FLAG_gc_global = false;
769 int dispose_count = 0;
770 bool in_new_space = false;
772 v8::HandleScope scope(CcTest::isolate());
773 const char* one_byte_string = "test string";
774 Local<String> string = String::NewExternal(
776 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
777 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
778 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
779 in_new_space = CcTest::heap()->InNewSpace(*istring);
780 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
781 CHECK_EQ(0, dispose_count);
783 CcTest::heap()->CollectGarbage(
784 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
785 CHECK_EQ(1, dispose_count);
789 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
791 // Only used by non-threaded tests, so it can use static fields.
792 static int dispose_calls;
793 static int dispose_count;
795 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
796 : TestAsciiResource(data, &dispose_count),
797 dispose_(dispose) { }
801 if (dispose_) delete this;
808 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
809 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
812 TEST(ExternalStringWithDisposeHandling) {
813 const char* c_source = "1 + 2 * 3";
815 // Use a stack allocated external string resource allocated object.
816 TestAsciiResourceWithDisposeControl::dispose_count = 0;
817 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
818 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
821 v8::HandleScope scope(env->GetIsolate());
822 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
823 Local<Script> script = v8_compile(source);
824 Local<Value> value = script->Run();
825 CHECK(value->IsNumber());
826 CHECK_EQ(7, value->Int32Value());
827 CcTest::heap()->CollectAllAvailableGarbage();
828 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
830 CcTest::i_isolate()->compilation_cache()->Clear();
831 CcTest::heap()->CollectAllAvailableGarbage();
832 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
833 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
835 // Use a heap allocated external string resource allocated object.
836 TestAsciiResourceWithDisposeControl::dispose_count = 0;
837 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
838 TestAsciiResource* res_heap =
839 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
842 v8::HandleScope scope(env->GetIsolate());
843 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
844 Local<Script> script = v8_compile(source);
845 Local<Value> value = script->Run();
846 CHECK(value->IsNumber());
847 CHECK_EQ(7, value->Int32Value());
848 CcTest::heap()->CollectAllAvailableGarbage();
849 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
851 CcTest::i_isolate()->compilation_cache()->Clear();
852 CcTest::heap()->CollectAllAvailableGarbage();
853 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
854 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
858 THREADED_TEST(StringConcat) {
861 v8::HandleScope scope(env->GetIsolate());
862 const char* one_byte_string_1 = "function a_times_t";
863 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
864 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
865 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
866 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
867 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
868 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
869 Local<String> left = v8_str(one_byte_string_1);
871 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
872 Local<String> right =
873 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
874 i::DeleteArray(two_byte_source);
876 Local<String> source = String::Concat(left, right);
877 right = String::NewExternal(
878 env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
879 source = String::Concat(source, right);
880 right = String::NewExternal(
882 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
883 source = String::Concat(source, right);
884 right = v8_str(one_byte_string_2);
885 source = String::Concat(source, right);
887 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
888 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
889 i::DeleteArray(two_byte_source);
891 source = String::Concat(source, right);
892 right = String::NewExternal(
894 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
895 source = String::Concat(source, right);
896 Local<Script> script = v8_compile(source);
897 Local<Value> value = script->Run();
898 CHECK(value->IsNumber());
899 CHECK_EQ(68, value->Int32Value());
901 CcTest::i_isolate()->compilation_cache()->Clear();
902 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
903 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
907 THREADED_TEST(GlobalProperties) {
909 v8::HandleScope scope(env->GetIsolate());
910 v8::Handle<v8::Object> global = env->Global();
911 global->Set(v8_str("pi"), v8_num(3.1415926));
912 Local<Value> pi = global->Get(v8_str("pi"));
913 CHECK_EQ(3.1415926, pi->NumberValue());
918 static void CheckReturnValue(const T& t, i::Address callback) {
919 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
920 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
921 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
922 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
923 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
925 bool is_runtime = (*o)->IsTheHole();
927 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
928 rv.Set(v8::Handle<v8::Object>());
929 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
930 CHECK_EQ(is_runtime, (*o)->IsTheHole());
932 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
933 // If CPU profiler is active check that when API callback is invoked
934 // VMState is set to EXTERNAL.
935 if (isolate->cpu_profiler()->is_profiling()) {
936 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
937 CHECK(isolate->external_callback_scope());
938 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
943 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
944 i::Address callback) {
945 ApiTestFuzzer::Fuzz();
946 CheckReturnValue(info, callback);
947 info.GetReturnValue().Set(v8_str("bad value"));
948 info.GetReturnValue().Set(v8_num(102));
952 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
953 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
957 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
958 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
961 static void construct_callback(
962 const v8::FunctionCallbackInfo<Value>& info) {
963 ApiTestFuzzer::Fuzz();
964 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
965 info.This()->Set(v8_str("x"), v8_num(1));
966 info.This()->Set(v8_str("y"), v8_num(2));
967 info.GetReturnValue().Set(v8_str("bad value"));
968 info.GetReturnValue().Set(info.This());
972 static void Return239Callback(
973 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
974 ApiTestFuzzer::Fuzz();
975 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
976 info.GetReturnValue().Set(v8_str("bad value"));
977 info.GetReturnValue().Set(v8_num(239));
981 template<typename Handler>
982 static void TestFunctionTemplateInitializer(Handler handler,
984 // Test constructor calls.
987 v8::Isolate* isolate = env->GetIsolate();
988 v8::HandleScope scope(isolate);
990 Local<v8::FunctionTemplate> fun_templ =
991 v8::FunctionTemplate::New(isolate, handler);
992 Local<Function> fun = fun_templ->GetFunction();
993 env->Global()->Set(v8_str("obj"), fun);
994 Local<Script> script = v8_compile("obj()");
995 for (int i = 0; i < 30; i++) {
996 CHECK_EQ(102, script->Run()->Int32Value());
999 // Use SetCallHandler to initialize a function template, should work like
1000 // the previous one.
1003 v8::Isolate* isolate = env->GetIsolate();
1004 v8::HandleScope scope(isolate);
1006 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1007 fun_templ->SetCallHandler(handler_2);
1008 Local<Function> fun = fun_templ->GetFunction();
1009 env->Global()->Set(v8_str("obj"), fun);
1010 Local<Script> script = v8_compile("obj()");
1011 for (int i = 0; i < 30; i++) {
1012 CHECK_EQ(102, script->Run()->Int32Value());
1018 template<typename Constructor, typename Accessor>
1019 static void TestFunctionTemplateAccessor(Constructor constructor,
1020 Accessor accessor) {
1022 v8::HandleScope scope(env->GetIsolate());
1024 Local<v8::FunctionTemplate> fun_templ =
1025 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1026 fun_templ->SetClassName(v8_str("funky"));
1027 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1028 Local<Function> fun = fun_templ->GetFunction();
1029 env->Global()->Set(v8_str("obj"), fun);
1030 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1031 CHECK_EQ(v8_str("[object funky]"), result);
1032 CompileRun("var obj_instance = new obj();");
1033 Local<Script> script;
1034 script = v8_compile("obj_instance.x");
1035 for (int i = 0; i < 30; i++) {
1036 CHECK_EQ(1, script->Run()->Int32Value());
1038 script = v8_compile("obj_instance.m");
1039 for (int i = 0; i < 30; i++) {
1040 CHECK_EQ(239, script->Run()->Int32Value());
1045 THREADED_PROFILED_TEST(FunctionTemplate) {
1046 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1047 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1051 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1052 ApiTestFuzzer::Fuzz();
1053 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1054 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1058 template<typename Callback>
1059 static void TestSimpleCallback(Callback callback) {
1061 v8::Isolate* isolate = env->GetIsolate();
1062 v8::HandleScope scope(isolate);
1064 v8::Handle<v8::ObjectTemplate> object_template =
1065 v8::ObjectTemplate::New(isolate);
1066 object_template->Set(isolate, "callback",
1067 v8::FunctionTemplate::New(isolate, callback));
1068 v8::Local<v8::Object> object = object_template->NewInstance();
1069 (*env)->Global()->Set(v8_str("callback_object"), object);
1070 v8::Handle<v8::Script> script;
1071 script = v8_compile("callback_object.callback(17)");
1072 for (int i = 0; i < 30; i++) {
1073 CHECK_EQ(51424, script->Run()->Int32Value());
1075 script = v8_compile("callback_object.callback(17, 24)");
1076 for (int i = 0; i < 30; i++) {
1077 CHECK_EQ(51425, script->Run()->Int32Value());
1082 THREADED_PROFILED_TEST(SimpleCallback) {
1083 TestSimpleCallback(SimpleCallback);
1087 template<typename T>
1088 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1090 // constant return values
1091 static int32_t fast_return_value_int32 = 471;
1092 static uint32_t fast_return_value_uint32 = 571;
1093 static const double kFastReturnValueDouble = 2.7;
1094 // variable return values
1095 static bool fast_return_value_bool = false;
1096 enum ReturnValueOddball {
1098 kUndefinedReturnValue,
1099 kEmptyStringReturnValue
1101 static ReturnValueOddball fast_return_value_void;
1102 static bool fast_return_value_object_is_empty = false;
1104 // Helper function to avoid compiler error: insufficient contextual information
1105 // to determine type when applying FUNCTION_ADDR to a template function.
1106 static i::Address address_of(v8::FunctionCallback callback) {
1107 return FUNCTION_ADDR(callback);
1111 void FastReturnValueCallback<int32_t>(
1112 const v8::FunctionCallbackInfo<v8::Value>& info) {
1113 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1114 info.GetReturnValue().Set(fast_return_value_int32);
1118 void FastReturnValueCallback<uint32_t>(
1119 const v8::FunctionCallbackInfo<v8::Value>& info) {
1120 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1121 info.GetReturnValue().Set(fast_return_value_uint32);
1125 void FastReturnValueCallback<double>(
1126 const v8::FunctionCallbackInfo<v8::Value>& info) {
1127 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1128 info.GetReturnValue().Set(kFastReturnValueDouble);
1132 void FastReturnValueCallback<bool>(
1133 const v8::FunctionCallbackInfo<v8::Value>& info) {
1134 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1135 info.GetReturnValue().Set(fast_return_value_bool);
1139 void FastReturnValueCallback<void>(
1140 const v8::FunctionCallbackInfo<v8::Value>& info) {
1141 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1142 switch (fast_return_value_void) {
1143 case kNullReturnValue:
1144 info.GetReturnValue().SetNull();
1146 case kUndefinedReturnValue:
1147 info.GetReturnValue().SetUndefined();
1149 case kEmptyStringReturnValue:
1150 info.GetReturnValue().SetEmptyString();
1156 void FastReturnValueCallback<Object>(
1157 const v8::FunctionCallbackInfo<v8::Value>& info) {
1158 v8::Handle<v8::Object> object;
1159 if (!fast_return_value_object_is_empty) {
1160 object = Object::New(info.GetIsolate());
1162 info.GetReturnValue().Set(object);
1165 template<typename T>
1166 Handle<Value> TestFastReturnValues() {
1168 v8::Isolate* isolate = env->GetIsolate();
1169 v8::EscapableHandleScope scope(isolate);
1170 v8::Handle<v8::ObjectTemplate> object_template =
1171 v8::ObjectTemplate::New(isolate);
1172 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1173 object_template->Set(isolate, "callback",
1174 v8::FunctionTemplate::New(isolate, callback));
1175 v8::Local<v8::Object> object = object_template->NewInstance();
1176 (*env)->Global()->Set(v8_str("callback_object"), object);
1177 return scope.Escape(CompileRun("callback_object.callback()"));
1181 THREADED_PROFILED_TEST(FastReturnValues) {
1183 v8::HandleScope scope(CcTest::isolate());
1184 v8::Handle<v8::Value> value;
1185 // check int32_t and uint32_t
1186 int32_t int_values[] = {
1188 i::Smi::kMinValue, i::Smi::kMaxValue
1190 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1191 for (int modifier = -1; modifier <= 1; modifier++) {
1192 int int_value = int_values[i] + modifier;
1194 fast_return_value_int32 = int_value;
1195 value = TestFastReturnValues<int32_t>();
1196 CHECK(value->IsInt32());
1197 CHECK(fast_return_value_int32 == value->Int32Value());
1199 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1200 value = TestFastReturnValues<uint32_t>();
1201 CHECK(value->IsUint32());
1202 CHECK(fast_return_value_uint32 == value->Uint32Value());
1206 value = TestFastReturnValues<double>();
1207 CHECK(value->IsNumber());
1208 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1209 // check bool values
1210 for (int i = 0; i < 2; i++) {
1211 fast_return_value_bool = i == 0;
1212 value = TestFastReturnValues<bool>();
1213 CHECK(value->IsBoolean());
1214 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1217 ReturnValueOddball oddballs[] = {
1219 kUndefinedReturnValue,
1220 kEmptyStringReturnValue
1222 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1223 fast_return_value_void = oddballs[i];
1224 value = TestFastReturnValues<void>();
1225 switch (fast_return_value_void) {
1226 case kNullReturnValue:
1227 CHECK(value->IsNull());
1229 case kUndefinedReturnValue:
1230 CHECK(value->IsUndefined());
1232 case kEmptyStringReturnValue:
1233 CHECK(value->IsString());
1234 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1239 fast_return_value_object_is_empty = false;
1240 value = TestFastReturnValues<Object>();
1241 CHECK(value->IsObject());
1242 fast_return_value_object_is_empty = true;
1243 value = TestFastReturnValues<Object>();
1244 CHECK(value->IsUndefined());
1248 THREADED_TEST(FunctionTemplateSetLength) {
1250 v8::Isolate* isolate = env->GetIsolate();
1251 v8::HandleScope scope(isolate);
1253 Local<v8::FunctionTemplate> fun_templ =
1254 v8::FunctionTemplate::New(isolate,
1256 Handle<v8::Value>(),
1257 Handle<v8::Signature>(),
1259 Local<Function> fun = fun_templ->GetFunction();
1260 env->Global()->Set(v8_str("obj"), fun);
1261 Local<Script> script = v8_compile("obj.length");
1262 CHECK_EQ(23, script->Run()->Int32Value());
1265 Local<v8::FunctionTemplate> fun_templ =
1266 v8::FunctionTemplate::New(isolate, handle_callback);
1267 fun_templ->SetLength(22);
1268 Local<Function> fun = fun_templ->GetFunction();
1269 env->Global()->Set(v8_str("obj"), fun);
1270 Local<Script> script = v8_compile("obj.length");
1271 CHECK_EQ(22, script->Run()->Int32Value());
1274 // Without setting length it defaults to 0.
1275 Local<v8::FunctionTemplate> fun_templ =
1276 v8::FunctionTemplate::New(isolate, handle_callback);
1277 Local<Function> fun = fun_templ->GetFunction();
1278 env->Global()->Set(v8_str("obj"), fun);
1279 Local<Script> script = v8_compile("obj.length");
1280 CHECK_EQ(0, script->Run()->Int32Value());
1285 static void* expected_ptr;
1286 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1287 void* ptr = v8::External::Cast(*args.Data())->Value();
1288 CHECK_EQ(expected_ptr, ptr);
1289 args.GetReturnValue().Set(true);
1293 static void TestExternalPointerWrapping() {
1295 v8::Isolate* isolate = env->GetIsolate();
1296 v8::HandleScope scope(isolate);
1298 v8::Handle<v8::Value> data =
1299 v8::External::New(isolate, expected_ptr);
1301 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1302 obj->Set(v8_str("func"),
1303 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1304 env->Global()->Set(v8_str("obj"), obj);
1307 "function foo() {\n"
1308 " for (var i = 0; i < 13; i++) obj.func();\n"
1310 "foo(), true")->BooleanValue());
1314 THREADED_TEST(ExternalWrap) {
1315 // Check heap allocated object.
1318 TestExternalPointerWrapping();
1321 // Check stack allocated object.
1323 expected_ptr = &foo;
1324 TestExternalPointerWrapping();
1326 // Check not aligned addresses.
1328 char* s = new char[n];
1329 for (int i = 0; i < n; i++) {
1330 expected_ptr = s + i;
1331 TestExternalPointerWrapping();
1336 // Check several invalid addresses.
1337 expected_ptr = reinterpret_cast<void*>(1);
1338 TestExternalPointerWrapping();
1340 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1341 TestExternalPointerWrapping();
1343 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1344 TestExternalPointerWrapping();
1346 #if defined(V8_HOST_ARCH_X64)
1347 // Check a value with a leading 1 bit in x64 Smi encoding.
1348 expected_ptr = reinterpret_cast<void*>(0x400000000);
1349 TestExternalPointerWrapping();
1351 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1352 TestExternalPointerWrapping();
1354 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1355 TestExternalPointerWrapping();
1360 THREADED_TEST(FindInstanceInPrototypeChain) {
1362 v8::Isolate* isolate = env->GetIsolate();
1363 v8::HandleScope scope(isolate);
1365 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1366 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1367 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1368 derived->Inherit(base);
1370 Local<v8::Function> base_function = base->GetFunction();
1371 Local<v8::Function> derived_function = derived->GetFunction();
1372 Local<v8::Function> other_function = other->GetFunction();
1374 Local<v8::Object> base_instance = base_function->NewInstance();
1375 Local<v8::Object> derived_instance = derived_function->NewInstance();
1376 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1377 Local<v8::Object> other_instance = other_function->NewInstance();
1378 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1379 other_instance->Set(v8_str("__proto__"), derived_instance2);
1381 // base_instance is only an instance of base.
1382 CHECK_EQ(base_instance,
1383 base_instance->FindInstanceInPrototypeChain(base));
1384 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1385 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1387 // derived_instance is an instance of base and derived.
1388 CHECK_EQ(derived_instance,
1389 derived_instance->FindInstanceInPrototypeChain(base));
1390 CHECK_EQ(derived_instance,
1391 derived_instance->FindInstanceInPrototypeChain(derived));
1392 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1394 // other_instance is an instance of other and its immediate
1395 // prototype derived_instance2 is an instance of base and derived.
1396 // Note, derived_instance is an instance of base and derived too,
1397 // but it comes after derived_instance2 in the prototype chain of
1399 CHECK_EQ(derived_instance2,
1400 other_instance->FindInstanceInPrototypeChain(base));
1401 CHECK_EQ(derived_instance2,
1402 other_instance->FindInstanceInPrototypeChain(derived));
1403 CHECK_EQ(other_instance,
1404 other_instance->FindInstanceInPrototypeChain(other));
1408 THREADED_TEST(TinyInteger) {
1410 v8::Isolate* isolate = env->GetIsolate();
1411 v8::HandleScope scope(isolate);
1413 int32_t value = 239;
1414 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1415 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1417 value_obj = v8::Integer::New(isolate, value);
1418 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1422 THREADED_TEST(BigSmiInteger) {
1424 v8::HandleScope scope(env->GetIsolate());
1425 v8::Isolate* isolate = CcTest::isolate();
1427 int32_t value = i::Smi::kMaxValue;
1428 // We cannot add one to a Smi::kMaxValue without wrapping.
1429 if (i::SmiValuesAre31Bits()) {
1430 CHECK(i::Smi::IsValid(value));
1431 CHECK(!i::Smi::IsValid(value + 1));
1433 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1434 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1436 value_obj = v8::Integer::New(isolate, value);
1437 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1442 THREADED_TEST(BigInteger) {
1444 v8::HandleScope scope(env->GetIsolate());
1445 v8::Isolate* isolate = CcTest::isolate();
1447 // We cannot add one to a Smi::kMaxValue without wrapping.
1448 if (i::SmiValuesAre31Bits()) {
1449 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1450 // The code will not be run in that case, due to the "if" guard.
1452 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1453 CHECK(value > i::Smi::kMaxValue);
1454 CHECK(!i::Smi::IsValid(value));
1456 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1457 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459 value_obj = v8::Integer::New(isolate, value);
1460 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1465 THREADED_TEST(TinyUnsignedInteger) {
1467 v8::HandleScope scope(env->GetIsolate());
1468 v8::Isolate* isolate = CcTest::isolate();
1470 uint32_t value = 239;
1472 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1473 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1475 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1476 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1480 THREADED_TEST(BigUnsignedSmiInteger) {
1482 v8::HandleScope scope(env->GetIsolate());
1483 v8::Isolate* isolate = CcTest::isolate();
1485 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1486 CHECK(i::Smi::IsValid(value));
1487 CHECK(!i::Smi::IsValid(value + 1));
1489 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1490 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1492 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1493 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1497 THREADED_TEST(BigUnsignedInteger) {
1499 v8::HandleScope scope(env->GetIsolate());
1500 v8::Isolate* isolate = CcTest::isolate();
1502 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1503 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1504 CHECK(!i::Smi::IsValid(value));
1506 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1507 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1510 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1514 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1516 v8::HandleScope scope(env->GetIsolate());
1517 v8::Isolate* isolate = CcTest::isolate();
1519 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1520 uint32_t value = INT32_MAX_AS_UINT + 1;
1521 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1523 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1526 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1527 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1531 THREADED_TEST(IsNativeError) {
1533 v8::HandleScope scope(env->GetIsolate());
1534 v8::Handle<Value> syntax_error = CompileRun(
1535 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1536 CHECK(syntax_error->IsNativeError());
1537 v8::Handle<Value> not_error = CompileRun("{a:42}");
1538 CHECK(!not_error->IsNativeError());
1539 v8::Handle<Value> not_object = CompileRun("42");
1540 CHECK(!not_object->IsNativeError());
1544 THREADED_TEST(StringObject) {
1546 v8::HandleScope scope(env->GetIsolate());
1547 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1548 CHECK(boxed_string->IsStringObject());
1549 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1550 CHECK(!unboxed_string->IsStringObject());
1551 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1552 CHECK(!boxed_not_string->IsStringObject());
1553 v8::Handle<Value> not_object = CompileRun("0");
1554 CHECK(!not_object->IsStringObject());
1555 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1556 CHECK(!as_boxed.IsEmpty());
1557 Local<v8::String> the_string = as_boxed->ValueOf();
1558 CHECK(!the_string.IsEmpty());
1559 ExpectObject("\"test\"", the_string);
1560 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1561 CHECK(new_boxed_string->IsStringObject());
1562 as_boxed = new_boxed_string.As<v8::StringObject>();
1563 the_string = as_boxed->ValueOf();
1564 CHECK(!the_string.IsEmpty());
1565 ExpectObject("\"test\"", the_string);
1569 THREADED_TEST(NumberObject) {
1571 v8::HandleScope scope(env->GetIsolate());
1572 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1573 CHECK(boxed_number->IsNumberObject());
1574 v8::Handle<Value> unboxed_number = CompileRun("42");
1575 CHECK(!unboxed_number->IsNumberObject());
1576 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1577 CHECK(!boxed_not_number->IsNumberObject());
1578 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1579 CHECK(!as_boxed.IsEmpty());
1580 double the_number = as_boxed->ValueOf();
1581 CHECK_EQ(42.0, the_number);
1582 v8::Handle<v8::Value> new_boxed_number =
1583 v8::NumberObject::New(env->GetIsolate(), 43);
1584 CHECK(new_boxed_number->IsNumberObject());
1585 as_boxed = new_boxed_number.As<v8::NumberObject>();
1586 the_number = as_boxed->ValueOf();
1587 CHECK_EQ(43.0, the_number);
1591 THREADED_TEST(BooleanObject) {
1593 v8::HandleScope scope(env->GetIsolate());
1594 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1595 CHECK(boxed_boolean->IsBooleanObject());
1596 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1597 CHECK(!unboxed_boolean->IsBooleanObject());
1598 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1599 CHECK(!boxed_not_boolean->IsBooleanObject());
1600 v8::Handle<v8::BooleanObject> as_boxed =
1601 boxed_boolean.As<v8::BooleanObject>();
1602 CHECK(!as_boxed.IsEmpty());
1603 bool the_boolean = as_boxed->ValueOf();
1604 CHECK_EQ(true, the_boolean);
1605 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1606 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1607 CHECK(boxed_true->IsBooleanObject());
1608 CHECK(boxed_false->IsBooleanObject());
1609 as_boxed = boxed_true.As<v8::BooleanObject>();
1610 CHECK_EQ(true, as_boxed->ValueOf());
1611 as_boxed = boxed_false.As<v8::BooleanObject>();
1612 CHECK_EQ(false, as_boxed->ValueOf());
1616 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1618 v8::HandleScope scope(env->GetIsolate());
1620 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1621 CHECK(primitive_false->IsBoolean());
1622 CHECK(!primitive_false->IsBooleanObject());
1623 CHECK(!primitive_false->BooleanValue());
1624 CHECK(!primitive_false->IsTrue());
1625 CHECK(primitive_false->IsFalse());
1627 Local<Value> false_value = BooleanObject::New(false);
1628 CHECK(!false_value->IsBoolean());
1629 CHECK(false_value->IsBooleanObject());
1630 CHECK(false_value->BooleanValue());
1631 CHECK(!false_value->IsTrue());
1632 CHECK(!false_value->IsFalse());
1634 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1635 CHECK(!false_boolean_object->IsBoolean());
1636 CHECK(false_boolean_object->IsBooleanObject());
1637 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1638 // CHECK(false_boolean_object->BooleanValue());
1639 CHECK(!false_boolean_object->ValueOf());
1640 CHECK(!false_boolean_object->IsTrue());
1641 CHECK(!false_boolean_object->IsFalse());
1643 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1644 CHECK(primitive_true->IsBoolean());
1645 CHECK(!primitive_true->IsBooleanObject());
1646 CHECK(primitive_true->BooleanValue());
1647 CHECK(primitive_true->IsTrue());
1648 CHECK(!primitive_true->IsFalse());
1650 Local<Value> true_value = BooleanObject::New(true);
1651 CHECK(!true_value->IsBoolean());
1652 CHECK(true_value->IsBooleanObject());
1653 CHECK(true_value->BooleanValue());
1654 CHECK(!true_value->IsTrue());
1655 CHECK(!true_value->IsFalse());
1657 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1658 CHECK(!true_boolean_object->IsBoolean());
1659 CHECK(true_boolean_object->IsBooleanObject());
1660 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1661 // CHECK(true_boolean_object->BooleanValue());
1662 CHECK(true_boolean_object->ValueOf());
1663 CHECK(!true_boolean_object->IsTrue());
1664 CHECK(!true_boolean_object->IsFalse());
1668 THREADED_TEST(Number) {
1670 v8::HandleScope scope(env->GetIsolate());
1671 double PI = 3.1415926;
1672 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1673 CHECK_EQ(PI, pi_obj->NumberValue());
1677 THREADED_TEST(ToNumber) {
1679 v8::Isolate* isolate = CcTest::isolate();
1680 v8::HandleScope scope(isolate);
1681 Local<String> str = v8_str("3.1415926");
1682 CHECK_EQ(3.1415926, str->NumberValue());
1683 v8::Handle<v8::Boolean> t = v8::True(isolate);
1684 CHECK_EQ(1.0, t->NumberValue());
1685 v8::Handle<v8::Boolean> f = v8::False(isolate);
1686 CHECK_EQ(0.0, f->NumberValue());
1690 THREADED_TEST(Date) {
1692 v8::HandleScope scope(env->GetIsolate());
1693 double PI = 3.1415926;
1694 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1695 CHECK_EQ(3.0, date->NumberValue());
1696 date.As<v8::Date>()->Set(v8_str("property"),
1697 v8::Integer::New(env->GetIsolate(), 42));
1698 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1702 THREADED_TEST(Boolean) {
1704 v8::Isolate* isolate = env->GetIsolate();
1705 v8::HandleScope scope(isolate);
1706 v8::Handle<v8::Boolean> t = v8::True(isolate);
1708 v8::Handle<v8::Boolean> f = v8::False(isolate);
1710 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1711 CHECK(!u->BooleanValue());
1712 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1713 CHECK(!n->BooleanValue());
1714 v8::Handle<String> str1 = v8_str("");
1715 CHECK(!str1->BooleanValue());
1716 v8::Handle<String> str2 = v8_str("x");
1717 CHECK(str2->BooleanValue());
1718 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1719 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1720 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1721 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1722 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1726 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1727 ApiTestFuzzer::Fuzz();
1728 args.GetReturnValue().Set(v8_num(13.4));
1732 static void GetM(Local<String> name,
1733 const v8::PropertyCallbackInfo<v8::Value>& info) {
1734 ApiTestFuzzer::Fuzz();
1735 info.GetReturnValue().Set(v8_num(876));
1739 THREADED_TEST(GlobalPrototype) {
1740 v8::Isolate* isolate = CcTest::isolate();
1741 v8::HandleScope scope(isolate);
1742 v8::Handle<v8::FunctionTemplate> func_templ =
1743 v8::FunctionTemplate::New(isolate);
1744 func_templ->PrototypeTemplate()->Set(
1745 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1746 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1747 templ->Set(isolate, "x", v8_num(200));
1748 templ->SetAccessor(v8_str("m"), GetM);
1749 LocalContext env(0, templ);
1750 v8::Handle<Script> script(v8_compile("dummy()"));
1751 v8::Handle<Value> result(script->Run());
1752 CHECK_EQ(13.4, result->NumberValue());
1753 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1754 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1758 THREADED_TEST(ObjectTemplate) {
1759 v8::Isolate* isolate = CcTest::isolate();
1760 v8::HandleScope scope(isolate);
1761 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1762 templ1->Set(isolate, "x", v8_num(10));
1763 templ1->Set(isolate, "y", v8_num(13));
1765 Local<v8::Object> instance1 = templ1->NewInstance();
1766 env->Global()->Set(v8_str("p"), instance1);
1767 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1768 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1769 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1770 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1771 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1772 templ2->Set(isolate, "a", v8_num(12));
1773 templ2->Set(isolate, "b", templ1);
1774 Local<v8::Object> instance2 = templ2->NewInstance();
1775 env->Global()->Set(v8_str("q"), instance2);
1776 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1777 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1778 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1779 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1783 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1784 ApiTestFuzzer::Fuzz();
1785 args.GetReturnValue().Set(v8_num(17.2));
1789 static void GetKnurd(Local<String> property,
1790 const v8::PropertyCallbackInfo<v8::Value>& info) {
1791 ApiTestFuzzer::Fuzz();
1792 info.GetReturnValue().Set(v8_num(15.2));
1796 THREADED_TEST(DescriptorInheritance) {
1797 v8::Isolate* isolate = CcTest::isolate();
1798 v8::HandleScope scope(isolate);
1799 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1800 super->PrototypeTemplate()->Set(isolate, "flabby",
1801 v8::FunctionTemplate::New(isolate,
1803 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1805 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1807 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1808 base1->Inherit(super);
1809 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1811 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1812 base2->Inherit(super);
1813 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1817 env->Global()->Set(v8_str("s"), super->GetFunction());
1818 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1819 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1821 // Checks right __proto__ chain.
1822 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1823 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1825 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1827 // Instance accessor should not be visible on function object or its prototype
1828 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1829 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1830 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1832 env->Global()->Set(v8_str("obj"),
1833 base1->GetFunction()->NewInstance());
1834 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1835 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1836 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1837 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1838 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1840 env->Global()->Set(v8_str("obj2"),
1841 base2->GetFunction()->NewInstance());
1842 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1843 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1844 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1845 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1846 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1848 // base1 and base2 cannot cross reference to each's prototype
1849 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1850 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1854 int echo_named_call_count;
1857 static void EchoNamedProperty(Local<String> name,
1858 const v8::PropertyCallbackInfo<v8::Value>& info) {
1859 ApiTestFuzzer::Fuzz();
1860 CHECK_EQ(v8_str("data"), info.Data());
1861 echo_named_call_count++;
1862 info.GetReturnValue().Set(name);
1866 // Helper functions for Interceptor/Accessor interaction tests
1868 void SimpleAccessorGetter(Local<String> name,
1869 const v8::PropertyCallbackInfo<v8::Value>& info) {
1870 Handle<Object> self = Handle<Object>::Cast(info.This());
1871 info.GetReturnValue().Set(
1872 self->Get(String::Concat(v8_str("accessor_"), name)));
1875 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1876 const v8::PropertyCallbackInfo<void>& info) {
1877 Handle<Object> self = Handle<Object>::Cast(info.This());
1878 self->Set(String::Concat(v8_str("accessor_"), name), value);
1881 void EmptyInterceptorGetter(Local<String> name,
1882 const v8::PropertyCallbackInfo<v8::Value>& info) {
1885 void EmptyInterceptorSetter(Local<String> name,
1887 const v8::PropertyCallbackInfo<v8::Value>& info) {
1890 void InterceptorGetter(Local<String> name,
1891 const v8::PropertyCallbackInfo<v8::Value>& info) {
1892 // Intercept names that start with 'interceptor_'.
1893 String::Utf8Value utf8(name);
1894 char* name_str = *utf8;
1895 char prefix[] = "interceptor_";
1897 for (i = 0; name_str[i] && prefix[i]; ++i) {
1898 if (name_str[i] != prefix[i]) return;
1900 Handle<Object> self = Handle<Object>::Cast(info.This());
1901 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1904 void InterceptorSetter(Local<String> name,
1906 const v8::PropertyCallbackInfo<v8::Value>& info) {
1907 // Intercept accesses that set certain integer values, for which the name does
1908 // not start with 'accessor_'.
1909 String::Utf8Value utf8(name);
1910 char* name_str = *utf8;
1911 char prefix[] = "accessor_";
1913 for (i = 0; name_str[i] && prefix[i]; ++i) {
1914 if (name_str[i] != prefix[i]) break;
1916 if (!prefix[i]) return;
1918 if (value->IsInt32() && value->Int32Value() < 10000) {
1919 Handle<Object> self = Handle<Object>::Cast(info.This());
1920 self->SetHiddenValue(name, value);
1921 info.GetReturnValue().Set(value);
1925 void AddAccessor(Handle<FunctionTemplate> templ,
1926 Handle<String> name,
1927 v8::AccessorGetterCallback getter,
1928 v8::AccessorSetterCallback setter) {
1929 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1932 void AddInterceptor(Handle<FunctionTemplate> templ,
1933 v8::NamedPropertyGetterCallback getter,
1934 v8::NamedPropertySetterCallback setter) {
1935 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1939 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1940 v8::HandleScope scope(CcTest::isolate());
1941 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1942 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1943 child->Inherit(parent);
1944 AddAccessor(parent, v8_str("age"),
1945 SimpleAccessorGetter, SimpleAccessorSetter);
1946 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1948 env->Global()->Set(v8_str("Child"), child->GetFunction());
1949 CompileRun("var child = new Child;"
1951 ExpectBoolean("child.hasOwnProperty('age')", false);
1952 ExpectInt32("child.age", 10);
1953 ExpectInt32("child.accessor_age", 10);
1957 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1958 v8::Isolate* isolate = CcTest::isolate();
1959 v8::HandleScope scope(isolate);
1961 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1962 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1963 CHECK(a->map()->instance_descriptors()->IsFixedArray());
1964 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1965 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1966 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1967 // But we should still have an ExecutableAccessorInfo.
1968 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1969 i::LookupResult lookup(i_isolate);
1970 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1971 a->LookupOwnRealNamedProperty(name, &lookup);
1972 CHECK(lookup.IsPropertyCallbacks());
1973 i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate);
1974 CHECK(callback->IsExecutableAccessorInfo());
1978 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1979 v8::HandleScope scope(CcTest::isolate());
1980 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1981 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1983 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1984 CompileRun("var o1 = new Constructor;"
1985 "o1.a = 1;" // Ensure a and x share the descriptor array.
1986 "Object.defineProperty(o1, 'x', {value: 10});");
1987 CompileRun("var o2 = new Constructor;"
1989 "Object.defineProperty(o2, 'x', {value: 10});");
1993 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1994 v8::Isolate* isolate = CcTest::isolate();
1995 v8::HandleScope scope(isolate);
1996 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1997 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1998 child->Inherit(parent);
1999 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2001 env->Global()->Set(v8_str("Child"), child->GetFunction());
2002 CompileRun("var child = new Child;"
2003 "var parent = child.__proto__;"
2004 "Object.defineProperty(parent, 'age', "
2005 " {get: function(){ return this.accessor_age; }, "
2006 " set: function(v){ this.accessor_age = v; }, "
2007 " enumerable: true, configurable: true});"
2009 ExpectBoolean("child.hasOwnProperty('age')", false);
2010 ExpectInt32("child.age", 10);
2011 ExpectInt32("child.accessor_age", 10);
2015 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2016 v8::Isolate* isolate = CcTest::isolate();
2017 v8::HandleScope scope(isolate);
2018 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2019 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2020 child->Inherit(parent);
2021 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2023 env->Global()->Set(v8_str("Child"), child->GetFunction());
2024 CompileRun("var child = new Child;"
2025 "var parent = child.__proto__;"
2026 "parent.name = 'Alice';");
2027 ExpectBoolean("child.hasOwnProperty('name')", false);
2028 ExpectString("child.name", "Alice");
2029 CompileRun("child.name = 'Bob';");
2030 ExpectString("child.name", "Bob");
2031 ExpectBoolean("child.hasOwnProperty('name')", true);
2032 ExpectString("parent.name", "Alice");
2036 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2037 v8::HandleScope scope(CcTest::isolate());
2038 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2039 AddAccessor(templ, v8_str("age"),
2040 SimpleAccessorGetter, SimpleAccessorSetter);
2041 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2043 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2044 CompileRun("var obj = new Obj;"
2045 "function setAge(i){ obj.age = i; };"
2046 "for(var i = 0; i <= 10000; i++) setAge(i);");
2047 // All i < 10000 go to the interceptor.
2048 ExpectInt32("obj.interceptor_age", 9999);
2049 // The last i goes to the accessor.
2050 ExpectInt32("obj.accessor_age", 10000);
2054 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2055 v8::HandleScope scope(CcTest::isolate());
2056 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2057 AddAccessor(templ, v8_str("age"),
2058 SimpleAccessorGetter, SimpleAccessorSetter);
2059 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2061 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2062 CompileRun("var obj = new Obj;"
2063 "function setAge(i){ obj.age = i; };"
2064 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2065 // All i >= 10000 go to the accessor.
2066 ExpectInt32("obj.accessor_age", 10000);
2067 // The last i goes to the interceptor.
2068 ExpectInt32("obj.interceptor_age", 9999);
2072 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2073 v8::HandleScope scope(CcTest::isolate());
2074 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2075 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2076 child->Inherit(parent);
2077 AddAccessor(parent, v8_str("age"),
2078 SimpleAccessorGetter, SimpleAccessorSetter);
2079 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2081 env->Global()->Set(v8_str("Child"), child->GetFunction());
2082 CompileRun("var child = new Child;"
2083 "function setAge(i){ child.age = i; };"
2084 "for(var i = 0; i <= 10000; i++) setAge(i);");
2085 // All i < 10000 go to the interceptor.
2086 ExpectInt32("child.interceptor_age", 9999);
2087 // The last i goes to the accessor.
2088 ExpectInt32("child.accessor_age", 10000);
2092 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2093 v8::HandleScope scope(CcTest::isolate());
2094 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2095 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2096 child->Inherit(parent);
2097 AddAccessor(parent, v8_str("age"),
2098 SimpleAccessorGetter, SimpleAccessorSetter);
2099 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2101 env->Global()->Set(v8_str("Child"), child->GetFunction());
2102 CompileRun("var child = new Child;"
2103 "function setAge(i){ child.age = i; };"
2104 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2105 // All i >= 10000 go to the accessor.
2106 ExpectInt32("child.accessor_age", 10000);
2107 // The last i goes to the interceptor.
2108 ExpectInt32("child.interceptor_age", 9999);
2112 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2113 v8::HandleScope scope(CcTest::isolate());
2114 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2115 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2117 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2118 CompileRun("var obj = new Obj;"
2119 "function setter(i) { this.accessor_age = i; };"
2120 "function getter() { return this.accessor_age; };"
2121 "function setAge(i) { obj.age = i; };"
2122 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2123 "for(var i = 0; i <= 10000; i++) setAge(i);");
2124 // All i < 10000 go to the interceptor.
2125 ExpectInt32("obj.interceptor_age", 9999);
2126 // The last i goes to the JavaScript accessor.
2127 ExpectInt32("obj.accessor_age", 10000);
2128 // The installed JavaScript getter is still intact.
2129 // This last part is a regression test for issue 1651 and relies on the fact
2130 // that both interceptor and accessor are being installed on the same object.
2131 ExpectInt32("obj.age", 10000);
2132 ExpectBoolean("obj.hasOwnProperty('age')", true);
2133 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2137 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2138 v8::HandleScope scope(CcTest::isolate());
2139 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2140 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2142 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2143 CompileRun("var obj = new Obj;"
2144 "function setter(i) { this.accessor_age = i; };"
2145 "function getter() { return this.accessor_age; };"
2146 "function setAge(i) { obj.age = i; };"
2147 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2148 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2149 // All i >= 10000 go to the accessor.
2150 ExpectInt32("obj.accessor_age", 10000);
2151 // The last i goes to the interceptor.
2152 ExpectInt32("obj.interceptor_age", 9999);
2153 // The installed JavaScript getter is still intact.
2154 // This last part is a regression test for issue 1651 and relies on the fact
2155 // that both interceptor and accessor are being installed on the same object.
2156 ExpectInt32("obj.age", 10000);
2157 ExpectBoolean("obj.hasOwnProperty('age')", true);
2158 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2162 THREADED_TEST(SwitchFromInterceptorToProperty) {
2163 v8::HandleScope scope(CcTest::isolate());
2164 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2165 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2166 child->Inherit(parent);
2167 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2169 env->Global()->Set(v8_str("Child"), child->GetFunction());
2170 CompileRun("var child = new Child;"
2171 "function setAge(i){ child.age = i; };"
2172 "for(var i = 0; i <= 10000; i++) setAge(i);");
2173 // All i < 10000 go to the interceptor.
2174 ExpectInt32("child.interceptor_age", 9999);
2175 // The last i goes to child's own property.
2176 ExpectInt32("child.age", 10000);
2180 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2181 v8::HandleScope scope(CcTest::isolate());
2182 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2183 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2184 child->Inherit(parent);
2185 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2187 env->Global()->Set(v8_str("Child"), child->GetFunction());
2188 CompileRun("var child = new Child;"
2189 "function setAge(i){ child.age = i; };"
2190 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2191 // All i >= 10000 go to child's own property.
2192 ExpectInt32("child.age", 10000);
2193 // The last i goes to the interceptor.
2194 ExpectInt32("child.interceptor_age", 9999);
2198 THREADED_TEST(NamedPropertyHandlerGetter) {
2199 echo_named_call_count = 0;
2200 v8::HandleScope scope(CcTest::isolate());
2201 v8::Handle<v8::FunctionTemplate> templ =
2202 v8::FunctionTemplate::New(CcTest::isolate());
2203 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2207 env->Global()->Set(v8_str("obj"),
2208 templ->GetFunction()->NewInstance());
2209 CHECK_EQ(echo_named_call_count, 0);
2210 v8_compile("obj.x")->Run();
2211 CHECK_EQ(echo_named_call_count, 1);
2212 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2213 v8::Handle<Value> str = CompileRun(code);
2214 String::Utf8Value value(str);
2215 CHECK_EQ(*value, "oddlepoddle");
2216 // Check default behavior
2217 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2218 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2219 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2223 int echo_indexed_call_count = 0;
2226 static void EchoIndexedProperty(
2228 const v8::PropertyCallbackInfo<v8::Value>& info) {
2229 ApiTestFuzzer::Fuzz();
2230 CHECK_EQ(v8_num(637), info.Data());
2231 echo_indexed_call_count++;
2232 info.GetReturnValue().Set(v8_num(index));
2236 THREADED_TEST(IndexedPropertyHandlerGetter) {
2237 v8::Isolate* isolate = CcTest::isolate();
2238 v8::HandleScope scope(isolate);
2239 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2240 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2244 env->Global()->Set(v8_str("obj"),
2245 templ->GetFunction()->NewInstance());
2246 Local<Script> script = v8_compile("obj[900]");
2247 CHECK_EQ(script->Run()->Int32Value(), 900);
2251 v8::Handle<v8::Object> bottom;
2253 static void CheckThisIndexedPropertyHandler(
2255 const v8::PropertyCallbackInfo<v8::Value>& info) {
2256 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2257 ApiTestFuzzer::Fuzz();
2258 CHECK(info.This()->Equals(bottom));
2261 static void CheckThisNamedPropertyHandler(
2263 const v8::PropertyCallbackInfo<v8::Value>& info) {
2264 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2265 ApiTestFuzzer::Fuzz();
2266 CHECK(info.This()->Equals(bottom));
2269 void CheckThisIndexedPropertySetter(
2272 const v8::PropertyCallbackInfo<v8::Value>& info) {
2273 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2274 ApiTestFuzzer::Fuzz();
2275 CHECK(info.This()->Equals(bottom));
2279 void CheckThisNamedPropertySetter(
2280 Local<String> property,
2282 const v8::PropertyCallbackInfo<v8::Value>& info) {
2283 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2284 ApiTestFuzzer::Fuzz();
2285 CHECK(info.This()->Equals(bottom));
2288 void CheckThisIndexedPropertyQuery(
2290 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2291 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2292 ApiTestFuzzer::Fuzz();
2293 CHECK(info.This()->Equals(bottom));
2297 void CheckThisNamedPropertyQuery(
2298 Local<String> property,
2299 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2300 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2301 ApiTestFuzzer::Fuzz();
2302 CHECK(info.This()->Equals(bottom));
2306 void CheckThisIndexedPropertyDeleter(
2308 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2309 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2310 ApiTestFuzzer::Fuzz();
2311 CHECK(info.This()->Equals(bottom));
2315 void CheckThisNamedPropertyDeleter(
2316 Local<String> property,
2317 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2318 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2319 ApiTestFuzzer::Fuzz();
2320 CHECK(info.This()->Equals(bottom));
2324 void CheckThisIndexedPropertyEnumerator(
2325 const v8::PropertyCallbackInfo<v8::Array>& info) {
2326 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2327 ApiTestFuzzer::Fuzz();
2328 CHECK(info.This()->Equals(bottom));
2332 void CheckThisNamedPropertyEnumerator(
2333 const v8::PropertyCallbackInfo<v8::Array>& info) {
2334 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2335 ApiTestFuzzer::Fuzz();
2336 CHECK(info.This()->Equals(bottom));
2340 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2342 v8::Isolate* isolate = env->GetIsolate();
2343 v8::HandleScope scope(isolate);
2345 // Set up a prototype chain with three interceptors.
2346 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2347 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2348 CheckThisIndexedPropertyHandler,
2349 CheckThisIndexedPropertySetter,
2350 CheckThisIndexedPropertyQuery,
2351 CheckThisIndexedPropertyDeleter,
2352 CheckThisIndexedPropertyEnumerator);
2354 templ->InstanceTemplate()->SetNamedPropertyHandler(
2355 CheckThisNamedPropertyHandler,
2356 CheckThisNamedPropertySetter,
2357 CheckThisNamedPropertyQuery,
2358 CheckThisNamedPropertyDeleter,
2359 CheckThisNamedPropertyEnumerator);
2361 bottom = templ->GetFunction()->NewInstance();
2362 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2363 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2365 bottom->SetPrototype(middle);
2366 middle->SetPrototype(top);
2367 env->Global()->Set(v8_str("obj"), bottom);
2369 // Indexed and named get.
2370 CompileRun("obj[0]");
2371 CompileRun("obj.x");
2373 // Indexed and named set.
2374 CompileRun("obj[1] = 42");
2375 CompileRun("obj.y = 42");
2377 // Indexed and named query.
2378 CompileRun("0 in obj");
2379 CompileRun("'x' in obj");
2381 // Indexed and named deleter.
2382 CompileRun("delete obj[0]");
2383 CompileRun("delete obj.x");
2386 CompileRun("for (var p in obj) ;");
2390 static void PrePropertyHandlerGet(
2392 const v8::PropertyCallbackInfo<v8::Value>& info) {
2393 ApiTestFuzzer::Fuzz();
2394 if (v8_str("pre")->Equals(key)) {
2395 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2400 static void PrePropertyHandlerQuery(
2402 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2403 if (v8_str("pre")->Equals(key)) {
2404 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2409 THREADED_TEST(PrePropertyHandler) {
2410 v8::Isolate* isolate = CcTest::isolate();
2411 v8::HandleScope scope(isolate);
2412 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2413 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2415 PrePropertyHandlerQuery);
2416 LocalContext env(NULL, desc->InstanceTemplate());
2417 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2418 v8::Handle<Value> result_pre = CompileRun("pre");
2419 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2420 v8::Handle<Value> result_on = CompileRun("on");
2421 CHECK_EQ(v8_str("Object: on"), result_on);
2422 v8::Handle<Value> result_post = CompileRun("post");
2423 CHECK(result_post.IsEmpty());
2427 THREADED_TEST(UndefinedIsNotEnumerable) {
2429 v8::HandleScope scope(env->GetIsolate());
2430 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2431 CHECK(result->IsFalse());
2435 v8::Handle<Script> call_recursively_script;
2436 static const int kTargetRecursionDepth = 200; // near maximum
2439 static void CallScriptRecursivelyCall(
2440 const v8::FunctionCallbackInfo<v8::Value>& args) {
2441 ApiTestFuzzer::Fuzz();
2442 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2443 if (depth == kTargetRecursionDepth) return;
2444 args.This()->Set(v8_str("depth"),
2445 v8::Integer::New(args.GetIsolate(), depth + 1));
2446 args.GetReturnValue().Set(call_recursively_script->Run());
2450 static void CallFunctionRecursivelyCall(
2451 const v8::FunctionCallbackInfo<v8::Value>& args) {
2452 ApiTestFuzzer::Fuzz();
2453 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2454 if (depth == kTargetRecursionDepth) {
2455 printf("[depth = %d]\n", depth);
2458 args.This()->Set(v8_str("depth"),
2459 v8::Integer::New(args.GetIsolate(), depth + 1));
2460 v8::Handle<Value> function =
2461 args.This()->Get(v8_str("callFunctionRecursively"));
2462 args.GetReturnValue().Set(
2463 function.As<Function>()->Call(args.This(), 0, NULL));
2467 THREADED_TEST(DeepCrossLanguageRecursion) {
2468 v8::Isolate* isolate = CcTest::isolate();
2469 v8::HandleScope scope(isolate);
2470 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2471 global->Set(v8_str("callScriptRecursively"),
2472 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2473 global->Set(v8_str("callFunctionRecursively"),
2474 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2475 LocalContext env(NULL, global);
2477 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2478 call_recursively_script = v8_compile("callScriptRecursively()");
2479 call_recursively_script->Run();
2480 call_recursively_script = v8::Handle<Script>();
2482 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2483 CompileRun("callFunctionRecursively()");
2487 static void ThrowingPropertyHandlerGet(
2489 const v8::PropertyCallbackInfo<v8::Value>& info) {
2490 ApiTestFuzzer::Fuzz();
2491 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2495 static void ThrowingPropertyHandlerSet(
2498 const v8::PropertyCallbackInfo<v8::Value>& info) {
2499 info.GetIsolate()->ThrowException(key);
2500 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2504 THREADED_TEST(CallbackExceptionRegression) {
2505 v8::Isolate* isolate = CcTest::isolate();
2506 v8::HandleScope scope(isolate);
2507 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2508 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2509 ThrowingPropertyHandlerSet);
2511 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2512 v8::Handle<Value> otto = CompileRun(
2513 "try { with (obj) { otto; } } catch (e) { e; }");
2514 CHECK_EQ(v8_str("otto"), otto);
2515 v8::Handle<Value> netto = CompileRun(
2516 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2517 CHECK_EQ(v8_str("netto"), netto);
2521 THREADED_TEST(FunctionPrototype) {
2522 v8::Isolate* isolate = CcTest::isolate();
2523 v8::HandleScope scope(isolate);
2524 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2525 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2527 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2528 Local<Script> script = v8_compile("Foo.prototype.plak");
2529 CHECK_EQ(script->Run()->Int32Value(), 321);
2533 THREADED_TEST(InternalFields) {
2535 v8::Isolate* isolate = env->GetIsolate();
2536 v8::HandleScope scope(isolate);
2538 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2539 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2540 instance_templ->SetInternalFieldCount(1);
2541 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2542 CHECK_EQ(1, obj->InternalFieldCount());
2543 CHECK(obj->GetInternalField(0)->IsUndefined());
2544 obj->SetInternalField(0, v8_num(17));
2545 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2549 THREADED_TEST(GlobalObjectInternalFields) {
2550 v8::Isolate* isolate = CcTest::isolate();
2551 v8::HandleScope scope(isolate);
2552 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2553 global_template->SetInternalFieldCount(1);
2554 LocalContext env(NULL, global_template);
2555 v8::Handle<v8::Object> global_proxy = env->Global();
2556 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2557 CHECK_EQ(1, global->InternalFieldCount());
2558 CHECK(global->GetInternalField(0)->IsUndefined());
2559 global->SetInternalField(0, v8_num(17));
2560 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2564 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2566 v8::HandleScope scope(CcTest::isolate());
2568 v8::Local<v8::Object> global = env->Global();
2569 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2570 CHECK(global->HasRealIndexedProperty(0));
2574 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2576 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2577 obj->SetAlignedPointerInInternalField(0, value);
2578 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2579 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2583 THREADED_TEST(InternalFieldsAlignedPointers) {
2585 v8::Isolate* isolate = env->GetIsolate();
2586 v8::HandleScope scope(isolate);
2588 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2589 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2590 instance_templ->SetInternalFieldCount(1);
2591 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2592 CHECK_EQ(1, obj->InternalFieldCount());
2594 CheckAlignedPointerInInternalField(obj, NULL);
2596 int* heap_allocated = new int[100];
2597 CheckAlignedPointerInInternalField(obj, heap_allocated);
2598 delete[] heap_allocated;
2600 int stack_allocated[100];
2601 CheckAlignedPointerInInternalField(obj, stack_allocated);
2603 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2604 CheckAlignedPointerInInternalField(obj, huge);
2606 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2607 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2608 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2612 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2615 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2616 (*env)->SetAlignedPointerInEmbedderData(index, value);
2617 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2618 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2622 static void* AlignedTestPointer(int i) {
2623 return reinterpret_cast<void*>(i * 1234);
2627 THREADED_TEST(EmbedderDataAlignedPointers) {
2629 v8::HandleScope scope(env->GetIsolate());
2631 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2633 int* heap_allocated = new int[100];
2634 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2635 delete[] heap_allocated;
2637 int stack_allocated[100];
2638 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2640 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2641 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2643 // Test growing of the embedder data's backing store.
2644 for (int i = 0; i < 100; i++) {
2645 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2647 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2648 for (int i = 0; i < 100; i++) {
2649 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2654 static void CheckEmbedderData(LocalContext* env,
2656 v8::Handle<Value> data) {
2657 (*env)->SetEmbedderData(index, data);
2658 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2662 THREADED_TEST(EmbedderData) {
2664 v8::Isolate* isolate = env->GetIsolate();
2665 v8::HandleScope scope(isolate);
2669 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2670 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2671 "over the lazy dog."));
2672 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2673 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2677 THREADED_TEST(IdentityHash) {
2679 v8::Isolate* isolate = env->GetIsolate();
2680 v8::HandleScope scope(isolate);
2682 // Ensure that the test starts with an fresh heap to test whether the hash
2683 // code is based on the address.
2684 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2685 Local<v8::Object> obj = v8::Object::New(isolate);
2686 int hash = obj->GetIdentityHash();
2687 int hash1 = obj->GetIdentityHash();
2688 CHECK_EQ(hash, hash1);
2689 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2690 // Since the identity hash is essentially a random number two consecutive
2691 // objects should not be assigned the same hash code. If the test below fails
2692 // the random number generator should be evaluated.
2693 CHECK_NE(hash, hash2);
2694 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2695 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2696 // Make sure that the identity hash is not based on the initial address of
2697 // the object alone. If the test below fails the random number generator
2698 // should be evaluated.
2699 CHECK_NE(hash, hash3);
2700 int hash4 = obj->GetIdentityHash();
2701 CHECK_EQ(hash, hash4);
2703 // Check identity hashes behaviour in the presence of JS accessors.
2704 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2706 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2707 Local<v8::Object> o1 = v8::Object::New(isolate);
2708 Local<v8::Object> o2 = v8::Object::New(isolate);
2709 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2713 "function cnst() { return 42; };\n"
2714 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2715 Local<v8::Object> o1 = v8::Object::New(isolate);
2716 Local<v8::Object> o2 = v8::Object::New(isolate);
2717 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2722 THREADED_TEST(GlobalProxyIdentityHash) {
2724 v8::Isolate* isolate = env->GetIsolate();
2725 v8::HandleScope scope(isolate);
2726 Handle<Object> global_proxy = env->Global();
2727 int hash1 = global_proxy->GetIdentityHash();
2728 // Hash should be retained after being detached.
2729 env->DetachGlobal();
2730 int hash2 = global_proxy->GetIdentityHash();
2731 CHECK_EQ(hash1, hash2);
2733 // Re-attach global proxy to a new context, hash should stay the same.
2734 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2735 int hash3 = global_proxy->GetIdentityHash();
2736 CHECK_EQ(hash1, hash3);
2741 THREADED_TEST(SymbolProperties) {
2743 v8::Isolate* isolate = env->GetIsolate();
2744 v8::HandleScope scope(isolate);
2746 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2747 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2748 v8::Local<v8::Symbol> sym2 =
2749 v8::Symbol::New(isolate, v8_str("my-symbol"));
2751 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2753 // Check basic symbol functionality.
2754 CHECK(sym1->IsSymbol());
2755 CHECK(sym2->IsSymbol());
2756 CHECK(!obj->IsSymbol());
2758 CHECK(sym1->Equals(sym1));
2759 CHECK(sym2->Equals(sym2));
2760 CHECK(!sym1->Equals(sym2));
2761 CHECK(!sym2->Equals(sym1));
2762 CHECK(sym1->StrictEquals(sym1));
2763 CHECK(sym2->StrictEquals(sym2));
2764 CHECK(!sym1->StrictEquals(sym2));
2765 CHECK(!sym2->StrictEquals(sym1));
2767 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2769 v8::Local<v8::Value> sym_val = sym2;
2770 CHECK(sym_val->IsSymbol());
2771 CHECK(sym_val->Equals(sym2));
2772 CHECK(sym_val->StrictEquals(sym2));
2773 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2775 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2776 CHECK(sym_obj->IsSymbolObject());
2777 CHECK(!sym2->IsSymbolObject());
2778 CHECK(!obj->IsSymbolObject());
2779 CHECK(!sym_obj->Equals(sym2));
2780 CHECK(!sym_obj->StrictEquals(sym2));
2781 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2782 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2784 // Make sure delete of a non-existent symbol property works.
2785 CHECK(obj->Delete(sym1));
2786 CHECK(!obj->Has(sym1));
2788 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2789 CHECK(obj->Has(sym1));
2790 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2791 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2792 CHECK(obj->Has(sym1));
2793 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2794 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2796 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2797 int num_props = obj->GetPropertyNames()->Length();
2798 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2799 v8::Integer::New(isolate, 20)));
2800 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2801 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2803 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2805 // Add another property and delete it afterwards to force the object in
2807 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2808 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2809 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2810 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2811 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2813 CHECK(obj->Has(sym1));
2814 CHECK(obj->Has(sym2));
2815 CHECK(obj->Delete(sym2));
2816 CHECK(obj->Has(sym1));
2817 CHECK(!obj->Has(sym2));
2818 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2821 // Symbol properties are inherited.
2822 v8::Local<v8::Object> child = v8::Object::New(isolate);
2823 child->SetPrototype(obj);
2824 CHECK(child->Has(sym1));
2825 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2826 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2830 THREADED_TEST(PrivateProperties) {
2832 v8::Isolate* isolate = env->GetIsolate();
2833 v8::HandleScope scope(isolate);
2835 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2836 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2837 v8::Local<v8::Private> priv2 =
2838 v8::Private::New(isolate, v8_str("my-private"));
2840 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2842 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2844 // Make sure delete of a non-existent private symbol property works.
2845 CHECK(obj->DeletePrivate(priv1));
2846 CHECK(!obj->HasPrivate(priv1));
2848 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2849 CHECK(obj->HasPrivate(priv1));
2850 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2851 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2852 CHECK(obj->HasPrivate(priv1));
2853 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2855 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2856 int num_props = obj->GetPropertyNames()->Length();
2857 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2858 v8::Integer::New(isolate, 20)));
2859 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2860 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2862 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2864 // Add another property and delete it afterwards to force the object in
2866 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2867 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2868 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2869 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2870 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2872 CHECK(obj->HasPrivate(priv1));
2873 CHECK(obj->HasPrivate(priv2));
2874 CHECK(obj->DeletePrivate(priv2));
2875 CHECK(obj->HasPrivate(priv1));
2876 CHECK(!obj->HasPrivate(priv2));
2877 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2878 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2880 // Private properties are inherited (for the time being).
2881 v8::Local<v8::Object> child = v8::Object::New(isolate);
2882 child->SetPrototype(obj);
2883 CHECK(child->HasPrivate(priv1));
2884 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2885 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2889 THREADED_TEST(GlobalSymbols) {
2891 v8::Isolate* isolate = env->GetIsolate();
2892 v8::HandleScope scope(isolate);
2894 v8::Local<String> name = v8_str("my-symbol");
2895 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2896 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2897 CHECK(glob2->SameValue(glob));
2899 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2900 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2901 CHECK(glob_api2->SameValue(glob_api));
2902 CHECK(!glob_api->SameValue(glob));
2904 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2905 CHECK(!sym->SameValue(glob));
2907 CompileRun("var sym2 = Symbol.for('my-symbol')");
2908 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2909 CHECK(sym2->SameValue(glob));
2910 CHECK(!sym2->SameValue(glob_api));
2914 THREADED_TEST(GlobalPrivates) {
2916 v8::Isolate* isolate = env->GetIsolate();
2917 v8::HandleScope scope(isolate);
2919 v8::Local<String> name = v8_str("my-private");
2920 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2921 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2922 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2924 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2925 CHECK(obj->HasPrivate(glob2));
2927 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2928 CHECK(!obj->HasPrivate(priv));
2930 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2931 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2932 CHECK(!obj->Has(intern));
2936 class ScopedArrayBufferContents {
2938 explicit ScopedArrayBufferContents(
2939 const v8::ArrayBuffer::Contents& contents)
2940 : contents_(contents) {}
2941 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2942 void* Data() const { return contents_.Data(); }
2943 size_t ByteLength() const { return contents_.ByteLength(); }
2945 const v8::ArrayBuffer::Contents contents_;
2948 template <typename T>
2949 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2950 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2951 for (int i = 0; i < value->InternalFieldCount(); i++) {
2952 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2957 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2959 v8::Isolate* isolate = env->GetIsolate();
2960 v8::HandleScope handle_scope(isolate);
2962 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2963 CheckInternalFieldsAreZero(ab);
2964 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2965 CHECK(!ab->IsExternal());
2966 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2968 ScopedArrayBufferContents ab_contents(ab->Externalize());
2969 CHECK(ab->IsExternal());
2971 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2972 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2973 DCHECK(data != NULL);
2974 env->Global()->Set(v8_str("ab"), ab);
2976 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2977 CHECK_EQ(1024, result->Int32Value());
2979 result = CompileRun("var u8 = new Uint8Array(ab);"
2983 CHECK_EQ(1024, result->Int32Value());
2984 CHECK_EQ(0xFF, data[0]);
2985 CHECK_EQ(0xAA, data[1]);
2988 result = CompileRun("u8[0] + u8[1]");
2989 CHECK_EQ(0xDD, result->Int32Value());
2993 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2995 v8::Isolate* isolate = env->GetIsolate();
2996 v8::HandleScope handle_scope(isolate);
2999 v8::Local<v8::Value> result =
3000 CompileRun("var ab1 = new ArrayBuffer(2);"
3001 "var u8_a = new Uint8Array(ab1);"
3003 "u8_a[1] = 0xFF; u8_a.buffer");
3004 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3005 CheckInternalFieldsAreZero(ab1);
3006 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3007 CHECK(!ab1->IsExternal());
3008 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3009 CHECK(ab1->IsExternal());
3011 result = CompileRun("ab1.byteLength");
3012 CHECK_EQ(2, result->Int32Value());
3013 result = CompileRun("u8_a[0]");
3014 CHECK_EQ(0xAA, result->Int32Value());
3015 result = CompileRun("u8_a[1]");
3016 CHECK_EQ(0xFF, result->Int32Value());
3017 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3020 CHECK_EQ(0xBB, result->Int32Value());
3021 result = CompileRun("u8_b[1]");
3022 CHECK_EQ(0xFF, result->Int32Value());
3024 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3025 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3026 CHECK_EQ(0xBB, ab1_data[0]);
3027 CHECK_EQ(0xFF, ab1_data[1]);
3030 result = CompileRun("u8_a[0] + u8_a[1]");
3031 CHECK_EQ(0xDD, result->Int32Value());
3035 THREADED_TEST(ArrayBuffer_External) {
3037 v8::Isolate* isolate = env->GetIsolate();
3038 v8::HandleScope handle_scope(isolate);
3040 i::ScopedVector<uint8_t> my_data(100);
3041 memset(my_data.start(), 0, 100);
3042 Local<v8::ArrayBuffer> ab3 =
3043 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3044 CheckInternalFieldsAreZero(ab3);
3045 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3046 CHECK(ab3->IsExternal());
3048 env->Global()->Set(v8_str("ab3"), ab3);
3050 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3051 CHECK_EQ(100, result->Int32Value());
3053 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3057 CHECK_EQ(100, result->Int32Value());
3058 CHECK_EQ(0xBB, my_data[0]);
3059 CHECK_EQ(0xCC, my_data[1]);
3062 result = CompileRun("u8_b[0] + u8_b[1]");
3063 CHECK_EQ(0xDD, result->Int32Value());
3067 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3068 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3069 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3073 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3074 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3075 CHECK_EQ(0, static_cast<int>(ta->Length()));
3076 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3080 static void CheckIsTypedArrayVarNeutered(const char* name) {
3081 i::ScopedVector<char> source(1024);
3083 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3085 CHECK(CompileRun(source.start())->IsTrue());
3086 v8::Handle<v8::TypedArray> ta =
3087 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3088 CheckIsNeutered(ta);
3092 template <typename TypedArray, int kElementSize>
3093 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3096 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3097 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3098 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3099 CHECK_EQ(length, static_cast<int>(ta->Length()));
3100 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3105 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3107 v8::Isolate* isolate = env->GetIsolate();
3108 v8::HandleScope handle_scope(isolate);
3110 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3112 v8::Handle<v8::Uint8Array> u8a =
3113 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3114 v8::Handle<v8::Uint8ClampedArray> u8c =
3115 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3116 v8::Handle<v8::Int8Array> i8a =
3117 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3119 v8::Handle<v8::Uint16Array> u16a =
3120 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3121 v8::Handle<v8::Int16Array> i16a =
3122 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3124 v8::Handle<v8::Uint32Array> u32a =
3125 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3126 v8::Handle<v8::Int32Array> i32a =
3127 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3129 v8::Handle<v8::Float32Array> f32a =
3130 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3131 v8::Handle<v8::Float64Array> f64a =
3132 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3134 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3135 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3136 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3137 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3139 ScopedArrayBufferContents contents(buffer->Externalize());
3141 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3142 CheckIsNeutered(u8a);
3143 CheckIsNeutered(u8c);
3144 CheckIsNeutered(i8a);
3145 CheckIsNeutered(u16a);
3146 CheckIsNeutered(i16a);
3147 CheckIsNeutered(u32a);
3148 CheckIsNeutered(i32a);
3149 CheckIsNeutered(f32a);
3150 CheckIsNeutered(f64a);
3151 CheckDataViewIsNeutered(dv);
3155 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3157 v8::Isolate* isolate = env->GetIsolate();
3158 v8::HandleScope handle_scope(isolate);
3161 "var ab = new ArrayBuffer(1024);"
3162 "var u8a = new Uint8Array(ab, 1, 1023);"
3163 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3164 "var i8a = new Int8Array(ab, 1, 1023);"
3165 "var u16a = new Uint16Array(ab, 2, 511);"
3166 "var i16a = new Int16Array(ab, 2, 511);"
3167 "var u32a = new Uint32Array(ab, 4, 255);"
3168 "var i32a = new Int32Array(ab, 4, 255);"
3169 "var f32a = new Float32Array(ab, 4, 255);"
3170 "var f64a = new Float64Array(ab, 8, 127);"
3171 "var dv = new DataView(ab, 1, 1023);");
3173 v8::Handle<v8::ArrayBuffer> ab =
3174 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3176 v8::Handle<v8::DataView> dv =
3177 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3179 ScopedArrayBufferContents contents(ab->Externalize());
3181 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3182 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3184 CheckIsTypedArrayVarNeutered("u8a");
3185 CheckIsTypedArrayVarNeutered("u8c");
3186 CheckIsTypedArrayVarNeutered("i8a");
3187 CheckIsTypedArrayVarNeutered("u16a");
3188 CheckIsTypedArrayVarNeutered("i16a");
3189 CheckIsTypedArrayVarNeutered("u32a");
3190 CheckIsTypedArrayVarNeutered("i32a");
3191 CheckIsTypedArrayVarNeutered("f32a");
3192 CheckIsTypedArrayVarNeutered("f64a");
3194 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3195 CheckDataViewIsNeutered(dv);
3200 THREADED_TEST(HiddenProperties) {
3202 v8::Isolate* isolate = env->GetIsolate();
3203 v8::HandleScope scope(isolate);
3205 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3206 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3207 v8::Local<v8::String> empty = v8_str("");
3208 v8::Local<v8::String> prop_name = v8_str("prop_name");
3210 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3212 // Make sure delete of a non-existent hidden value works
3213 CHECK(obj->DeleteHiddenValue(key));
3215 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3216 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3217 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3218 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3220 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3222 // Make sure we do not find the hidden property.
3223 CHECK(!obj->Has(empty));
3224 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3225 CHECK(obj->Get(empty)->IsUndefined());
3226 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3227 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3228 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3229 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3231 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3233 // Add another property and delete it afterwards to force the object in
3235 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3236 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3237 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3238 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239 CHECK(obj->Delete(prop_name));
3240 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3242 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3244 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3245 CHECK(obj->GetHiddenValue(key).IsEmpty());
3247 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3248 CHECK(obj->DeleteHiddenValue(key));
3249 CHECK(obj->GetHiddenValue(key).IsEmpty());
3253 THREADED_TEST(Regress97784) {
3254 // Regression test for crbug.com/97784
3255 // Messing with the Object.prototype should not have effect on
3256 // hidden properties.
3258 v8::HandleScope scope(env->GetIsolate());
3260 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3261 v8::Local<v8::String> key = v8_str("hidden");
3264 "set_called = false;"
3265 "Object.defineProperty("
3266 " Object.prototype,"
3268 " {get: function() { return 45; },"
3269 " set: function() { set_called = true; }})");
3271 CHECK(obj->GetHiddenValue(key).IsEmpty());
3272 // Make sure that the getter and setter from Object.prototype is not invoked.
3273 // If it did we would have full access to the hidden properties in
3275 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3276 ExpectFalse("set_called");
3277 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3281 static bool interceptor_for_hidden_properties_called;
3282 static void InterceptorForHiddenProperties(
3283 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3284 interceptor_for_hidden_properties_called = true;
3288 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3289 LocalContext context;
3290 v8::Isolate* isolate = context->GetIsolate();
3291 v8::HandleScope scope(isolate);
3293 interceptor_for_hidden_properties_called = false;
3295 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3297 // Associate an interceptor with an object and start setting hidden values.
3298 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3299 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3300 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3301 Local<v8::Function> function = fun_templ->GetFunction();
3302 Local<v8::Object> obj = function->NewInstance();
3303 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3304 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3305 CHECK(!interceptor_for_hidden_properties_called);
3309 THREADED_TEST(External) {
3310 v8::HandleScope scope(CcTest::isolate());
3312 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3314 env->Global()->Set(v8_str("ext"), ext);
3315 Local<Value> reext_obj = CompileRun("this.ext");
3316 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3317 int* ptr = static_cast<int*>(reext->Value());
3322 // Make sure unaligned pointers are wrapped properly.
3323 char* data = i::StrDup("0123456789");
3324 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3325 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3326 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3327 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3329 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3330 CHECK_EQ('0', *char_ptr);
3331 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3332 CHECK_EQ('1', *char_ptr);
3333 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3334 CHECK_EQ('2', *char_ptr);
3335 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3336 CHECK_EQ('3', *char_ptr);
3337 i::DeleteArray(data);
3341 THREADED_TEST(GlobalHandle) {
3342 v8::Isolate* isolate = CcTest::isolate();
3343 v8::Persistent<String> global;
3345 v8::HandleScope scope(isolate);
3346 global.Reset(isolate, v8_str("str"));
3349 v8::HandleScope scope(isolate);
3350 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3354 v8::HandleScope scope(isolate);
3355 global.Reset(isolate, v8_str("str"));
3358 v8::HandleScope scope(isolate);
3359 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3365 THREADED_TEST(ResettingGlobalHandle) {
3366 v8::Isolate* isolate = CcTest::isolate();
3367 v8::Persistent<String> global;
3369 v8::HandleScope scope(isolate);
3370 global.Reset(isolate, v8_str("str"));
3372 v8::internal::GlobalHandles* global_handles =
3373 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3374 int initial_handle_count = global_handles->global_handles_count();
3376 v8::HandleScope scope(isolate);
3377 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3380 v8::HandleScope scope(isolate);
3381 global.Reset(isolate, v8_str("longer"));
3383 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3385 v8::HandleScope scope(isolate);
3386 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3389 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3393 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3394 v8::Isolate* isolate = CcTest::isolate();
3395 v8::Persistent<String> global;
3397 v8::HandleScope scope(isolate);
3398 global.Reset(isolate, v8_str("str"));
3400 v8::internal::GlobalHandles* global_handles =
3401 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3402 int initial_handle_count = global_handles->global_handles_count();
3404 v8::HandleScope scope(isolate);
3405 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3408 v8::HandleScope scope(isolate);
3409 Local<String> empty;
3410 global.Reset(isolate, empty);
3412 CHECK(global.IsEmpty());
3413 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3418 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3419 return unique.Pass();
3424 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3425 const v8::Persistent<T> & global) {
3426 v8::UniquePersistent<String> unique(isolate, global);
3427 return unique.Pass();
3431 THREADED_TEST(UniquePersistent) {
3432 v8::Isolate* isolate = CcTest::isolate();
3433 v8::Persistent<String> global;
3435 v8::HandleScope scope(isolate);
3436 global.Reset(isolate, v8_str("str"));
3438 v8::internal::GlobalHandles* global_handles =
3439 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3440 int initial_handle_count = global_handles->global_handles_count();
3442 v8::UniquePersistent<String> unique(isolate, global);
3443 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3444 // Test assignment via Pass
3446 v8::UniquePersistent<String> copy = unique.Pass();
3447 CHECK(unique.IsEmpty());
3448 CHECK(copy == global);
3449 CHECK_EQ(initial_handle_count + 1,
3450 global_handles->global_handles_count());
3451 unique = copy.Pass();
3453 // Test ctor via Pass
3455 v8::UniquePersistent<String> copy(unique.Pass());
3456 CHECK(unique.IsEmpty());
3457 CHECK(copy == global);
3458 CHECK_EQ(initial_handle_count + 1,
3459 global_handles->global_handles_count());
3460 unique = copy.Pass();
3462 // Test pass through function call
3464 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3465 CHECK(unique.IsEmpty());
3466 CHECK(copy == global);
3467 CHECK_EQ(initial_handle_count + 1,
3468 global_handles->global_handles_count());
3469 unique = copy.Pass();
3471 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3473 // Test pass from function call
3475 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3476 CHECK(unique == global);
3477 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3479 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3484 template<typename K, typename V>
3485 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3487 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3489 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3490 struct WeakCallbackDataType {
3494 static WeakCallbackDataType* WeakCallbackParameter(
3495 MapType* map, const K& key, Local<V> value) {
3496 WeakCallbackDataType* data = new WeakCallbackDataType;
3501 static MapType* MapFromWeakCallbackData(
3502 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3503 return data.GetParameter()->map;
3505 static K KeyFromWeakCallbackData(
3506 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3507 return data.GetParameter()->key;
3509 static void DisposeCallbackData(WeakCallbackDataType* data) {
3512 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3517 template<typename Map>
3518 static void TestPersistentValueMap() {
3520 v8::Isolate* isolate = env->GetIsolate();
3522 v8::internal::GlobalHandles* global_handles =
3523 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3524 int initial_handle_count = global_handles->global_handles_count();
3525 CHECK_EQ(0, static_cast<int>(map.Size()));
3527 HandleScope scope(isolate);
3528 Local<v8::Object> obj = map.Get(7);
3529 CHECK(obj.IsEmpty());
3530 Local<v8::Object> expected = v8::Object::New(isolate);
3531 map.Set(7, expected);
3532 CHECK_EQ(1, static_cast<int>(map.Size()));
3534 CHECK_EQ(expected, obj);
3536 typename Map::PersistentValueReference ref = map.GetReference(7);
3537 CHECK_EQ(expected, ref.NewLocal(isolate));
3539 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3540 CHECK_EQ(0, static_cast<int>(map.Size()));
3541 CHECK(expected == removed);
3542 removed = map.Remove(7);
3543 CHECK(removed.IsEmpty());
3544 map.Set(8, expected);
3545 CHECK_EQ(1, static_cast<int>(map.Size()));
3546 map.Set(8, expected);
3547 CHECK_EQ(1, static_cast<int>(map.Size()));
3549 typename Map::PersistentValueReference ref;
3550 Local<v8::Object> expected2 = v8::Object::New(isolate);
3551 removed = map.Set(8,
3552 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3553 CHECK_EQ(1, static_cast<int>(map.Size()));
3554 CHECK(expected == removed);
3555 CHECK_EQ(expected2, ref.NewLocal(isolate));
3558 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3560 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3561 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3565 CHECK_EQ(0, static_cast<int>(map.Size()));
3566 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3570 TEST(PersistentValueMap) {
3571 // Default case, w/o weak callbacks:
3572 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3574 // Custom traits with weak callbacks:
3575 typedef v8::PersistentValueMap<int, v8::Object,
3576 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3577 TestPersistentValueMap<WeakPersistentValueMap>();
3581 TEST(PersistentValueVector) {
3583 v8::Isolate* isolate = env->GetIsolate();
3584 v8::internal::GlobalHandles* global_handles =
3585 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3586 int handle_count = global_handles->global_handles_count();
3587 HandleScope scope(isolate);
3589 v8::PersistentValueVector<v8::Object> vector(isolate);
3591 Local<v8::Object> obj1 = v8::Object::New(isolate);
3592 Local<v8::Object> obj2 = v8::Object::New(isolate);
3593 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3595 CHECK(vector.IsEmpty());
3596 CHECK_EQ(0, static_cast<int>(vector.Size()));
3598 vector.ReserveCapacity(3);
3599 CHECK(vector.IsEmpty());
3601 vector.Append(obj1);
3602 vector.Append(obj2);
3603 vector.Append(obj1);
3604 vector.Append(obj3.Pass());
3605 vector.Append(obj1);
3607 CHECK(!vector.IsEmpty());
3608 CHECK_EQ(5, static_cast<int>(vector.Size()));
3609 CHECK(obj3.IsEmpty());
3610 CHECK_EQ(obj1, vector.Get(0));
3611 CHECK_EQ(obj1, vector.Get(2));
3612 CHECK_EQ(obj1, vector.Get(4));
3613 CHECK_EQ(obj2, vector.Get(1));
3615 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3618 CHECK(vector.IsEmpty());
3619 CHECK_EQ(0, static_cast<int>(vector.Size()));
3620 CHECK_EQ(handle_count, global_handles->global_handles_count());
3624 THREADED_TEST(GlobalHandleUpcast) {
3625 v8::Isolate* isolate = CcTest::isolate();
3626 v8::HandleScope scope(isolate);
3627 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3628 v8::Persistent<String> global_string(isolate, local);
3629 v8::Persistent<Value>& global_value =
3630 v8::Persistent<Value>::Cast(global_string);
3631 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3632 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3633 global_string.Reset();
3637 THREADED_TEST(HandleEquality) {
3638 v8::Isolate* isolate = CcTest::isolate();
3639 v8::Persistent<String> global1;
3640 v8::Persistent<String> global2;
3642 v8::HandleScope scope(isolate);
3643 global1.Reset(isolate, v8_str("str"));
3644 global2.Reset(isolate, v8_str("str2"));
3646 CHECK_EQ(global1 == global1, true);
3647 CHECK_EQ(global1 != global1, false);
3649 v8::HandleScope scope(isolate);
3650 Local<String> local1 = Local<String>::New(isolate, global1);
3651 Local<String> local2 = Local<String>::New(isolate, global2);
3653 CHECK_EQ(global1 == local1, true);
3654 CHECK_EQ(global1 != local1, false);
3655 CHECK_EQ(local1 == global1, true);
3656 CHECK_EQ(local1 != global1, false);
3658 CHECK_EQ(global1 == local2, false);
3659 CHECK_EQ(global1 != local2, true);
3660 CHECK_EQ(local2 == global1, false);
3661 CHECK_EQ(local2 != global1, true);
3663 CHECK_EQ(local1 == local2, false);
3664 CHECK_EQ(local1 != local2, true);
3666 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3667 CHECK_EQ(local1 == anotherLocal1, true);
3668 CHECK_EQ(local1 != anotherLocal1, false);
3675 THREADED_TEST(LocalHandle) {
3676 v8::HandleScope scope(CcTest::isolate());
3677 v8::Local<String> local =
3678 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3679 CHECK_EQ(local->Length(), 3);
3683 class WeakCallCounter {
3685 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3686 int id() { return id_; }
3687 void increment() { number_of_weak_calls_++; }
3688 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3691 int number_of_weak_calls_;
3695 template<typename T>
3696 struct WeakCallCounterAndPersistent {
3697 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3698 : counter(counter) {}
3699 WeakCallCounter* counter;
3700 v8::Persistent<T> handle;
3704 template <typename T>
3705 static void WeakPointerCallback(
3706 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3707 CHECK_EQ(1234, data.GetParameter()->counter->id());
3708 data.GetParameter()->counter->increment();
3709 data.GetParameter()->handle.Reset();
3713 template<typename T>
3714 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3715 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3719 THREADED_TEST(ApiObjectGroups) {
3721 v8::Isolate* iso = env->GetIsolate();
3722 HandleScope scope(iso);
3724 WeakCallCounter counter(1234);
3726 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3727 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3728 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3729 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3730 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3731 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3734 HandleScope scope(iso);
3735 g1s1.handle.Reset(iso, Object::New(iso));
3736 g1s2.handle.Reset(iso, Object::New(iso));
3737 g1c1.handle.Reset(iso, Object::New(iso));
3738 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3739 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3740 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3742 g2s1.handle.Reset(iso, Object::New(iso));
3743 g2s2.handle.Reset(iso, Object::New(iso));
3744 g2c1.handle.Reset(iso, Object::New(iso));
3745 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3746 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3747 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3750 WeakCallCounterAndPersistent<Value> root(&counter);
3751 root.handle.Reset(iso, g1s1.handle); // make a root.
3753 // Connect group 1 and 2, make a cycle.
3755 HandleScope scope(iso);
3756 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3757 Set(0, Local<Value>::New(iso, g2s2.handle)));
3758 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3759 Set(0, Local<Value>::New(iso, g1s1.handle)));
3763 UniqueId id1 = MakeUniqueId(g1s1.handle);
3764 UniqueId id2 = MakeUniqueId(g2s2.handle);
3765 iso->SetObjectGroupId(g1s1.handle, id1);
3766 iso->SetObjectGroupId(g1s2.handle, id1);
3767 iso->SetReferenceFromGroup(id1, g1c1.handle);
3768 iso->SetObjectGroupId(g2s1.handle, id2);
3769 iso->SetObjectGroupId(g2s2.handle, id2);
3770 iso->SetReferenceFromGroup(id2, g2c1.handle);
3772 // Do a single full GC, ensure incremental marking is stopped.
3773 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3775 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3777 // All object should be alive.
3778 CHECK_EQ(0, counter.NumberOfWeakCalls());
3781 root.handle.SetWeak(&root, &WeakPointerCallback);
3782 // But make children strong roots---all the objects (except for children)
3783 // should be collectable now.
3784 g1c1.handle.ClearWeak();
3785 g2c1.handle.ClearWeak();
3787 // Groups are deleted, rebuild groups.
3789 UniqueId id1 = MakeUniqueId(g1s1.handle);
3790 UniqueId id2 = MakeUniqueId(g2s2.handle);
3791 iso->SetObjectGroupId(g1s1.handle, id1);
3792 iso->SetObjectGroupId(g1s2.handle, id1);
3793 iso->SetReferenceFromGroup(id1, g1c1.handle);
3794 iso->SetObjectGroupId(g2s1.handle, id2);
3795 iso->SetObjectGroupId(g2s2.handle, id2);
3796 iso->SetReferenceFromGroup(id2, g2c1.handle);
3799 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3801 // All objects should be gone. 5 global handles in total.
3802 CHECK_EQ(5, counter.NumberOfWeakCalls());
3804 // And now make children weak again and collect them.
3805 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3806 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3808 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3809 CHECK_EQ(7, counter.NumberOfWeakCalls());
3813 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3815 v8::Isolate* iso = env->GetIsolate();
3816 HandleScope scope(iso);
3818 WeakCallCounter counter(1234);
3820 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3821 WeakCallCounterAndPersistent<String> g1s2(&counter);
3822 WeakCallCounterAndPersistent<String> g1c1(&counter);
3823 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3824 WeakCallCounterAndPersistent<String> g2s2(&counter);
3825 WeakCallCounterAndPersistent<String> g2c1(&counter);
3828 HandleScope scope(iso);
3829 g1s1.handle.Reset(iso, Object::New(iso));
3830 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3831 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3832 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3833 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3834 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3836 g2s1.handle.Reset(iso, Object::New(iso));
3837 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3838 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3839 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3840 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3841 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3844 WeakCallCounterAndPersistent<Value> root(&counter);
3845 root.handle.Reset(iso, g1s1.handle); // make a root.
3847 // Connect group 1 and 2, make a cycle.
3849 HandleScope scope(iso);
3850 CHECK(Local<Object>::New(iso, g1s1.handle)
3851 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3852 CHECK(Local<Object>::New(iso, g2s1.handle)
3853 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3857 UniqueId id1 = MakeUniqueId(g1s1.handle);
3858 UniqueId id2 = MakeUniqueId(g2s2.handle);
3859 iso->SetObjectGroupId(g1s1.handle, id1);
3860 iso->SetObjectGroupId(g1s2.handle, id1);
3861 iso->SetReference(g1s1.handle, g1c1.handle);
3862 iso->SetObjectGroupId(g2s1.handle, id2);
3863 iso->SetObjectGroupId(g2s2.handle, id2);
3864 iso->SetReferenceFromGroup(id2, g2c1.handle);
3866 // Do a single full GC, ensure incremental marking is stopped.
3867 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3869 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3871 // All object should be alive.
3872 CHECK_EQ(0, counter.NumberOfWeakCalls());
3875 root.handle.SetWeak(&root, &WeakPointerCallback);
3876 // But make children strong roots---all the objects (except for children)
3877 // should be collectable now.
3878 g1c1.handle.ClearWeak();
3879 g2c1.handle.ClearWeak();
3881 // Groups are deleted, rebuild groups.
3883 UniqueId id1 = MakeUniqueId(g1s1.handle);
3884 UniqueId id2 = MakeUniqueId(g2s2.handle);
3885 iso->SetObjectGroupId(g1s1.handle, id1);
3886 iso->SetObjectGroupId(g1s2.handle, id1);
3887 iso->SetReference(g1s1.handle, g1c1.handle);
3888 iso->SetObjectGroupId(g2s1.handle, id2);
3889 iso->SetObjectGroupId(g2s2.handle, id2);
3890 iso->SetReferenceFromGroup(id2, g2c1.handle);
3893 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3895 // All objects should be gone. 5 global handles in total.
3896 CHECK_EQ(5, counter.NumberOfWeakCalls());
3898 // And now make children weak again and collect them.
3899 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3900 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3902 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3903 CHECK_EQ(7, counter.NumberOfWeakCalls());
3907 THREADED_TEST(ApiObjectGroupsCycle) {
3909 v8::Isolate* iso = env->GetIsolate();
3910 HandleScope scope(iso);
3912 WeakCallCounter counter(1234);
3914 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3915 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3916 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3917 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3918 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3919 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3920 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3921 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3924 HandleScope scope(iso);
3925 g1s1.handle.Reset(iso, Object::New(iso));
3926 g1s2.handle.Reset(iso, Object::New(iso));
3927 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3928 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3929 CHECK(g1s1.handle.IsWeak());
3930 CHECK(g1s2.handle.IsWeak());
3932 g2s1.handle.Reset(iso, Object::New(iso));
3933 g2s2.handle.Reset(iso, Object::New(iso));
3934 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3935 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3936 CHECK(g2s1.handle.IsWeak());
3937 CHECK(g2s2.handle.IsWeak());
3939 g3s1.handle.Reset(iso, Object::New(iso));
3940 g3s2.handle.Reset(iso, Object::New(iso));
3941 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3942 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3943 CHECK(g3s1.handle.IsWeak());
3944 CHECK(g3s2.handle.IsWeak());
3946 g4s1.handle.Reset(iso, Object::New(iso));
3947 g4s2.handle.Reset(iso, Object::New(iso));
3948 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3949 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3950 CHECK(g4s1.handle.IsWeak());
3951 CHECK(g4s2.handle.IsWeak());
3954 WeakCallCounterAndPersistent<Value> root(&counter);
3955 root.handle.Reset(iso, g1s1.handle); // make a root.
3957 // Connect groups. We're building the following cycle:
3958 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3961 UniqueId id1 = MakeUniqueId(g1s1.handle);
3962 UniqueId id2 = MakeUniqueId(g2s1.handle);
3963 UniqueId id3 = MakeUniqueId(g3s1.handle);
3964 UniqueId id4 = MakeUniqueId(g4s1.handle);
3965 iso->SetObjectGroupId(g1s1.handle, id1);
3966 iso->SetObjectGroupId(g1s2.handle, id1);
3967 iso->SetReferenceFromGroup(id1, g2s1.handle);
3968 iso->SetObjectGroupId(g2s1.handle, id2);
3969 iso->SetObjectGroupId(g2s2.handle, id2);
3970 iso->SetReferenceFromGroup(id2, g3s1.handle);
3971 iso->SetObjectGroupId(g3s1.handle, id3);
3972 iso->SetObjectGroupId(g3s2.handle, id3);
3973 iso->SetReferenceFromGroup(id3, g4s1.handle);
3974 iso->SetObjectGroupId(g4s1.handle, id4);
3975 iso->SetObjectGroupId(g4s2.handle, id4);
3976 iso->SetReferenceFromGroup(id4, g1s1.handle);
3978 // Do a single full GC
3979 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3981 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3983 // All object should be alive.
3984 CHECK_EQ(0, counter.NumberOfWeakCalls());
3987 root.handle.SetWeak(&root, &WeakPointerCallback);
3989 // Groups are deleted, rebuild groups.
3991 UniqueId id1 = MakeUniqueId(g1s1.handle);
3992 UniqueId id2 = MakeUniqueId(g2s1.handle);
3993 UniqueId id3 = MakeUniqueId(g3s1.handle);
3994 UniqueId id4 = MakeUniqueId(g4s1.handle);
3995 iso->SetObjectGroupId(g1s1.handle, id1);
3996 iso->SetObjectGroupId(g1s2.handle, id1);
3997 iso->SetReferenceFromGroup(id1, g2s1.handle);
3998 iso->SetObjectGroupId(g2s1.handle, id2);
3999 iso->SetObjectGroupId(g2s2.handle, id2);
4000 iso->SetReferenceFromGroup(id2, g3s1.handle);
4001 iso->SetObjectGroupId(g3s1.handle, id3);
4002 iso->SetObjectGroupId(g3s2.handle, id3);
4003 iso->SetReferenceFromGroup(id3, g4s1.handle);
4004 iso->SetObjectGroupId(g4s1.handle, id4);
4005 iso->SetObjectGroupId(g4s2.handle, id4);
4006 iso->SetReferenceFromGroup(id4, g1s1.handle);
4009 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4011 // All objects should be gone. 9 global handles in total.
4012 CHECK_EQ(9, counter.NumberOfWeakCalls());
4016 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4017 // on the buildbots, so was made non-threaded for the time being.
4018 TEST(ApiObjectGroupsCycleForScavenger) {
4019 i::FLAG_stress_compaction = false;
4020 i::FLAG_gc_global = false;
4022 v8::Isolate* iso = env->GetIsolate();
4023 HandleScope scope(iso);
4025 WeakCallCounter counter(1234);
4027 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4028 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4029 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4030 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4031 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4032 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4035 HandleScope scope(iso);
4036 g1s1.handle.Reset(iso, Object::New(iso));
4037 g1s2.handle.Reset(iso, Object::New(iso));
4038 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4039 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4041 g2s1.handle.Reset(iso, Object::New(iso));
4042 g2s2.handle.Reset(iso, Object::New(iso));
4043 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4044 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4046 g3s1.handle.Reset(iso, Object::New(iso));
4047 g3s2.handle.Reset(iso, Object::New(iso));
4048 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4049 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4053 WeakCallCounterAndPersistent<Value> root(&counter);
4054 root.handle.Reset(iso, g1s1.handle);
4055 root.handle.MarkPartiallyDependent();
4057 // Connect groups. We're building the following cycle:
4058 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4061 HandleScope handle_scope(iso);
4062 g1s1.handle.MarkPartiallyDependent();
4063 g1s2.handle.MarkPartiallyDependent();
4064 g2s1.handle.MarkPartiallyDependent();
4065 g2s2.handle.MarkPartiallyDependent();
4066 g3s1.handle.MarkPartiallyDependent();
4067 g3s2.handle.MarkPartiallyDependent();
4068 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4069 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4070 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4071 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4072 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4073 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4074 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4075 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4076 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4077 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4078 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4079 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4082 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4084 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4086 // All objects should be alive.
4087 CHECK_EQ(0, counter.NumberOfWeakCalls());
4090 root.handle.SetWeak(&root, &WeakPointerCallback);
4091 root.handle.MarkPartiallyDependent();
4093 // Groups are deleted, rebuild groups.
4095 HandleScope handle_scope(iso);
4096 g1s1.handle.MarkPartiallyDependent();
4097 g1s2.handle.MarkPartiallyDependent();
4098 g2s1.handle.MarkPartiallyDependent();
4099 g2s2.handle.MarkPartiallyDependent();
4100 g3s1.handle.MarkPartiallyDependent();
4101 g3s2.handle.MarkPartiallyDependent();
4102 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4103 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4104 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4105 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4106 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4107 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4108 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4109 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4110 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4111 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4112 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4113 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4116 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4118 // All objects should be gone. 7 global handles in total.
4119 CHECK_EQ(7, counter.NumberOfWeakCalls());
4123 THREADED_TEST(ScriptException) {
4125 v8::HandleScope scope(env->GetIsolate());
4126 Local<Script> script = v8_compile("throw 'panama!';");
4127 v8::TryCatch try_catch;
4128 Local<Value> result = script->Run();
4129 CHECK(result.IsEmpty());
4130 CHECK(try_catch.HasCaught());
4131 String::Utf8Value exception_value(try_catch.Exception());
4132 CHECK_EQ(*exception_value, "panama!");
4136 TEST(TryCatchCustomException) {
4138 v8::HandleScope scope(env->GetIsolate());
4139 v8::TryCatch try_catch;
4140 CompileRun("function CustomError() { this.a = 'b'; }"
4141 "(function f() { throw new CustomError(); })();");
4142 CHECK(try_catch.HasCaught());
4143 CHECK(try_catch.Exception()->ToObject()->
4144 Get(v8_str("a"))->Equals(v8_str("b")));
4148 bool message_received;
4151 static void check_message_0(v8::Handle<v8::Message> message,
4152 v8::Handle<Value> data) {
4153 CHECK_EQ(5.76, data->NumberValue());
4154 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4155 CHECK(!message->IsSharedCrossOrigin());
4156 message_received = true;
4160 THREADED_TEST(MessageHandler0) {
4161 message_received = false;
4162 v8::HandleScope scope(CcTest::isolate());
4163 CHECK(!message_received);
4164 LocalContext context;
4165 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4166 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4168 CHECK(message_received);
4169 // clear out the message listener
4170 v8::V8::RemoveMessageListeners(check_message_0);
4174 static void check_message_1(v8::Handle<v8::Message> message,
4175 v8::Handle<Value> data) {
4176 CHECK(data->IsNumber());
4177 CHECK_EQ(1337, data->Int32Value());
4178 CHECK(!message->IsSharedCrossOrigin());
4179 message_received = true;
4183 TEST(MessageHandler1) {
4184 message_received = false;
4185 v8::HandleScope scope(CcTest::isolate());
4186 CHECK(!message_received);
4187 v8::V8::AddMessageListener(check_message_1);
4188 LocalContext context;
4189 CompileRun("throw 1337;");
4190 CHECK(message_received);
4191 // clear out the message listener
4192 v8::V8::RemoveMessageListeners(check_message_1);
4196 static void check_message_2(v8::Handle<v8::Message> message,
4197 v8::Handle<Value> data) {
4198 LocalContext context;
4199 CHECK(data->IsObject());
4200 v8::Local<v8::Value> hidden_property =
4201 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4202 CHECK(v8_str("hidden value")->Equals(hidden_property));
4203 CHECK(!message->IsSharedCrossOrigin());
4204 message_received = true;
4208 TEST(MessageHandler2) {
4209 message_received = false;
4210 v8::HandleScope scope(CcTest::isolate());
4211 CHECK(!message_received);
4212 v8::V8::AddMessageListener(check_message_2);
4213 LocalContext context;
4214 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4215 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4216 v8_str("hidden value"));
4217 context->Global()->Set(v8_str("error"), error);
4218 CompileRun("throw error;");
4219 CHECK(message_received);
4220 // clear out the message listener
4221 v8::V8::RemoveMessageListeners(check_message_2);
4225 static void check_message_3(v8::Handle<v8::Message> message,
4226 v8::Handle<Value> data) {
4227 CHECK(message->IsSharedCrossOrigin());
4228 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4229 message_received = true;
4233 TEST(MessageHandler3) {
4234 message_received = false;
4235 v8::Isolate* isolate = CcTest::isolate();
4236 v8::HandleScope scope(isolate);
4237 CHECK(!message_received);
4238 v8::V8::AddMessageListener(check_message_3);
4239 LocalContext context;
4240 v8::ScriptOrigin origin =
4241 v8::ScriptOrigin(v8_str("6.75"),
4242 v8::Integer::New(isolate, 1),
4243 v8::Integer::New(isolate, 2),
4245 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4248 CHECK(message_received);
4249 // clear out the message listener
4250 v8::V8::RemoveMessageListeners(check_message_3);
4254 static void check_message_4(v8::Handle<v8::Message> message,
4255 v8::Handle<Value> data) {
4256 CHECK(!message->IsSharedCrossOrigin());
4257 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4258 message_received = true;
4262 TEST(MessageHandler4) {
4263 message_received = false;
4264 v8::Isolate* isolate = CcTest::isolate();
4265 v8::HandleScope scope(isolate);
4266 CHECK(!message_received);
4267 v8::V8::AddMessageListener(check_message_4);
4268 LocalContext context;
4269 v8::ScriptOrigin origin =
4270 v8::ScriptOrigin(v8_str("6.75"),
4271 v8::Integer::New(isolate, 1),
4272 v8::Integer::New(isolate, 2),
4273 v8::False(isolate));
4274 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4277 CHECK(message_received);
4278 // clear out the message listener
4279 v8::V8::RemoveMessageListeners(check_message_4);
4283 static void check_message_5a(v8::Handle<v8::Message> message,
4284 v8::Handle<Value> data) {
4285 CHECK(message->IsSharedCrossOrigin());
4286 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4287 message_received = true;
4291 static void check_message_5b(v8::Handle<v8::Message> message,
4292 v8::Handle<Value> data) {
4293 CHECK(!message->IsSharedCrossOrigin());
4294 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4295 message_received = true;
4299 TEST(MessageHandler5) {
4300 message_received = false;
4301 v8::Isolate* isolate = CcTest::isolate();
4302 v8::HandleScope scope(isolate);
4303 CHECK(!message_received);
4304 v8::V8::AddMessageListener(check_message_5a);
4305 LocalContext context;
4306 v8::ScriptOrigin origin =
4307 v8::ScriptOrigin(v8_str("6.75"),
4308 v8::Integer::New(isolate, 1),
4309 v8::Integer::New(isolate, 2),
4311 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4314 CHECK(message_received);
4315 // clear out the message listener
4316 v8::V8::RemoveMessageListeners(check_message_5a);
4318 message_received = false;
4319 v8::V8::AddMessageListener(check_message_5b);
4321 v8::ScriptOrigin(v8_str("6.75"),
4322 v8::Integer::New(isolate, 1),
4323 v8::Integer::New(isolate, 2),
4324 v8::False(isolate));
4325 script = Script::Compile(v8_str("throw 'error'"),
4328 CHECK(message_received);
4329 // clear out the message listener
4330 v8::V8::RemoveMessageListeners(check_message_5b);
4334 THREADED_TEST(GetSetProperty) {
4335 LocalContext context;
4336 v8::Isolate* isolate = context->GetIsolate();
4337 v8::HandleScope scope(isolate);
4338 context->Global()->Set(v8_str("foo"), v8_num(14));
4339 context->Global()->Set(v8_str("12"), v8_num(92));
4340 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4341 context->Global()->Set(v8_num(13), v8_num(56));
4342 Local<Value> foo = CompileRun("this.foo");
4343 CHECK_EQ(14, foo->Int32Value());
4344 Local<Value> twelve = CompileRun("this[12]");
4345 CHECK_EQ(92, twelve->Int32Value());
4346 Local<Value> sixteen = CompileRun("this[16]");
4347 CHECK_EQ(32, sixteen->Int32Value());
4348 Local<Value> thirteen = CompileRun("this[13]");
4349 CHECK_EQ(56, thirteen->Int32Value());
4351 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4352 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4353 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4355 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4356 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4357 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4359 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4360 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4361 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4365 THREADED_TEST(PropertyAttributes) {
4366 LocalContext context;
4367 v8::HandleScope scope(context->GetIsolate());
4369 Local<String> prop = v8_str("none");
4370 context->Global()->Set(prop, v8_num(7));
4371 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4373 prop = v8_str("read_only");
4374 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4375 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4376 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4377 CompileRun("read_only = 9");
4378 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4379 context->Global()->Set(prop, v8_num(10));
4380 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4382 prop = v8_str("dont_delete");
4383 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4384 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4385 CompileRun("delete dont_delete");
4386 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4387 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4389 prop = v8_str("dont_enum");
4390 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4391 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4393 prop = v8_str("absent");
4394 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4395 Local<Value> fake_prop = v8_num(1);
4396 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4399 Local<Value> exception =
4400 CompileRun("({ toString: function() { throw 'exception';} })");
4401 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4402 CHECK(try_catch.HasCaught());
4403 String::Utf8Value exception_value(try_catch.Exception());
4404 CHECK_EQ("exception", *exception_value);
4409 THREADED_TEST(Array) {
4410 LocalContext context;
4411 v8::HandleScope scope(context->GetIsolate());
4412 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4413 CHECK_EQ(0, array->Length());
4414 CHECK(array->Get(0)->IsUndefined());
4415 CHECK(!array->Has(0));
4416 CHECK(array->Get(100)->IsUndefined());
4417 CHECK(!array->Has(100));
4418 array->Set(2, v8_num(7));
4419 CHECK_EQ(3, array->Length());
4420 CHECK(!array->Has(0));
4421 CHECK(!array->Has(1));
4422 CHECK(array->Has(2));
4423 CHECK_EQ(7, array->Get(2)->Int32Value());
4424 Local<Value> obj = CompileRun("[1, 2, 3]");
4425 Local<v8::Array> arr = obj.As<v8::Array>();
4426 CHECK_EQ(3, arr->Length());
4427 CHECK_EQ(1, arr->Get(0)->Int32Value());
4428 CHECK_EQ(2, arr->Get(1)->Int32Value());
4429 CHECK_EQ(3, arr->Get(2)->Int32Value());
4430 array = v8::Array::New(context->GetIsolate(), 27);
4431 CHECK_EQ(27, array->Length());
4432 array = v8::Array::New(context->GetIsolate(), -27);
4433 CHECK_EQ(0, array->Length());
4437 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4438 v8::EscapableHandleScope scope(args.GetIsolate());
4439 ApiTestFuzzer::Fuzz();
4440 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4441 for (int i = 0; i < args.Length(); i++)
4442 result->Set(i, args[i]);
4443 args.GetReturnValue().Set(scope.Escape(result));
4447 THREADED_TEST(Vector) {
4448 v8::Isolate* isolate = CcTest::isolate();
4449 v8::HandleScope scope(isolate);
4450 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4451 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4452 LocalContext context(0, global);
4454 const char* fun = "f()";
4455 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4456 CHECK_EQ(0, a0->Length());
4458 const char* fun2 = "f(11)";
4459 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4460 CHECK_EQ(1, a1->Length());
4461 CHECK_EQ(11, a1->Get(0)->Int32Value());
4463 const char* fun3 = "f(12, 13)";
4464 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4465 CHECK_EQ(2, a2->Length());
4466 CHECK_EQ(12, a2->Get(0)->Int32Value());
4467 CHECK_EQ(13, a2->Get(1)->Int32Value());
4469 const char* fun4 = "f(14, 15, 16)";
4470 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4471 CHECK_EQ(3, a3->Length());
4472 CHECK_EQ(14, a3->Get(0)->Int32Value());
4473 CHECK_EQ(15, a3->Get(1)->Int32Value());
4474 CHECK_EQ(16, a3->Get(2)->Int32Value());
4476 const char* fun5 = "f(17, 18, 19, 20)";
4477 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4478 CHECK_EQ(4, a4->Length());
4479 CHECK_EQ(17, a4->Get(0)->Int32Value());
4480 CHECK_EQ(18, a4->Get(1)->Int32Value());
4481 CHECK_EQ(19, a4->Get(2)->Int32Value());
4482 CHECK_EQ(20, a4->Get(3)->Int32Value());
4486 THREADED_TEST(FunctionCall) {
4487 LocalContext context;
4488 v8::Isolate* isolate = context->GetIsolate();
4489 v8::HandleScope scope(isolate);
4493 " for (var i = 0; i < arguments.length; i++) {"
4494 " result.push(arguments[i]);"
4498 "function ReturnThisSloppy() {"
4501 "function ReturnThisStrict() {"
4505 Local<Function> Foo =
4506 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4507 Local<Function> ReturnThisSloppy =
4508 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4509 Local<Function> ReturnThisStrict =
4510 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4512 v8::Handle<Value>* args0 = NULL;
4513 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4514 CHECK_EQ(0, a0->Length());
4516 v8::Handle<Value> args1[] = { v8_num(1.1) };
4517 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4518 CHECK_EQ(1, a1->Length());
4519 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4521 v8::Handle<Value> args2[] = { v8_num(2.2),
4523 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4524 CHECK_EQ(2, a2->Length());
4525 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4526 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4528 v8::Handle<Value> args3[] = { v8_num(4.4),
4531 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4532 CHECK_EQ(3, a3->Length());
4533 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4534 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4535 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4537 v8::Handle<Value> args4[] = { v8_num(7.7),
4541 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4542 CHECK_EQ(4, a4->Length());
4543 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4544 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4545 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4546 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4548 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4549 CHECK(r1->StrictEquals(context->Global()));
4550 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4551 CHECK(r2->StrictEquals(context->Global()));
4552 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4553 CHECK(r3->IsNumberObject());
4554 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4555 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4556 CHECK(r4->IsStringObject());
4557 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4558 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4559 CHECK(r5->IsBooleanObject());
4560 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4562 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4563 CHECK(r6->IsUndefined());
4564 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4565 CHECK(r7->IsNull());
4566 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4567 CHECK(r8->StrictEquals(v8_num(42)));
4568 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4569 CHECK(r9->StrictEquals(v8_str("hello")));
4570 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4571 CHECK(r10->StrictEquals(v8::True(isolate)));
4575 THREADED_TEST(ConstructCall) {
4576 LocalContext context;
4577 v8::Isolate* isolate = context->GetIsolate();
4578 v8::HandleScope scope(isolate);
4582 " for (var i = 0; i < arguments.length; i++) {"
4583 " result.push(arguments[i]);"
4587 Local<Function> Foo =
4588 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4590 v8::Handle<Value>* args0 = NULL;
4591 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4592 CHECK_EQ(0, a0->Length());
4594 v8::Handle<Value> args1[] = { v8_num(1.1) };
4595 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4596 CHECK_EQ(1, a1->Length());
4597 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4599 v8::Handle<Value> args2[] = { v8_num(2.2),
4601 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4602 CHECK_EQ(2, a2->Length());
4603 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4604 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4606 v8::Handle<Value> args3[] = { v8_num(4.4),
4609 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4610 CHECK_EQ(3, a3->Length());
4611 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4612 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4613 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4615 v8::Handle<Value> args4[] = { v8_num(7.7),
4619 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4620 CHECK_EQ(4, a4->Length());
4621 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4622 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4623 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4624 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4628 static void CheckUncle(v8::TryCatch* try_catch) {
4629 CHECK(try_catch->HasCaught());
4630 String::Utf8Value str_value(try_catch->Exception());
4631 CHECK_EQ(*str_value, "uncle?");
4636 THREADED_TEST(ConversionNumber) {
4638 v8::HandleScope scope(env->GetIsolate());
4639 // Very large number.
4640 CompileRun("var obj = Math.pow(2,32) * 1237;");
4641 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4642 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4643 CHECK_EQ(0, obj->ToInt32()->Value());
4644 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4646 CompileRun("var obj = -1234567890123;");
4647 obj = env->Global()->Get(v8_str("obj"));
4648 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4649 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4650 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4651 // Small positive integer.
4652 CompileRun("var obj = 42;");
4653 obj = env->Global()->Get(v8_str("obj"));
4654 CHECK_EQ(42.0, obj->ToNumber()->Value());
4655 CHECK_EQ(42, obj->ToInt32()->Value());
4656 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4657 // Negative integer.
4658 CompileRun("var obj = -37;");
4659 obj = env->Global()->Get(v8_str("obj"));
4660 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4661 CHECK_EQ(-37, obj->ToInt32()->Value());
4662 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4663 // Positive non-int32 integer.
4664 CompileRun("var obj = 0x81234567;");
4665 obj = env->Global()->Get(v8_str("obj"));
4666 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4667 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4668 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4670 CompileRun("var obj = 42.3;");
4671 obj = env->Global()->Get(v8_str("obj"));
4672 CHECK_EQ(42.3, obj->ToNumber()->Value());
4673 CHECK_EQ(42, obj->ToInt32()->Value());
4674 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4675 // Large negative fraction.
4676 CompileRun("var obj = -5726623061.75;");
4677 obj = env->Global()->Get(v8_str("obj"));
4678 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4679 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4680 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4684 THREADED_TEST(isNumberType) {
4686 v8::HandleScope scope(env->GetIsolate());
4687 // Very large number.
4688 CompileRun("var obj = Math.pow(2,32) * 1237;");
4689 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4690 CHECK(!obj->IsInt32());
4691 CHECK(!obj->IsUint32());
4692 // Large negative number.
4693 CompileRun("var obj = -1234567890123;");
4694 obj = env->Global()->Get(v8_str("obj"));
4695 CHECK(!obj->IsInt32());
4696 CHECK(!obj->IsUint32());
4697 // Small positive integer.
4698 CompileRun("var obj = 42;");
4699 obj = env->Global()->Get(v8_str("obj"));
4700 CHECK(obj->IsInt32());
4701 CHECK(obj->IsUint32());
4702 // Negative integer.
4703 CompileRun("var obj = -37;");
4704 obj = env->Global()->Get(v8_str("obj"));
4705 CHECK(obj->IsInt32());
4706 CHECK(!obj->IsUint32());
4707 // Positive non-int32 integer.
4708 CompileRun("var obj = 0x81234567;");
4709 obj = env->Global()->Get(v8_str("obj"));
4710 CHECK(!obj->IsInt32());
4711 CHECK(obj->IsUint32());
4713 CompileRun("var obj = 42.3;");
4714 obj = env->Global()->Get(v8_str("obj"));
4715 CHECK(!obj->IsInt32());
4716 CHECK(!obj->IsUint32());
4717 // Large negative fraction.
4718 CompileRun("var obj = -5726623061.75;");
4719 obj = env->Global()->Get(v8_str("obj"));
4720 CHECK(!obj->IsInt32());
4721 CHECK(!obj->IsUint32());
4723 CompileRun("var obj = 0.0;");
4724 obj = env->Global()->Get(v8_str("obj"));
4725 CHECK(obj->IsInt32());
4726 CHECK(obj->IsUint32());
4728 CompileRun("var obj = -0.0;");
4729 obj = env->Global()->Get(v8_str("obj"));
4730 CHECK(!obj->IsInt32());
4731 CHECK(!obj->IsUint32());
4735 THREADED_TEST(ConversionException) {
4737 v8::Isolate* isolate = env->GetIsolate();
4738 v8::HandleScope scope(isolate);
4740 "function TestClass() { };"
4741 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4742 "var obj = new TestClass();");
4743 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4745 v8::TryCatch try_catch;
4747 Local<Value> to_string_result = obj->ToString();
4748 CHECK(to_string_result.IsEmpty());
4749 CheckUncle(&try_catch);
4751 Local<Value> to_number_result = obj->ToNumber();
4752 CHECK(to_number_result.IsEmpty());
4753 CheckUncle(&try_catch);
4755 Local<Value> to_integer_result = obj->ToInteger();
4756 CHECK(to_integer_result.IsEmpty());
4757 CheckUncle(&try_catch);
4759 Local<Value> to_uint32_result = obj->ToUint32();
4760 CHECK(to_uint32_result.IsEmpty());
4761 CheckUncle(&try_catch);
4763 Local<Value> to_int32_result = obj->ToInt32();
4764 CHECK(to_int32_result.IsEmpty());
4765 CheckUncle(&try_catch);
4767 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4768 CHECK(to_object_result.IsEmpty());
4769 CHECK(try_catch.HasCaught());
4772 int32_t int32_value = obj->Int32Value();
4773 CHECK_EQ(0, int32_value);
4774 CheckUncle(&try_catch);
4776 uint32_t uint32_value = obj->Uint32Value();
4777 CHECK_EQ(0, uint32_value);
4778 CheckUncle(&try_catch);
4780 double number_value = obj->NumberValue();
4781 CHECK_NE(0, std::isnan(number_value));
4782 CheckUncle(&try_catch);
4784 int64_t integer_value = obj->IntegerValue();
4785 CHECK_EQ(0.0, static_cast<double>(integer_value));
4786 CheckUncle(&try_catch);
4790 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4791 ApiTestFuzzer::Fuzz();
4792 args.GetIsolate()->ThrowException(v8_str("konto"));
4796 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4797 if (args.Length() < 1) {
4798 args.GetReturnValue().Set(false);
4801 v8::HandleScope scope(args.GetIsolate());
4802 v8::TryCatch try_catch;
4803 Local<Value> result = CompileRun(args[0]->ToString());
4804 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4805 args.GetReturnValue().Set(try_catch.HasCaught());
4809 THREADED_TEST(APICatch) {
4810 v8::Isolate* isolate = CcTest::isolate();
4811 v8::HandleScope scope(isolate);
4812 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4813 templ->Set(v8_str("ThrowFromC"),
4814 v8::FunctionTemplate::New(isolate, ThrowFromC));
4815 LocalContext context(0, templ);
4817 "var thrown = false;"
4823 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4824 CHECK(thrown->BooleanValue());
4828 THREADED_TEST(APIThrowTryCatch) {
4829 v8::Isolate* isolate = CcTest::isolate();
4830 v8::HandleScope scope(isolate);
4831 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4832 templ->Set(v8_str("ThrowFromC"),
4833 v8::FunctionTemplate::New(isolate, ThrowFromC));
4834 LocalContext context(0, templ);
4835 v8::TryCatch try_catch;
4836 CompileRun("ThrowFromC();");
4837 CHECK(try_catch.HasCaught());
4841 // Test that a try-finally block doesn't shadow a try-catch block
4842 // when setting up an external handler.
4844 // BUG(271): Some of the exception propagation does not work on the
4845 // ARM simulator because the simulator separates the C++ stack and the
4846 // JS stack. This test therefore fails on the simulator. The test is
4847 // not threaded to allow the threading tests to run on the simulator.
4848 TEST(TryCatchInTryFinally) {
4849 v8::Isolate* isolate = CcTest::isolate();
4850 v8::HandleScope scope(isolate);
4851 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4852 templ->Set(v8_str("CCatcher"),
4853 v8::FunctionTemplate::New(isolate, CCatcher));
4854 LocalContext context(0, templ);
4855 Local<Value> result = CompileRun("try {"
4857 " CCatcher('throw 7;');"
4862 CHECK(result->IsTrue());
4866 static void check_reference_error_message(
4867 v8::Handle<v8::Message> message,
4868 v8::Handle<v8::Value> data) {
4869 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4870 CHECK(message->Get()->Equals(v8_str(reference_error)));
4874 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4875 ApiTestFuzzer::Fuzz();
4880 // Test that overwritten methods are not invoked on uncaught exception
4881 // formatting. However, they are invoked when performing normal error
4882 // string conversions.
4883 TEST(APIThrowMessageOverwrittenToString) {
4884 v8::Isolate* isolate = CcTest::isolate();
4885 v8::HandleScope scope(isolate);
4886 v8::V8::AddMessageListener(check_reference_error_message);
4887 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4888 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4889 LocalContext context(NULL, templ);
4890 CompileRun("asdf;");
4891 CompileRun("var limit = {};"
4892 "limit.valueOf = fail;"
4893 "Error.stackTraceLimit = limit;");
4895 CompileRun("Array.prototype.pop = fail;");
4896 CompileRun("Object.prototype.hasOwnProperty = fail;");
4897 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4898 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4899 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4900 CompileRun("ReferenceError.prototype.toString ="
4901 " function() { return 'Whoops' }");
4902 CompileRun("asdf;");
4903 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4904 CompileRun("asdf;");
4905 CompileRun("ReferenceError.prototype.constructor = void 0;");
4906 CompileRun("asdf;");
4907 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4908 CompileRun("asdf;");
4909 CompileRun("ReferenceError.prototype = new Object();");
4910 CompileRun("asdf;");
4911 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4912 CHECK(string->Equals(v8_str("Whoops")));
4913 CompileRun("ReferenceError.prototype.constructor = new Object();"
4914 "ReferenceError.prototype.constructor.name = 1;"
4915 "Number.prototype.toString = function() { return 'Whoops'; };"
4916 "ReferenceError.prototype.toString = Object.prototype.toString;");
4917 CompileRun("asdf;");
4918 v8::V8::RemoveMessageListeners(check_reference_error_message);
4922 static void check_custom_error_tostring(
4923 v8::Handle<v8::Message> message,
4924 v8::Handle<v8::Value> data) {
4925 const char* uncaught_error = "Uncaught MyError toString";
4926 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4930 TEST(CustomErrorToString) {
4931 LocalContext context;
4932 v8::HandleScope scope(context->GetIsolate());
4933 v8::V8::AddMessageListener(check_custom_error_tostring);
4935 "function MyError(name, message) { "
4936 " this.name = name; "
4937 " this.message = message; "
4939 "MyError.prototype = Object.create(Error.prototype); "
4940 "MyError.prototype.toString = function() { "
4941 " return 'MyError toString'; "
4943 "throw new MyError('my name', 'my message'); ");
4944 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4948 static void check_custom_error_message(
4949 v8::Handle<v8::Message> message,
4950 v8::Handle<v8::Value> data) {
4951 const char* uncaught_error = "Uncaught MyError: my message";
4952 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4953 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4957 TEST(CustomErrorMessage) {
4958 LocalContext context;
4959 v8::HandleScope scope(context->GetIsolate());
4960 v8::V8::AddMessageListener(check_custom_error_message);
4964 "function MyError(msg) { "
4965 " this.name = 'MyError'; "
4966 " this.message = msg; "
4968 "MyError.prototype = new Error(); "
4969 "throw new MyError('my message'); ");
4973 "function MyError(msg) { "
4974 " this.name = 'MyError'; "
4975 " this.message = msg; "
4977 "inherits = function(childCtor, parentCtor) { "
4978 " function tempCtor() {}; "
4979 " tempCtor.prototype = parentCtor.prototype; "
4980 " childCtor.superClass_ = parentCtor.prototype; "
4981 " childCtor.prototype = new tempCtor(); "
4982 " childCtor.prototype.constructor = childCtor; "
4984 "inherits(MyError, Error); "
4985 "throw new MyError('my message'); ");
4989 "function MyError(msg) { "
4990 " this.name = 'MyError'; "
4991 " this.message = msg; "
4993 "MyError.prototype = Object.create(Error.prototype); "
4994 "throw new MyError('my message'); ");
4996 v8::V8::RemoveMessageListeners(check_custom_error_message);
5000 static void receive_message(v8::Handle<v8::Message> message,
5001 v8::Handle<v8::Value> data) {
5003 message_received = true;
5007 TEST(APIThrowMessage) {
5008 message_received = false;
5009 v8::Isolate* isolate = CcTest::isolate();
5010 v8::HandleScope scope(isolate);
5011 v8::V8::AddMessageListener(receive_message);
5012 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5013 templ->Set(v8_str("ThrowFromC"),
5014 v8::FunctionTemplate::New(isolate, ThrowFromC));
5015 LocalContext context(0, templ);
5016 CompileRun("ThrowFromC();");
5017 CHECK(message_received);
5018 v8::V8::RemoveMessageListeners(receive_message);
5022 TEST(APIThrowMessageAndVerboseTryCatch) {
5023 message_received = false;
5024 v8::Isolate* isolate = CcTest::isolate();
5025 v8::HandleScope scope(isolate);
5026 v8::V8::AddMessageListener(receive_message);
5027 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5028 templ->Set(v8_str("ThrowFromC"),
5029 v8::FunctionTemplate::New(isolate, ThrowFromC));
5030 LocalContext context(0, templ);
5031 v8::TryCatch try_catch;
5032 try_catch.SetVerbose(true);
5033 Local<Value> result = CompileRun("ThrowFromC();");
5034 CHECK(try_catch.HasCaught());
5035 CHECK(result.IsEmpty());
5036 CHECK(message_received);
5037 v8::V8::RemoveMessageListeners(receive_message);
5041 TEST(APIStackOverflowAndVerboseTryCatch) {
5042 message_received = false;
5043 LocalContext context;
5044 v8::HandleScope scope(context->GetIsolate());
5045 v8::V8::AddMessageListener(receive_message);
5046 v8::TryCatch try_catch;
5047 try_catch.SetVerbose(true);
5048 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5049 CHECK(try_catch.HasCaught());
5050 CHECK(result.IsEmpty());
5051 CHECK(message_received);
5052 v8::V8::RemoveMessageListeners(receive_message);
5056 THREADED_TEST(ExternalScriptException) {
5057 v8::Isolate* isolate = CcTest::isolate();
5058 v8::HandleScope scope(isolate);
5059 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5060 templ->Set(v8_str("ThrowFromC"),
5061 v8::FunctionTemplate::New(isolate, ThrowFromC));
5062 LocalContext context(0, templ);
5064 v8::TryCatch try_catch;
5065 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5066 CHECK(result.IsEmpty());
5067 CHECK(try_catch.HasCaught());
5068 String::Utf8Value exception_value(try_catch.Exception());
5069 CHECK_EQ("konto", *exception_value);
5074 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5075 ApiTestFuzzer::Fuzz();
5076 CHECK_EQ(4, args.Length());
5077 int count = args[0]->Int32Value();
5078 int cInterval = args[2]->Int32Value();
5080 args.GetIsolate()->ThrowException(v8_str("FromC"));
5083 Local<v8::Object> global =
5084 args.GetIsolate()->GetCurrentContext()->Global();
5085 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5086 v8::Handle<Value> argv[] = { v8_num(count - 1),
5090 if (count % cInterval == 0) {
5091 v8::TryCatch try_catch;
5092 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5093 int expected = args[3]->Int32Value();
5094 if (try_catch.HasCaught()) {
5095 CHECK_EQ(expected, count);
5096 CHECK(result.IsEmpty());
5097 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5099 CHECK_NE(expected, count);
5101 args.GetReturnValue().Set(result);
5104 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5111 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5112 ApiTestFuzzer::Fuzz();
5113 CHECK_EQ(3, args.Length());
5114 bool equality = args[0]->BooleanValue();
5115 int count = args[1]->Int32Value();
5116 int expected = args[2]->Int32Value();
5118 CHECK_EQ(count, expected);
5120 CHECK_NE(count, expected);
5125 THREADED_TEST(EvalInTryFinally) {
5126 LocalContext context;
5127 v8::HandleScope scope(context->GetIsolate());
5128 v8::TryCatch try_catch;
5129 CompileRun("(function() {"
5131 " eval('asldkf (*&^&*^');"
5136 CHECK(!try_catch.HasCaught());
5140 // This test works by making a stack of alternating JavaScript and C
5141 // activations. These activations set up exception handlers with regular
5142 // intervals, one interval for C activations and another for JavaScript
5143 // activations. When enough activations have been created an exception is
5144 // thrown and we check that the right activation catches the exception and that
5145 // no other activations do. The right activation is always the topmost one with
5146 // a handler, regardless of whether it is in JavaScript or C.
5148 // The notation used to describe a test case looks like this:
5150 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5152 // Each entry is an activation, either JS or C. The index is the count at that
5153 // level. Stars identify activations with exception handlers, the @ identifies
5154 // the exception handler that should catch the exception.
5156 // BUG(271): Some of the exception propagation does not work on the
5157 // ARM simulator because the simulator separates the C++ stack and the
5158 // JS stack. This test therefore fails on the simulator. The test is
5159 // not threaded to allow the threading tests to run on the simulator.
5160 TEST(ExceptionOrder) {
5161 v8::Isolate* isolate = CcTest::isolate();
5162 v8::HandleScope scope(isolate);
5163 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5164 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5165 templ->Set(v8_str("CThrowCountDown"),
5166 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5167 LocalContext context(0, templ);
5169 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5170 " if (count == 0) throw 'FromJS';"
5171 " if (count % jsInterval == 0) {"
5173 " var value = CThrowCountDown(count - 1,"
5177 " check(false, count, expected);"
5180 " check(true, count, expected);"
5183 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5186 Local<Function> fun =
5187 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5190 // count jsInterval cInterval expected
5192 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5193 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5194 fun->Call(fun, argc, a0);
5196 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5197 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5198 fun->Call(fun, argc, a1);
5200 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5201 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5202 fun->Call(fun, argc, a2);
5204 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5205 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5206 fun->Call(fun, argc, a3);
5208 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5209 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5210 fun->Call(fun, argc, a4);
5212 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5213 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5214 fun->Call(fun, argc, a5);
5218 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5219 ApiTestFuzzer::Fuzz();
5220 CHECK_EQ(1, args.Length());
5221 args.GetIsolate()->ThrowException(args[0]);
5225 THREADED_TEST(ThrowValues) {
5226 v8::Isolate* isolate = CcTest::isolate();
5227 v8::HandleScope scope(isolate);
5228 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5229 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5230 LocalContext context(0, templ);
5231 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5232 "function Run(obj) {"
5238 " return 'no exception';"
5240 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5241 CHECK_EQ(5, result->Length());
5242 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5243 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5244 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5245 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5246 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5247 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5248 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5252 THREADED_TEST(CatchZero) {
5253 LocalContext context;
5254 v8::HandleScope scope(context->GetIsolate());
5255 v8::TryCatch try_catch;
5256 CHECK(!try_catch.HasCaught());
5257 CompileRun("throw 10");
5258 CHECK(try_catch.HasCaught());
5259 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5261 CHECK(!try_catch.HasCaught());
5262 CompileRun("throw 0");
5263 CHECK(try_catch.HasCaught());
5264 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5268 THREADED_TEST(CatchExceptionFromWith) {
5269 LocalContext context;
5270 v8::HandleScope scope(context->GetIsolate());
5271 v8::TryCatch try_catch;
5272 CHECK(!try_catch.HasCaught());
5273 CompileRun("var o = {}; with (o) { throw 42; }");
5274 CHECK(try_catch.HasCaught());
5278 THREADED_TEST(TryCatchAndFinallyHidingException) {
5279 LocalContext context;
5280 v8::HandleScope scope(context->GetIsolate());
5281 v8::TryCatch try_catch;
5282 CHECK(!try_catch.HasCaught());
5283 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5284 CompileRun("f({toString: function() { throw 42; }});");
5285 CHECK(!try_catch.HasCaught());
5289 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5290 v8::TryCatch try_catch;
5294 THREADED_TEST(TryCatchAndFinally) {
5295 LocalContext context;
5296 v8::Isolate* isolate = context->GetIsolate();
5297 v8::HandleScope scope(isolate);
5298 context->Global()->Set(
5299 v8_str("native_with_try_catch"),
5300 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5301 v8::TryCatch try_catch;
5302 CHECK(!try_catch.HasCaught());
5305 " throw new Error('a');\n"
5307 " native_with_try_catch();\n"
5309 CHECK(try_catch.HasCaught());
5313 static void TryCatchNested1Helper(int depth) {
5315 v8::TryCatch try_catch;
5316 try_catch.SetVerbose(true);
5317 TryCatchNested1Helper(depth - 1);
5318 CHECK(try_catch.HasCaught());
5319 try_catch.ReThrow();
5321 CcTest::isolate()->ThrowException(v8_str("E1"));
5326 static void TryCatchNested2Helper(int depth) {
5328 v8::TryCatch try_catch;
5329 try_catch.SetVerbose(true);
5330 TryCatchNested2Helper(depth - 1);
5331 CHECK(try_catch.HasCaught());
5332 try_catch.ReThrow();
5334 CompileRun("throw 'E2';");
5339 TEST(TryCatchNested) {
5340 v8::V8::Initialize();
5341 LocalContext context;
5342 v8::HandleScope scope(context->GetIsolate());
5345 // Test nested try-catch with a native throw in the end.
5346 v8::TryCatch try_catch;
5347 TryCatchNested1Helper(5);
5348 CHECK(try_catch.HasCaught());
5349 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5353 // Test nested try-catch with a JavaScript throw in the end.
5354 v8::TryCatch try_catch;
5355 TryCatchNested2Helper(5);
5356 CHECK(try_catch.HasCaught());
5357 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5362 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5363 CHECK(try_catch->HasCaught());
5364 Handle<Message> message = try_catch->Message();
5365 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5366 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5367 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5368 "Uncaught Error: a"));
5369 CHECK_EQ(1, message->GetLineNumber());
5370 CHECK_EQ(6, message->GetStartColumn());
5374 void TryCatchMixedNestingHelper(
5375 const v8::FunctionCallbackInfo<v8::Value>& args) {
5376 ApiTestFuzzer::Fuzz();
5377 v8::TryCatch try_catch;
5378 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5379 CHECK(try_catch.HasCaught());
5380 TryCatchMixedNestingCheck(&try_catch);
5381 try_catch.ReThrow();
5385 // This test ensures that an outer TryCatch in the following situation:
5386 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5387 // does not clobber the Message object generated for the inner TryCatch.
5388 // This exercises the ability of TryCatch.ReThrow() to restore the
5389 // inner pending Message before throwing the exception again.
5390 TEST(TryCatchMixedNesting) {
5391 v8::Isolate* isolate = CcTest::isolate();
5392 v8::HandleScope scope(isolate);
5393 v8::V8::Initialize();
5394 v8::TryCatch try_catch;
5395 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5396 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5397 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5398 LocalContext context(0, templ);
5399 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5400 TryCatchMixedNestingCheck(&try_catch);
5404 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5405 ApiTestFuzzer::Fuzz();
5406 v8::TryCatch try_catch;
5407 args.GetIsolate()->ThrowException(v8_str("boom"));
5408 CHECK(try_catch.HasCaught());
5412 TEST(TryCatchNative) {
5413 v8::Isolate* isolate = CcTest::isolate();
5414 v8::HandleScope scope(isolate);
5415 v8::V8::Initialize();
5416 v8::TryCatch try_catch;
5417 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5418 templ->Set(v8_str("TryCatchNativeHelper"),
5419 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5420 LocalContext context(0, templ);
5421 CompileRun("TryCatchNativeHelper();");
5422 CHECK(!try_catch.HasCaught());
5426 void TryCatchNativeResetHelper(
5427 const v8::FunctionCallbackInfo<v8::Value>& args) {
5428 ApiTestFuzzer::Fuzz();
5429 v8::TryCatch try_catch;
5430 args.GetIsolate()->ThrowException(v8_str("boom"));
5431 CHECK(try_catch.HasCaught());
5433 CHECK(!try_catch.HasCaught());
5437 TEST(TryCatchNativeReset) {
5438 v8::Isolate* isolate = CcTest::isolate();
5439 v8::HandleScope scope(isolate);
5440 v8::V8::Initialize();
5441 v8::TryCatch try_catch;
5442 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5443 templ->Set(v8_str("TryCatchNativeResetHelper"),
5444 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5445 LocalContext context(0, templ);
5446 CompileRun("TryCatchNativeResetHelper();");
5447 CHECK(!try_catch.HasCaught());
5451 THREADED_TEST(Equality) {
5452 LocalContext context;
5453 v8::Isolate* isolate = context->GetIsolate();
5454 v8::HandleScope scope(context->GetIsolate());
5455 // Check that equality works at all before relying on CHECK_EQ
5456 CHECK(v8_str("a")->Equals(v8_str("a")));
5457 CHECK(!v8_str("a")->Equals(v8_str("b")));
5459 CHECK_EQ(v8_str("a"), v8_str("a"));
5460 CHECK_NE(v8_str("a"), v8_str("b"));
5461 CHECK_EQ(v8_num(1), v8_num(1));
5462 CHECK_EQ(v8_num(1.00), v8_num(1));
5463 CHECK_NE(v8_num(1), v8_num(2));
5465 // Assume String is not internalized.
5466 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5467 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5468 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5469 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5470 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5471 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5472 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5473 CHECK(!not_a_number->StrictEquals(not_a_number));
5474 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5475 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5477 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5478 v8::Persistent<v8::Object> alias(isolate, obj);
5479 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5482 CHECK(v8_str("a")->SameValue(v8_str("a")));
5483 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5484 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5485 CHECK(v8_num(1)->SameValue(v8_num(1)));
5486 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5487 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5488 CHECK(not_a_number->SameValue(not_a_number));
5489 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5490 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5494 THREADED_TEST(MultiRun) {
5495 LocalContext context;
5496 v8::HandleScope scope(context->GetIsolate());
5497 Local<Script> script = v8_compile("x");
5498 for (int i = 0; i < 10; i++)
5503 static void GetXValue(Local<String> name,
5504 const v8::PropertyCallbackInfo<v8::Value>& info) {
5505 ApiTestFuzzer::Fuzz();
5506 CHECK_EQ(info.Data(), v8_str("donut"));
5507 CHECK_EQ(name, v8_str("x"));
5508 info.GetReturnValue().Set(name);
5512 THREADED_TEST(SimplePropertyRead) {
5513 LocalContext context;
5514 v8::Isolate* isolate = context->GetIsolate();
5515 v8::HandleScope scope(isolate);
5516 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5517 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5518 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5519 Local<Script> script = v8_compile("obj.x");
5520 for (int i = 0; i < 10; i++) {
5521 Local<Value> result = script->Run();
5522 CHECK_EQ(result, v8_str("x"));
5527 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5528 LocalContext context;
5529 v8::Isolate* isolate = context->GetIsolate();
5530 v8::HandleScope scope(isolate);
5531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5532 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5533 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5535 // Uses getOwnPropertyDescriptor to check the configurable status
5536 Local<Script> script_desc = v8_compile(
5537 "var prop = Object.getOwnPropertyDescriptor( "
5539 "prop.configurable;");
5540 Local<Value> result = script_desc->Run();
5541 CHECK_EQ(result->BooleanValue(), true);
5543 // Redefine get - but still configurable
5544 Local<Script> script_define = v8_compile(
5545 "var desc = { get: function(){return 42; },"
5546 " configurable: true };"
5547 "Object.defineProperty(obj, 'x', desc);"
5549 result = script_define->Run();
5550 CHECK_EQ(result, v8_num(42));
5552 // Check that the accessor is still configurable
5553 result = script_desc->Run();
5554 CHECK_EQ(result->BooleanValue(), true);
5556 // Redefine to a non-configurable
5557 script_define = v8_compile(
5558 "var desc = { get: function(){return 43; },"
5559 " configurable: false };"
5560 "Object.defineProperty(obj, 'x', desc);"
5562 result = script_define->Run();
5563 CHECK_EQ(result, v8_num(43));
5564 result = script_desc->Run();
5565 CHECK_EQ(result->BooleanValue(), false);
5567 // Make sure that it is not possible to redefine again
5568 v8::TryCatch try_catch;
5569 result = script_define->Run();
5570 CHECK(try_catch.HasCaught());
5571 String::Utf8Value exception_value(try_catch.Exception());
5572 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5576 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5577 v8::Isolate* isolate = CcTest::isolate();
5578 v8::HandleScope scope(isolate);
5579 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5580 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5581 LocalContext context;
5582 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5584 Local<Script> script_desc = v8_compile(
5586 "Object.getOwnPropertyDescriptor( "
5588 "prop.configurable;");
5589 Local<Value> result = script_desc->Run();
5590 CHECK_EQ(result->BooleanValue(), true);
5592 Local<Script> script_define = v8_compile(
5593 "var desc = {get: function(){return 42; },"
5594 " configurable: true };"
5595 "Object.defineProperty(obj, 'x', desc);"
5597 result = script_define->Run();
5598 CHECK_EQ(result, v8_num(42));
5601 result = script_desc->Run();
5602 CHECK_EQ(result->BooleanValue(), true);
5605 script_define = v8_compile(
5606 "var desc = {get: function(){return 43; },"
5607 " configurable: false };"
5608 "Object.defineProperty(obj, 'x', desc);"
5610 result = script_define->Run();
5611 CHECK_EQ(result, v8_num(43));
5612 result = script_desc->Run();
5614 CHECK_EQ(result->BooleanValue(), false);
5616 v8::TryCatch try_catch;
5617 result = script_define->Run();
5618 CHECK(try_catch.HasCaught());
5619 String::Utf8Value exception_value(try_catch.Exception());
5620 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5624 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5626 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5630 THREADED_TEST(DefineAPIAccessorOnObject) {
5631 v8::Isolate* isolate = CcTest::isolate();
5632 v8::HandleScope scope(isolate);
5633 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5634 LocalContext context;
5636 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5637 CompileRun("var obj2 = {};");
5639 CHECK(CompileRun("obj1.x")->IsUndefined());
5640 CHECK(CompileRun("obj2.x")->IsUndefined());
5642 CHECK(GetGlobalProperty(&context, "obj1")->
5643 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5645 ExpectString("obj1.x", "x");
5646 CHECK(CompileRun("obj2.x")->IsUndefined());
5648 CHECK(GetGlobalProperty(&context, "obj2")->
5649 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5651 ExpectString("obj1.x", "x");
5652 ExpectString("obj2.x", "x");
5654 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5655 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5657 CompileRun("Object.defineProperty(obj1, 'x',"
5658 "{ get: function() { return 'y'; }, configurable: true })");
5660 ExpectString("obj1.x", "y");
5661 ExpectString("obj2.x", "x");
5663 CompileRun("Object.defineProperty(obj2, 'x',"
5664 "{ get: function() { return 'y'; }, configurable: true })");
5666 ExpectString("obj1.x", "y");
5667 ExpectString("obj2.x", "y");
5669 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5670 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5672 CHECK(GetGlobalProperty(&context, "obj1")->
5673 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5674 CHECK(GetGlobalProperty(&context, "obj2")->
5675 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5677 ExpectString("obj1.x", "x");
5678 ExpectString("obj2.x", "x");
5680 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5681 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5683 // Define getters/setters, but now make them not configurable.
5684 CompileRun("Object.defineProperty(obj1, 'x',"
5685 "{ get: function() { return 'z'; }, configurable: false })");
5686 CompileRun("Object.defineProperty(obj2, 'x',"
5687 "{ get: function() { return 'z'; }, configurable: false })");
5689 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5690 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5692 ExpectString("obj1.x", "z");
5693 ExpectString("obj2.x", "z");
5695 CHECK(!GetGlobalProperty(&context, "obj1")->
5696 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5697 CHECK(!GetGlobalProperty(&context, "obj2")->
5698 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5700 ExpectString("obj1.x", "z");
5701 ExpectString("obj2.x", "z");
5705 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5706 v8::Isolate* isolate = CcTest::isolate();
5707 v8::HandleScope scope(isolate);
5708 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5709 LocalContext context;
5711 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5712 CompileRun("var obj2 = {};");
5714 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5717 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5718 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5721 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5723 ExpectString("obj1.x", "x");
5724 ExpectString("obj2.x", "x");
5726 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5727 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5729 CHECK(!GetGlobalProperty(&context, "obj1")->
5730 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5731 CHECK(!GetGlobalProperty(&context, "obj2")->
5732 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5735 v8::TryCatch try_catch;
5736 CompileRun("Object.defineProperty(obj1, 'x',"
5737 "{get: function() { return 'func'; }})");
5738 CHECK(try_catch.HasCaught());
5739 String::Utf8Value exception_value(try_catch.Exception());
5740 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5743 v8::TryCatch try_catch;
5744 CompileRun("Object.defineProperty(obj2, 'x',"
5745 "{get: function() { return 'func'; }})");
5746 CHECK(try_catch.HasCaught());
5747 String::Utf8Value exception_value(try_catch.Exception());
5748 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5753 static void Get239Value(Local<String> name,
5754 const v8::PropertyCallbackInfo<v8::Value>& info) {
5755 ApiTestFuzzer::Fuzz();
5756 CHECK_EQ(info.Data(), v8_str("donut"));
5757 CHECK_EQ(name, v8_str("239"));
5758 info.GetReturnValue().Set(name);
5762 THREADED_TEST(ElementAPIAccessor) {
5763 v8::Isolate* isolate = CcTest::isolate();
5764 v8::HandleScope scope(isolate);
5765 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5766 LocalContext context;
5768 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5769 CompileRun("var obj2 = {};");
5771 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5775 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5780 ExpectString("obj1[239]", "239");
5781 ExpectString("obj2[239]", "239");
5782 ExpectString("obj1['239']", "239");
5783 ExpectString("obj2['239']", "239");
5787 v8::Persistent<Value> xValue;
5790 static void SetXValue(Local<String> name,
5792 const v8::PropertyCallbackInfo<void>& info) {
5793 CHECK_EQ(value, v8_num(4));
5794 CHECK_EQ(info.Data(), v8_str("donut"));
5795 CHECK_EQ(name, v8_str("x"));
5796 CHECK(xValue.IsEmpty());
5797 xValue.Reset(info.GetIsolate(), value);
5801 THREADED_TEST(SimplePropertyWrite) {
5802 v8::Isolate* isolate = CcTest::isolate();
5803 v8::HandleScope scope(isolate);
5804 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5805 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5806 LocalContext context;
5807 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5808 Local<Script> script = v8_compile("obj.x = 4");
5809 for (int i = 0; i < 10; i++) {
5810 CHECK(xValue.IsEmpty());
5812 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5818 THREADED_TEST(SetterOnly) {
5819 v8::Isolate* isolate = CcTest::isolate();
5820 v8::HandleScope scope(isolate);
5821 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5822 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5823 LocalContext context;
5824 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5825 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5826 for (int i = 0; i < 10; i++) {
5827 CHECK(xValue.IsEmpty());
5829 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5835 THREADED_TEST(NoAccessors) {
5836 v8::Isolate* isolate = CcTest::isolate();
5837 v8::HandleScope scope(isolate);
5838 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5839 templ->SetAccessor(v8_str("x"),
5840 static_cast<v8::AccessorGetterCallback>(NULL),
5843 LocalContext context;
5844 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5845 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5846 for (int i = 0; i < 10; i++) {
5852 static void XPropertyGetter(Local<String> property,
5853 const v8::PropertyCallbackInfo<v8::Value>& info) {
5854 ApiTestFuzzer::Fuzz();
5855 CHECK(info.Data()->IsUndefined());
5856 info.GetReturnValue().Set(property);
5860 THREADED_TEST(NamedInterceptorPropertyRead) {
5861 v8::Isolate* isolate = CcTest::isolate();
5862 v8::HandleScope scope(isolate);
5863 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5864 templ->SetNamedPropertyHandler(XPropertyGetter);
5865 LocalContext context;
5866 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5867 Local<Script> script = v8_compile("obj.x");
5868 for (int i = 0; i < 10; i++) {
5869 Local<Value> result = script->Run();
5870 CHECK_EQ(result, v8_str("x"));
5875 THREADED_TEST(NamedInterceptorDictionaryIC) {
5876 v8::Isolate* isolate = CcTest::isolate();
5877 v8::HandleScope scope(isolate);
5878 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5879 templ->SetNamedPropertyHandler(XPropertyGetter);
5880 LocalContext context;
5881 // Create an object with a named interceptor.
5882 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5883 Local<Script> script = v8_compile("interceptor_obj.x");
5884 for (int i = 0; i < 10; i++) {
5885 Local<Value> result = script->Run();
5886 CHECK_EQ(result, v8_str("x"));
5888 // Create a slow case object and a function accessing a property in
5889 // that slow case object (with dictionary probing in generated
5890 // code). Then force object with a named interceptor into slow-case,
5891 // pass it to the function, and check that the interceptor is called
5892 // instead of accessing the local property.
5893 Local<Value> result =
5894 CompileRun("function get_x(o) { return o.x; };"
5895 "var obj = { x : 42, y : 0 };"
5897 "for (var i = 0; i < 10; i++) get_x(obj);"
5898 "interceptor_obj.x = 42;"
5899 "interceptor_obj.y = 10;"
5900 "delete interceptor_obj.y;"
5901 "get_x(interceptor_obj)");
5902 CHECK_EQ(result, v8_str("x"));
5906 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5907 v8::Isolate* isolate = CcTest::isolate();
5908 v8::HandleScope scope(isolate);
5909 v8::Local<Context> context1 = Context::New(isolate);
5912 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5913 templ->SetNamedPropertyHandler(XPropertyGetter);
5914 // Create an object with a named interceptor.
5915 v8::Local<v8::Object> object = templ->NewInstance();
5916 context1->Global()->Set(v8_str("interceptor_obj"), object);
5918 // Force the object into the slow case.
5919 CompileRun("interceptor_obj.y = 0;"
5920 "delete interceptor_obj.y;");
5924 // Introduce the object into a different context.
5925 // Repeat named loads to exercise ICs.
5926 LocalContext context2;
5927 context2->Global()->Set(v8_str("interceptor_obj"), object);
5928 Local<Value> result =
5929 CompileRun("function get_x(o) { return o.x; }"
5930 "interceptor_obj.x = 42;"
5931 "for (var i=0; i != 10; i++) {"
5932 " get_x(interceptor_obj);"
5934 "get_x(interceptor_obj)");
5935 // Check that the interceptor was actually invoked.
5936 CHECK_EQ(result, v8_str("x"));
5939 // Return to the original context and force some object to the slow case
5940 // to cause the NormalizedMapCache to verify.
5942 CompileRun("var obj = { x : 0 }; delete obj.x;");
5947 static void SetXOnPrototypeGetter(
5948 Local<String> property,
5949 const v8::PropertyCallbackInfo<v8::Value>& info) {
5950 // Set x on the prototype object and do not handle the get request.
5951 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5952 proto.As<v8::Object>()->Set(v8_str("x"),
5953 v8::Integer::New(info.GetIsolate(), 23));
5957 // This is a regression test for http://crbug.com/20104. Map
5958 // transitions should not interfere with post interceptor lookup.
5959 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5960 v8::Isolate* isolate = CcTest::isolate();
5961 v8::HandleScope scope(isolate);
5962 Local<v8::FunctionTemplate> function_template =
5963 v8::FunctionTemplate::New(isolate);
5964 Local<v8::ObjectTemplate> instance_template
5965 = function_template->InstanceTemplate();
5966 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5967 LocalContext context;
5968 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5969 // Create an instance of F and introduce a map transition for x.
5970 CompileRun("var o = new F(); o.x = 23;");
5971 // Create an instance of F and invoke the getter. The result should be 23.
5972 Local<Value> result = CompileRun("o = new F(); o.x");
5973 CHECK_EQ(result->Int32Value(), 23);
5977 static void IndexedPropertyGetter(
5979 const v8::PropertyCallbackInfo<v8::Value>& info) {
5980 ApiTestFuzzer::Fuzz();
5982 info.GetReturnValue().Set(v8_num(625));
5987 static void IndexedPropertySetter(
5990 const v8::PropertyCallbackInfo<v8::Value>& info) {
5991 ApiTestFuzzer::Fuzz();
5993 info.GetReturnValue().Set(value);
5998 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5999 v8::Isolate* isolate = CcTest::isolate();
6000 v8::HandleScope scope(isolate);
6001 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6002 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6003 IndexedPropertySetter);
6004 LocalContext context;
6005 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6006 Local<Script> getter_script = v8_compile(
6007 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6008 Local<Script> setter_script = v8_compile(
6009 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6012 Local<Script> interceptor_setter_script = v8_compile(
6013 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6015 "obj.foo;"); // This setter should not run, due to the interceptor.
6016 Local<Script> interceptor_getter_script = v8_compile(
6018 Local<Value> result = getter_script->Run();
6019 CHECK_EQ(v8_num(5), result);
6020 result = setter_script->Run();
6021 CHECK_EQ(v8_num(23), result);
6022 result = interceptor_setter_script->Run();
6023 CHECK_EQ(v8_num(23), result);
6024 result = interceptor_getter_script->Run();
6025 CHECK_EQ(v8_num(625), result);
6029 static void UnboxedDoubleIndexedPropertyGetter(
6031 const v8::PropertyCallbackInfo<v8::Value>& info) {
6032 ApiTestFuzzer::Fuzz();
6034 info.GetReturnValue().Set(v8_num(index));
6039 static void UnboxedDoubleIndexedPropertySetter(
6042 const v8::PropertyCallbackInfo<v8::Value>& info) {
6043 ApiTestFuzzer::Fuzz();
6045 info.GetReturnValue().Set(v8_num(index));
6050 void UnboxedDoubleIndexedPropertyEnumerator(
6051 const v8::PropertyCallbackInfo<v8::Array>& info) {
6052 // Force the list of returned keys to be stored in a FastDoubleArray.
6053 Local<Script> indexed_property_names_script = v8_compile(
6054 "keys = new Array(); keys[125000] = 1;"
6055 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6056 "keys.length = 25; keys;");
6057 Local<Value> result = indexed_property_names_script->Run();
6058 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6062 // Make sure that the the interceptor code in the runtime properly handles
6063 // merging property name lists for double-array-backed arrays.
6064 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6065 v8::Isolate* isolate = CcTest::isolate();
6066 v8::HandleScope scope(isolate);
6067 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6068 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6069 UnboxedDoubleIndexedPropertySetter,
6072 UnboxedDoubleIndexedPropertyEnumerator);
6073 LocalContext context;
6074 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6075 // When obj is created, force it to be Stored in a FastDoubleArray.
6076 Local<Script> create_unboxed_double_script = v8_compile(
6077 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6079 "for (x in obj) {key_count++;};"
6081 Local<Value> result = create_unboxed_double_script->Run();
6082 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6083 Local<Script> key_count_check = v8_compile("key_count;");
6084 result = key_count_check->Run();
6085 CHECK_EQ(v8_num(40013), result);
6089 void SloppyArgsIndexedPropertyEnumerator(
6090 const v8::PropertyCallbackInfo<v8::Array>& info) {
6091 // Force the list of returned keys to be stored in a Arguments object.
6092 Local<Script> indexed_property_names_script = v8_compile(
6094 " return arguments;"
6096 "keys = f(0, 1, 2, 3);"
6098 Local<Object> result =
6099 Local<Object>::Cast(indexed_property_names_script->Run());
6100 // Have to populate the handle manually, as it's not Cast-able.
6101 i::Handle<i::JSObject> o =
6102 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6103 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6104 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6108 static void SloppyIndexedPropertyGetter(
6110 const v8::PropertyCallbackInfo<v8::Value>& info) {
6111 ApiTestFuzzer::Fuzz();
6113 info.GetReturnValue().Set(v8_num(index));
6118 // Make sure that the the interceptor code in the runtime properly handles
6119 // merging property name lists for non-string arguments arrays.
6120 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6121 v8::Isolate* isolate = CcTest::isolate();
6122 v8::HandleScope scope(isolate);
6123 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6124 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6128 SloppyArgsIndexedPropertyEnumerator);
6129 LocalContext context;
6130 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6131 Local<Script> create_args_script = v8_compile(
6132 "var key_count = 0;"
6133 "for (x in obj) {key_count++;} key_count;");
6134 Local<Value> result = create_args_script->Run();
6135 CHECK_EQ(v8_num(4), result);
6139 static void IdentityIndexedPropertyGetter(
6141 const v8::PropertyCallbackInfo<v8::Value>& info) {
6142 info.GetReturnValue().Set(index);
6146 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6147 v8::Isolate* isolate = CcTest::isolate();
6148 v8::HandleScope scope(isolate);
6149 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6150 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6152 LocalContext context;
6153 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6155 // Check fast object case.
6156 const char* fast_case_code =
6157 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6158 ExpectString(fast_case_code, "0");
6161 const char* slow_case_code =
6162 "obj.x = 1; delete obj.x;"
6163 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6164 ExpectString(slow_case_code, "1");
6168 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6169 v8::Isolate* isolate = CcTest::isolate();
6170 v8::HandleScope scope(isolate);
6171 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6172 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6174 LocalContext context;
6175 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6180 " for (var i = 0; i < 100; i++) {"
6182 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6188 ExpectString(code, "PASSED");
6192 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6193 v8::Isolate* isolate = CcTest::isolate();
6194 v8::HandleScope scope(isolate);
6195 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6196 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6198 LocalContext context;
6199 Local<v8::Object> obj = templ->NewInstance();
6200 obj->TurnOnAccessCheck();
6201 context->Global()->Set(v8_str("obj"), obj);
6204 "var result = 'PASSED';"
6205 "for (var i = 0; i < 100; i++) {"
6208 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6215 ExpectString(code, "PASSED");
6219 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6220 i::FLAG_allow_natives_syntax = true;
6221 v8::Isolate* isolate = CcTest::isolate();
6222 v8::HandleScope scope(isolate);
6223 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6224 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6226 LocalContext context;
6227 Local<v8::Object> obj = templ->NewInstance();
6228 context->Global()->Set(v8_str("obj"), obj);
6231 "var result = 'PASSED';"
6232 "for (var i = 0; i < 100; i++) {"
6233 " var expected = i;"
6235 " %EnableAccessChecks(obj);"
6240 " result = 'Should not have reached this!';"
6242 " } else if (v != expected) {"
6243 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6251 " if (i == 5) %DisableAccessChecks(obj);"
6254 ExpectString(code, "PASSED");
6258 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6259 v8::Isolate* isolate = CcTest::isolate();
6260 v8::HandleScope scope(isolate);
6261 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6262 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6264 LocalContext context;
6265 Local<v8::Object> obj = templ->NewInstance();
6266 context->Global()->Set(v8_str("obj"), obj);
6270 " for (var i = 0; i < 100; i++) {"
6272 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6278 ExpectString(code, "PASSED");
6282 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6283 v8::Isolate* isolate = CcTest::isolate();
6284 v8::HandleScope scope(isolate);
6285 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6286 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6288 LocalContext context;
6289 Local<v8::Object> obj = templ->NewInstance();
6290 context->Global()->Set(v8_str("obj"), obj);
6294 " for (var i = 0; i < 100; i++) {"
6295 " var expected = i;"
6299 " expected = undefined;"
6302 " /* probe minimal Smi number on 32-bit platforms */"
6303 " key = -(1 << 30);"
6304 " expected = undefined;"
6307 " /* probe minimal Smi number on 64-bit platforms */"
6309 " expected = undefined;"
6311 " var v = obj[key];"
6312 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6318 ExpectString(code, "PASSED");
6322 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6323 v8::Isolate* isolate = CcTest::isolate();
6324 v8::HandleScope scope(isolate);
6325 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6326 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6328 LocalContext context;
6329 Local<v8::Object> obj = templ->NewInstance();
6330 context->Global()->Set(v8_str("obj"), obj);
6334 " for (var i = 0; i < 100; i++) {"
6335 " var expected = i;"
6339 " expected = undefined;"
6341 " var v = obj[key];"
6342 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6348 ExpectString(code, "PASSED");
6352 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6353 v8::Isolate* isolate = CcTest::isolate();
6354 v8::HandleScope scope(isolate);
6355 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6356 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6358 LocalContext context;
6359 Local<v8::Object> obj = templ->NewInstance();
6360 context->Global()->Set(v8_str("obj"), obj);
6363 "var original = obj;"
6365 " for (var i = 0; i < 100; i++) {"
6366 " var expected = i;"
6368 " obj = {50: 'foobar'};"
6369 " expected = 'foobar';"
6372 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6373 " if (i == 50) obj = original;"
6379 ExpectString(code, "PASSED");
6383 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6384 v8::Isolate* isolate = CcTest::isolate();
6385 v8::HandleScope scope(isolate);
6386 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6387 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6389 LocalContext context;
6390 Local<v8::Object> obj = templ->NewInstance();
6391 context->Global()->Set(v8_str("obj"), obj);
6394 "var original = obj;"
6396 " for (var i = 0; i < 100; i++) {"
6397 " var expected = i;"
6400 " expected = undefined;"
6403 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6404 " if (i == 5) obj = original;"
6410 ExpectString(code, "PASSED");
6414 THREADED_TEST(IndexedInterceptorOnProto) {
6415 v8::Isolate* isolate = CcTest::isolate();
6416 v8::HandleScope scope(isolate);
6417 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6418 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6420 LocalContext context;
6421 Local<v8::Object> obj = templ->NewInstance();
6422 context->Global()->Set(v8_str("obj"), obj);
6425 "var o = {__proto__: obj};"
6427 " for (var i = 0; i < 100; i++) {"
6429 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6435 ExpectString(code, "PASSED");
6439 THREADED_TEST(MultiContexts) {
6440 v8::Isolate* isolate = CcTest::isolate();
6441 v8::HandleScope scope(isolate);
6442 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6443 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6446 Local<String> password = v8_str("Password");
6448 // Create an environment
6449 LocalContext context0(0, templ);
6450 context0->SetSecurityToken(password);
6451 v8::Handle<v8::Object> global0 = context0->Global();
6452 global0->Set(v8_str("custom"), v8_num(1234));
6453 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6455 // Create an independent environment
6456 LocalContext context1(0, templ);
6457 context1->SetSecurityToken(password);
6458 v8::Handle<v8::Object> global1 = context1->Global();
6459 global1->Set(v8_str("custom"), v8_num(1234));
6460 CHECK_NE(global0, global1);
6461 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6462 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6464 // Now create a new context with the old global
6465 LocalContext context2(0, templ, global1);
6466 context2->SetSecurityToken(password);
6467 v8::Handle<v8::Object> global2 = context2->Global();
6468 CHECK_EQ(global1, global2);
6469 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6470 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6474 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6475 // Make sure that functions created by cloning boilerplates cannot
6476 // communicate through their __proto__ field.
6478 v8::HandleScope scope(CcTest::isolate());
6481 v8::Handle<v8::Object> global0 =
6483 v8::Handle<v8::Object> object0 =
6484 global0->Get(v8_str("Object")).As<v8::Object>();
6485 v8::Handle<v8::Object> tostring0 =
6486 object0->Get(v8_str("toString")).As<v8::Object>();
6487 v8::Handle<v8::Object> proto0 =
6488 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6489 proto0->Set(v8_str("custom"), v8_num(1234));
6492 v8::Handle<v8::Object> global1 =
6494 v8::Handle<v8::Object> object1 =
6495 global1->Get(v8_str("Object")).As<v8::Object>();
6496 v8::Handle<v8::Object> tostring1 =
6497 object1->Get(v8_str("toString")).As<v8::Object>();
6498 v8::Handle<v8::Object> proto1 =
6499 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6500 CHECK(!proto1->Has(v8_str("custom")));
6504 THREADED_TEST(Regress892105) {
6505 // Make sure that object and array literals created by cloning
6506 // boilerplates cannot communicate through their __proto__
6507 // field. This is rather difficult to check, but we try to add stuff
6508 // to Object.prototype and Array.prototype and create a new
6509 // environment. This should succeed.
6511 v8::HandleScope scope(CcTest::isolate());
6513 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6514 "Array.prototype.arr = 4567;"
6518 Local<Script> script0 = v8_compile(source);
6519 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6522 Local<Script> script1 = v8_compile(source);
6523 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6527 THREADED_TEST(UndetectableObject) {
6529 v8::HandleScope scope(env->GetIsolate());
6531 Local<v8::FunctionTemplate> desc =
6532 v8::FunctionTemplate::New(env->GetIsolate());
6533 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6535 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6536 env->Global()->Set(v8_str("undetectable"), obj);
6538 ExpectString("undetectable.toString()", "[object Object]");
6539 ExpectString("typeof undetectable", "undefined");
6540 ExpectString("typeof(undetectable)", "undefined");
6541 ExpectBoolean("typeof undetectable == 'undefined'", true);
6542 ExpectBoolean("typeof undetectable == 'object'", false);
6543 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6544 ExpectBoolean("!undetectable", true);
6546 ExpectObject("true&&undetectable", obj);
6547 ExpectBoolean("false&&undetectable", false);
6548 ExpectBoolean("true||undetectable", true);
6549 ExpectObject("false||undetectable", obj);
6551 ExpectObject("undetectable&&true", obj);
6552 ExpectObject("undetectable&&false", obj);
6553 ExpectBoolean("undetectable||true", true);
6554 ExpectBoolean("undetectable||false", false);
6556 ExpectBoolean("undetectable==null", true);
6557 ExpectBoolean("null==undetectable", true);
6558 ExpectBoolean("undetectable==undefined", true);
6559 ExpectBoolean("undefined==undetectable", true);
6560 ExpectBoolean("undetectable==undetectable", true);
6563 ExpectBoolean("undetectable===null", false);
6564 ExpectBoolean("null===undetectable", false);
6565 ExpectBoolean("undetectable===undefined", false);
6566 ExpectBoolean("undefined===undetectable", false);
6567 ExpectBoolean("undetectable===undetectable", true);
6571 THREADED_TEST(VoidLiteral) {
6573 v8::Isolate* isolate = env->GetIsolate();
6574 v8::HandleScope scope(isolate);
6576 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6577 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6579 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6580 env->Global()->Set(v8_str("undetectable"), obj);
6582 ExpectBoolean("undefined == void 0", true);
6583 ExpectBoolean("undetectable == void 0", true);
6584 ExpectBoolean("null == void 0", true);
6585 ExpectBoolean("undefined === void 0", true);
6586 ExpectBoolean("undetectable === void 0", false);
6587 ExpectBoolean("null === void 0", false);
6589 ExpectBoolean("void 0 == undefined", true);
6590 ExpectBoolean("void 0 == undetectable", true);
6591 ExpectBoolean("void 0 == null", true);
6592 ExpectBoolean("void 0 === undefined", true);
6593 ExpectBoolean("void 0 === undetectable", false);
6594 ExpectBoolean("void 0 === null", false);
6596 ExpectString("(function() {"
6598 " return x === void 0;"
6600 " return e.toString();"
6603 "ReferenceError: x is not defined");
6604 ExpectString("(function() {"
6606 " return void 0 === x;"
6608 " return e.toString();"
6611 "ReferenceError: x is not defined");
6615 THREADED_TEST(ExtensibleOnUndetectable) {
6617 v8::Isolate* isolate = env->GetIsolate();
6618 v8::HandleScope scope(isolate);
6620 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6621 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6623 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6624 env->Global()->Set(v8_str("undetectable"), obj);
6626 Local<String> source = v8_str("undetectable.x = 42;"
6629 Local<Script> script = v8_compile(source);
6631 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6633 ExpectBoolean("Object.isExtensible(undetectable)", true);
6635 source = v8_str("Object.preventExtensions(undetectable);");
6636 script = v8_compile(source);
6638 ExpectBoolean("Object.isExtensible(undetectable)", false);
6640 source = v8_str("undetectable.y = 2000;");
6641 script = v8_compile(source);
6643 ExpectBoolean("undetectable.y == undefined", true);
6648 THREADED_TEST(UndetectableString) {
6650 v8::HandleScope scope(env->GetIsolate());
6652 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6653 String::kUndetectableString);
6654 env->Global()->Set(v8_str("undetectable"), obj);
6656 ExpectString("undetectable", "foo");
6657 ExpectString("typeof undetectable", "undefined");
6658 ExpectString("typeof(undetectable)", "undefined");
6659 ExpectBoolean("typeof undetectable == 'undefined'", true);
6660 ExpectBoolean("typeof undetectable == 'string'", false);
6661 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6662 ExpectBoolean("!undetectable", true);
6664 ExpectObject("true&&undetectable", obj);
6665 ExpectBoolean("false&&undetectable", false);
6666 ExpectBoolean("true||undetectable", true);
6667 ExpectObject("false||undetectable", obj);
6669 ExpectObject("undetectable&&true", obj);
6670 ExpectObject("undetectable&&false", obj);
6671 ExpectBoolean("undetectable||true", true);
6672 ExpectBoolean("undetectable||false", false);
6674 ExpectBoolean("undetectable==null", true);
6675 ExpectBoolean("null==undetectable", true);
6676 ExpectBoolean("undetectable==undefined", true);
6677 ExpectBoolean("undefined==undetectable", true);
6678 ExpectBoolean("undetectable==undetectable", true);
6681 ExpectBoolean("undetectable===null", false);
6682 ExpectBoolean("null===undetectable", false);
6683 ExpectBoolean("undetectable===undefined", false);
6684 ExpectBoolean("undefined===undetectable", false);
6685 ExpectBoolean("undetectable===undetectable", true);
6689 TEST(UndetectableOptimized) {
6690 i::FLAG_allow_natives_syntax = true;
6692 v8::HandleScope scope(env->GetIsolate());
6694 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6695 String::kUndetectableString);
6696 env->Global()->Set(v8_str("undetectable"), obj);
6697 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6700 "function testBranch() {"
6701 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6702 " if (%_IsUndetectableObject(detectable)) throw 2;"
6704 "function testBool() {"
6705 " var b1 = !%_IsUndetectableObject(undetectable);"
6706 " var b2 = %_IsUndetectableObject(detectable);"
6711 "%OptimizeFunctionOnNextCall(testBranch);"
6712 "%OptimizeFunctionOnNextCall(testBool);"
6713 "for (var i = 0; i < 10; i++) {"
6722 // The point of this test is type checking. We run it only so compilers
6723 // don't complain about an unused function.
6724 TEST(PersistentHandles) {
6726 v8::Isolate* isolate = CcTest::isolate();
6727 v8::HandleScope scope(isolate);
6728 Local<String> str = v8_str("foo");
6729 v8::Persistent<String> p_str(isolate, str);
6731 Local<Script> scr = v8_compile("");
6732 v8::Persistent<Script> p_scr(isolate, scr);
6734 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6735 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6740 static void HandleLogDelegator(
6741 const v8::FunctionCallbackInfo<v8::Value>& args) {
6742 ApiTestFuzzer::Fuzz();
6746 THREADED_TEST(GlobalObjectTemplate) {
6747 v8::Isolate* isolate = CcTest::isolate();
6748 v8::HandleScope handle_scope(isolate);
6749 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6750 global_template->Set(v8_str("JSNI_Log"),
6751 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6752 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6753 Context::Scope context_scope(context);
6754 CompileRun("JSNI_Log('LOG')");
6758 static const char* kSimpleExtensionSource =
6764 TEST(SimpleExtensions) {
6765 v8::HandleScope handle_scope(CcTest::isolate());
6766 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6767 const char* extension_names[] = { "simpletest" };
6768 v8::ExtensionConfiguration extensions(1, extension_names);
6769 v8::Handle<Context> context =
6770 Context::New(CcTest::isolate(), &extensions);
6771 Context::Scope lock(context);
6772 v8::Handle<Value> result = CompileRun("Foo()");
6773 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6777 static const char* kStackTraceFromExtensionSource =
6779 " throw new Error();"
6786 TEST(StackTraceInExtension) {
6787 v8::HandleScope handle_scope(CcTest::isolate());
6788 v8::RegisterExtension(new Extension("stacktracetest",
6789 kStackTraceFromExtensionSource));
6790 const char* extension_names[] = { "stacktracetest" };
6791 v8::ExtensionConfiguration extensions(1, extension_names);
6792 v8::Handle<Context> context =
6793 Context::New(CcTest::isolate(), &extensions);
6794 Context::Scope lock(context);
6795 CompileRun("function user() { bar(); }"
6797 "try{ user(); } catch (e) { error = e; }");
6798 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6799 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6800 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6804 TEST(NullExtensions) {
6805 v8::HandleScope handle_scope(CcTest::isolate());
6806 v8::RegisterExtension(new Extension("nulltest", NULL));
6807 const char* extension_names[] = { "nulltest" };
6808 v8::ExtensionConfiguration extensions(1, extension_names);
6809 v8::Handle<Context> context =
6810 Context::New(CcTest::isolate(), &extensions);
6811 Context::Scope lock(context);
6812 v8::Handle<Value> result = CompileRun("1+3");
6813 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6817 static const char* kEmbeddedExtensionSource =
6818 "function Ret54321(){return 54321;}~~@@$"
6819 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6820 static const int kEmbeddedExtensionSourceValidLen = 34;
6823 TEST(ExtensionMissingSourceLength) {
6824 v8::HandleScope handle_scope(CcTest::isolate());
6825 v8::RegisterExtension(new Extension("srclentest_fail",
6826 kEmbeddedExtensionSource));
6827 const char* extension_names[] = { "srclentest_fail" };
6828 v8::ExtensionConfiguration extensions(1, extension_names);
6829 v8::Handle<Context> context =
6830 Context::New(CcTest::isolate(), &extensions);
6831 CHECK_EQ(0, *context);
6835 TEST(ExtensionWithSourceLength) {
6836 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6837 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6838 v8::HandleScope handle_scope(CcTest::isolate());
6839 i::ScopedVector<char> extension_name(32);
6840 i::SNPrintF(extension_name, "ext #%d", source_len);
6841 v8::RegisterExtension(new Extension(extension_name.start(),
6842 kEmbeddedExtensionSource, 0, 0,
6844 const char* extension_names[1] = { extension_name.start() };
6845 v8::ExtensionConfiguration extensions(1, extension_names);
6846 v8::Handle<Context> context =
6847 Context::New(CcTest::isolate(), &extensions);
6848 if (source_len == kEmbeddedExtensionSourceValidLen) {
6849 Context::Scope lock(context);
6850 v8::Handle<Value> result = CompileRun("Ret54321()");
6851 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6853 // Anything but exactly the right length should fail to compile.
6854 CHECK_EQ(0, *context);
6860 static const char* kEvalExtensionSource1 =
6861 "function UseEval1() {"
6863 " return eval('x');"
6867 static const char* kEvalExtensionSource2 =
6871 " return eval('x');"
6873 " this.UseEval2 = e;"
6877 TEST(UseEvalFromExtension) {
6878 v8::HandleScope handle_scope(CcTest::isolate());
6879 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6880 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6881 const char* extension_names[] = { "evaltest1", "evaltest2" };
6882 v8::ExtensionConfiguration extensions(2, extension_names);
6883 v8::Handle<Context> context =
6884 Context::New(CcTest::isolate(), &extensions);
6885 Context::Scope lock(context);
6886 v8::Handle<Value> result = CompileRun("UseEval1()");
6887 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6888 result = CompileRun("UseEval2()");
6889 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6893 static const char* kWithExtensionSource1 =
6894 "function UseWith1() {"
6896 " with({x:87}) { return x; }"
6901 static const char* kWithExtensionSource2 =
6905 " with ({x:87}) { return x; }"
6907 " this.UseWith2 = e;"
6911 TEST(UseWithFromExtension) {
6912 v8::HandleScope handle_scope(CcTest::isolate());
6913 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6914 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6915 const char* extension_names[] = { "withtest1", "withtest2" };
6916 v8::ExtensionConfiguration extensions(2, extension_names);
6917 v8::Handle<Context> context =
6918 Context::New(CcTest::isolate(), &extensions);
6919 Context::Scope lock(context);
6920 v8::Handle<Value> result = CompileRun("UseWith1()");
6921 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6922 result = CompileRun("UseWith2()");
6923 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6927 TEST(AutoExtensions) {
6928 v8::HandleScope handle_scope(CcTest::isolate());
6929 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6930 extension->set_auto_enable(true);
6931 v8::RegisterExtension(extension);
6932 v8::Handle<Context> context =
6933 Context::New(CcTest::isolate());
6934 Context::Scope lock(context);
6935 v8::Handle<Value> result = CompileRun("Foo()");
6936 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6940 static const char* kSyntaxErrorInExtensionSource =
6944 // Test that a syntax error in an extension does not cause a fatal
6945 // error but results in an empty context.
6946 TEST(SyntaxErrorExtensions) {
6947 v8::HandleScope handle_scope(CcTest::isolate());
6948 v8::RegisterExtension(new Extension("syntaxerror",
6949 kSyntaxErrorInExtensionSource));
6950 const char* extension_names[] = { "syntaxerror" };
6951 v8::ExtensionConfiguration extensions(1, extension_names);
6952 v8::Handle<Context> context =
6953 Context::New(CcTest::isolate(), &extensions);
6954 CHECK(context.IsEmpty());
6958 static const char* kExceptionInExtensionSource =
6962 // Test that an exception when installing an extension does not cause
6963 // a fatal error but results in an empty context.
6964 TEST(ExceptionExtensions) {
6965 v8::HandleScope handle_scope(CcTest::isolate());
6966 v8::RegisterExtension(new Extension("exception",
6967 kExceptionInExtensionSource));
6968 const char* extension_names[] = { "exception" };
6969 v8::ExtensionConfiguration extensions(1, extension_names);
6970 v8::Handle<Context> context =
6971 Context::New(CcTest::isolate(), &extensions);
6972 CHECK(context.IsEmpty());
6976 static const char* kNativeCallInExtensionSource =
6977 "function call_runtime_last_index_of(x) {"
6978 " return %StringLastIndexOf(x, 'bob', 10);"
6982 static const char* kNativeCallTest =
6983 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6985 // Test that a native runtime calls are supported in extensions.
6986 TEST(NativeCallInExtensions) {
6987 v8::HandleScope handle_scope(CcTest::isolate());
6988 v8::RegisterExtension(new Extension("nativecall",
6989 kNativeCallInExtensionSource));
6990 const char* extension_names[] = { "nativecall" };
6991 v8::ExtensionConfiguration extensions(1, extension_names);
6992 v8::Handle<Context> context =
6993 Context::New(CcTest::isolate(), &extensions);
6994 Context::Scope lock(context);
6995 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6996 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7000 class NativeFunctionExtension : public Extension {
7002 NativeFunctionExtension(const char* name,
7004 v8::FunctionCallback fun = &Echo)
7005 : Extension(name, source),
7008 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7009 v8::Isolate* isolate,
7010 v8::Handle<v8::String> name) {
7011 return v8::FunctionTemplate::New(isolate, function_);
7014 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7015 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7018 v8::FunctionCallback function_;
7022 TEST(NativeFunctionDeclaration) {
7023 v8::HandleScope handle_scope(CcTest::isolate());
7024 const char* name = "nativedecl";
7025 v8::RegisterExtension(new NativeFunctionExtension(name,
7026 "native function foo();"));
7027 const char* extension_names[] = { name };
7028 v8::ExtensionConfiguration extensions(1, extension_names);
7029 v8::Handle<Context> context =
7030 Context::New(CcTest::isolate(), &extensions);
7031 Context::Scope lock(context);
7032 v8::Handle<Value> result = CompileRun("foo(42);");
7033 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7037 TEST(NativeFunctionDeclarationError) {
7038 v8::HandleScope handle_scope(CcTest::isolate());
7039 const char* name = "nativedeclerr";
7040 // Syntax error in extension code.
7041 v8::RegisterExtension(new NativeFunctionExtension(name,
7042 "native\nfunction foo();"));
7043 const char* extension_names[] = { name };
7044 v8::ExtensionConfiguration extensions(1, extension_names);
7045 v8::Handle<Context> context =
7046 Context::New(CcTest::isolate(), &extensions);
7047 CHECK(context.IsEmpty());
7051 TEST(NativeFunctionDeclarationErrorEscape) {
7052 v8::HandleScope handle_scope(CcTest::isolate());
7053 const char* name = "nativedeclerresc";
7054 // Syntax error in extension code - escape code in "native" means that
7055 // it's not treated as a keyword.
7056 v8::RegisterExtension(new NativeFunctionExtension(
7058 "nativ\\u0065 function foo();"));
7059 const char* extension_names[] = { name };
7060 v8::ExtensionConfiguration extensions(1, extension_names);
7061 v8::Handle<Context> context =
7062 Context::New(CcTest::isolate(), &extensions);
7063 CHECK(context.IsEmpty());
7067 static void CheckDependencies(const char* name, const char* expected) {
7068 v8::HandleScope handle_scope(CcTest::isolate());
7069 v8::ExtensionConfiguration config(1, &name);
7070 LocalContext context(&config);
7071 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7072 context->Global()->Get(v8_str("loaded")));
7083 THREADED_TEST(ExtensionDependency) {
7084 static const char* kEDeps[] = { "D" };
7085 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7086 static const char* kDDeps[] = { "B", "C" };
7087 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7088 static const char* kBCDeps[] = { "A" };
7089 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7090 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7091 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7092 CheckDependencies("A", "undefinedA");
7093 CheckDependencies("B", "undefinedAB");
7094 CheckDependencies("C", "undefinedAC");
7095 CheckDependencies("D", "undefinedABCD");
7096 CheckDependencies("E", "undefinedABCDE");
7097 v8::HandleScope handle_scope(CcTest::isolate());
7098 static const char* exts[2] = { "C", "E" };
7099 v8::ExtensionConfiguration config(2, exts);
7100 LocalContext context(&config);
7101 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7105 static const char* kExtensionTestScript =
7106 "native function A();"
7107 "native function B();"
7108 "native function C();"
7110 " if (i == 0) return A();"
7111 " if (i == 1) return B();"
7112 " if (i == 2) return C();"
7116 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7117 ApiTestFuzzer::Fuzz();
7118 if (args.IsConstructCall()) {
7119 args.This()->Set(v8_str("data"), args.Data());
7120 args.GetReturnValue().SetNull();
7123 args.GetReturnValue().Set(args.Data());
7127 class FunctionExtension : public Extension {
7129 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7130 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7131 v8::Isolate* isolate,
7132 v8::Handle<String> name);
7136 static int lookup_count = 0;
7137 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7138 v8::Isolate* isolate, v8::Handle<String> name) {
7140 if (name->Equals(v8_str("A"))) {
7141 return v8::FunctionTemplate::New(
7142 isolate, CallFun, v8::Integer::New(isolate, 8));
7143 } else if (name->Equals(v8_str("B"))) {
7144 return v8::FunctionTemplate::New(
7145 isolate, CallFun, v8::Integer::New(isolate, 7));
7146 } else if (name->Equals(v8_str("C"))) {
7147 return v8::FunctionTemplate::New(
7148 isolate, CallFun, v8::Integer::New(isolate, 6));
7150 return v8::Handle<v8::FunctionTemplate>();
7155 THREADED_TEST(FunctionLookup) {
7156 v8::RegisterExtension(new FunctionExtension());
7157 v8::HandleScope handle_scope(CcTest::isolate());
7158 static const char* exts[1] = { "functiontest" };
7159 v8::ExtensionConfiguration config(1, exts);
7160 LocalContext context(&config);
7161 CHECK_EQ(3, lookup_count);
7162 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7163 CompileRun("Foo(0)"));
7164 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7165 CompileRun("Foo(1)"));
7166 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7167 CompileRun("Foo(2)"));
7171 THREADED_TEST(NativeFunctionConstructCall) {
7172 v8::RegisterExtension(new FunctionExtension());
7173 v8::HandleScope handle_scope(CcTest::isolate());
7174 static const char* exts[1] = { "functiontest" };
7175 v8::ExtensionConfiguration config(1, exts);
7176 LocalContext context(&config);
7177 for (int i = 0; i < 10; i++) {
7178 // Run a few times to ensure that allocation of objects doesn't
7179 // change behavior of a constructor function.
7180 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7181 CompileRun("(new A()).data"));
7182 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7183 CompileRun("(new B()).data"));
7184 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7185 CompileRun("(new C()).data"));
7190 static const char* last_location;
7191 static const char* last_message;
7192 void StoringErrorCallback(const char* location, const char* message) {
7193 if (last_location == NULL) {
7194 last_location = location;
7195 last_message = message;
7200 // ErrorReporting creates a circular extensions configuration and
7201 // tests that the fatal error handler gets called. This renders V8
7202 // unusable and therefore this test cannot be run in parallel.
7203 TEST(ErrorReporting) {
7204 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7205 static const char* aDeps[] = { "B" };
7206 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7207 static const char* bDeps[] = { "A" };
7208 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7209 last_location = NULL;
7210 v8::ExtensionConfiguration config(1, bDeps);
7211 v8::Handle<Context> context =
7212 Context::New(CcTest::isolate(), &config);
7213 CHECK(context.IsEmpty());
7214 CHECK_NE(last_location, NULL);
7218 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7219 v8::Handle<Value> data) {
7220 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7221 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7222 message->GetScriptOrigin().ResourceName());
7223 message->GetLineNumber();
7224 message->GetSourceLine();
7228 THREADED_TEST(ErrorWithMissingScriptInfo) {
7229 LocalContext context;
7230 v8::HandleScope scope(context->GetIsolate());
7231 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7232 CompileRun("throw Error()");
7233 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7237 struct FlagAndPersistent {
7239 v8::Persistent<v8::Object> handle;
7243 static void DisposeAndSetFlag(
7244 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7245 data.GetParameter()->handle.Reset();
7246 data.GetParameter()->flag = true;
7250 THREADED_TEST(IndependentWeakHandle) {
7251 v8::Isolate* iso = CcTest::isolate();
7252 v8::HandleScope scope(iso);
7253 v8::Handle<Context> context = Context::New(iso);
7254 Context::Scope context_scope(context);
7256 FlagAndPersistent object_a, object_b;
7259 v8::HandleScope handle_scope(iso);
7260 object_a.handle.Reset(iso, v8::Object::New(iso));
7261 object_b.handle.Reset(iso, v8::Object::New(iso));
7264 object_a.flag = false;
7265 object_b.flag = false;
7266 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7267 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7268 CHECK(!object_b.handle.IsIndependent());
7269 object_a.handle.MarkIndependent();
7270 object_b.handle.MarkIndependent();
7271 CHECK(object_b.handle.IsIndependent());
7272 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7273 CHECK(object_a.flag);
7274 CHECK(object_b.flag);
7278 static void InvokeScavenge() {
7279 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7283 static void InvokeMarkSweep() {
7284 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7288 static void ForceScavenge(
7289 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7290 data.GetParameter()->handle.Reset();
7291 data.GetParameter()->flag = true;
7296 static void ForceMarkSweep(
7297 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7298 data.GetParameter()->handle.Reset();
7299 data.GetParameter()->flag = true;
7304 THREADED_TEST(GCFromWeakCallbacks) {
7305 v8::Isolate* isolate = CcTest::isolate();
7306 v8::HandleScope scope(isolate);
7307 v8::Handle<Context> context = Context::New(isolate);
7308 Context::Scope context_scope(context);
7310 static const int kNumberOfGCTypes = 2;
7311 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7313 Callback gc_forcing_callback[kNumberOfGCTypes] =
7314 {&ForceScavenge, &ForceMarkSweep};
7316 typedef void (*GCInvoker)();
7317 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7319 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7320 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7321 FlagAndPersistent object;
7323 v8::HandleScope handle_scope(isolate);
7324 object.handle.Reset(isolate, v8::Object::New(isolate));
7326 object.flag = false;
7327 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7328 object.handle.MarkIndependent();
7329 invoke_gc[outer_gc]();
7336 static void RevivingCallback(
7337 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7338 data.GetParameter()->handle.ClearWeak();
7339 data.GetParameter()->flag = true;
7343 THREADED_TEST(IndependentHandleRevival) {
7344 v8::Isolate* isolate = CcTest::isolate();
7345 v8::HandleScope scope(isolate);
7346 v8::Handle<Context> context = Context::New(isolate);
7347 Context::Scope context_scope(context);
7349 FlagAndPersistent object;
7351 v8::HandleScope handle_scope(isolate);
7352 v8::Local<v8::Object> o = v8::Object::New(isolate);
7353 object.handle.Reset(isolate, o);
7354 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7355 v8::Local<String> y_str = v8_str("y");
7356 o->Set(y_str, y_str);
7358 object.flag = false;
7359 object.handle.SetWeak(&object, &RevivingCallback);
7360 object.handle.MarkIndependent();
7361 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7363 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7365 v8::HandleScope handle_scope(isolate);
7366 v8::Local<v8::Object> o =
7367 v8::Local<v8::Object>::New(isolate, object.handle);
7368 v8::Local<String> y_str = v8_str("y");
7369 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7370 CHECK(o->Get(y_str)->Equals(y_str));
7375 v8::Handle<Function> args_fun;
7378 static void ArgumentsTestCallback(
7379 const v8::FunctionCallbackInfo<v8::Value>& args) {
7380 ApiTestFuzzer::Fuzz();
7381 v8::Isolate* isolate = args.GetIsolate();
7382 CHECK_EQ(args_fun, args.Callee());
7383 CHECK_EQ(3, args.Length());
7384 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7385 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7386 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7387 CHECK_EQ(v8::Undefined(isolate), args[3]);
7388 v8::HandleScope scope(args.GetIsolate());
7389 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7393 THREADED_TEST(Arguments) {
7394 v8::Isolate* isolate = CcTest::isolate();
7395 v8::HandleScope scope(isolate);
7396 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7397 global->Set(v8_str("f"),
7398 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7399 LocalContext context(NULL, global);
7400 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7401 v8_compile("f(1, 2, 3)")->Run();
7405 static void NoBlockGetterX(Local<String> name,
7406 const v8::PropertyCallbackInfo<v8::Value>&) {
7410 static void NoBlockGetterI(uint32_t index,
7411 const v8::PropertyCallbackInfo<v8::Value>&) {
7415 static void PDeleter(Local<String> name,
7416 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7417 if (!name->Equals(v8_str("foo"))) {
7418 return; // not intercepted
7421 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7425 static void IDeleter(uint32_t index,
7426 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7428 return; // not intercepted
7431 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7435 THREADED_TEST(Deleter) {
7436 v8::Isolate* isolate = CcTest::isolate();
7437 v8::HandleScope scope(isolate);
7438 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7439 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7440 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7441 LocalContext context;
7442 context->Global()->Set(v8_str("k"), obj->NewInstance());
7448 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7449 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7451 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7452 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7454 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7455 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7457 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7458 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7462 static void GetK(Local<String> name,
7463 const v8::PropertyCallbackInfo<v8::Value>& info) {
7464 ApiTestFuzzer::Fuzz();
7465 if (name->Equals(v8_str("foo")) ||
7466 name->Equals(v8_str("bar")) ||
7467 name->Equals(v8_str("baz"))) {
7468 info.GetReturnValue().SetUndefined();
7473 static void IndexedGetK(uint32_t index,
7474 const v8::PropertyCallbackInfo<v8::Value>& info) {
7475 ApiTestFuzzer::Fuzz();
7476 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7480 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7481 ApiTestFuzzer::Fuzz();
7482 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7483 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7484 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7485 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7486 info.GetReturnValue().Set(result);
7490 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7491 ApiTestFuzzer::Fuzz();
7492 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7493 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7494 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7495 info.GetReturnValue().Set(result);
7499 THREADED_TEST(Enumerators) {
7500 v8::Isolate* isolate = CcTest::isolate();
7501 v8::HandleScope scope(isolate);
7502 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7503 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7504 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7505 LocalContext context;
7506 context->Global()->Set(v8_str("k"), obj->NewInstance());
7507 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7512 "k[4294967295] = 0;"
7514 "k[4294967296] = 0;"
7518 "k[30000000000] = 0;"
7521 "for (var prop in k) {"
7522 " result.push(prop);"
7525 // Check that we get all the property names returned including the
7526 // ones from the enumerators in the right order: indexed properties
7527 // in numerical order, indexed interceptor properties, named
7528 // properties in insertion order, named interceptor properties.
7529 // This order is not mandated by the spec, so this test is just
7530 // documenting our behavior.
7531 CHECK_EQ(17, result->Length());
7532 // Indexed properties in numerical order.
7533 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7534 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7535 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7536 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7537 // Indexed interceptor properties in the order they are returned
7538 // from the enumerator interceptor.
7539 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7540 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7541 // Named properties in insertion order.
7542 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7543 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7544 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7545 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7546 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7547 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7548 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7549 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7550 // Named interceptor properties.
7551 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7552 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7553 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7558 int p_getter_count2;
7561 static void PGetter(Local<String> name,
7562 const v8::PropertyCallbackInfo<v8::Value>& info) {
7563 ApiTestFuzzer::Fuzz();
7565 v8::Handle<v8::Object> global =
7566 info.GetIsolate()->GetCurrentContext()->Global();
7567 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7568 if (name->Equals(v8_str("p1"))) {
7569 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7570 } else if (name->Equals(v8_str("p2"))) {
7571 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7572 } else if (name->Equals(v8_str("p3"))) {
7573 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7574 } else if (name->Equals(v8_str("p4"))) {
7575 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7580 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7581 ApiTestFuzzer::Fuzz();
7582 LocalContext context;
7583 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7585 "o1.__proto__ = { };"
7586 "var o2 = { __proto__: o1 };"
7587 "var o3 = { __proto__: o2 };"
7588 "var o4 = { __proto__: o3 };"
7589 "for (var i = 0; i < 10; i++) o4.p4;"
7590 "for (var i = 0; i < 10; i++) o3.p3;"
7591 "for (var i = 0; i < 10; i++) o2.p2;"
7592 "for (var i = 0; i < 10; i++) o1.p1;");
7596 static void PGetter2(Local<String> name,
7597 const v8::PropertyCallbackInfo<v8::Value>& info) {
7598 ApiTestFuzzer::Fuzz();
7600 v8::Handle<v8::Object> global =
7601 info.GetIsolate()->GetCurrentContext()->Global();
7602 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7603 if (name->Equals(v8_str("p1"))) {
7604 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7605 } else if (name->Equals(v8_str("p2"))) {
7606 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7607 } else if (name->Equals(v8_str("p3"))) {
7608 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7609 } else if (name->Equals(v8_str("p4"))) {
7610 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7615 THREADED_TEST(GetterHolders) {
7616 v8::Isolate* isolate = CcTest::isolate();
7617 v8::HandleScope scope(isolate);
7618 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7619 obj->SetAccessor(v8_str("p1"), PGetter);
7620 obj->SetAccessor(v8_str("p2"), PGetter);
7621 obj->SetAccessor(v8_str("p3"), PGetter);
7622 obj->SetAccessor(v8_str("p4"), PGetter);
7625 CHECK_EQ(40, p_getter_count);
7629 THREADED_TEST(PreInterceptorHolders) {
7630 v8::Isolate* isolate = CcTest::isolate();
7631 v8::HandleScope scope(isolate);
7632 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7633 obj->SetNamedPropertyHandler(PGetter2);
7634 p_getter_count2 = 0;
7636 CHECK_EQ(40, p_getter_count2);
7640 THREADED_TEST(ObjectInstantiation) {
7641 v8::Isolate* isolate = CcTest::isolate();
7642 v8::HandleScope scope(isolate);
7643 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7644 templ->SetAccessor(v8_str("t"), PGetter2);
7645 LocalContext context;
7646 context->Global()->Set(v8_str("o"), templ->NewInstance());
7647 for (int i = 0; i < 100; i++) {
7648 v8::HandleScope inner_scope(CcTest::isolate());
7649 v8::Handle<v8::Object> obj = templ->NewInstance();
7650 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7651 context->Global()->Set(v8_str("o2"), obj);
7652 v8::Handle<Value> value =
7653 CompileRun("o.__proto__ === o2.__proto__");
7654 CHECK_EQ(v8::True(isolate), value);
7655 context->Global()->Set(v8_str("o"), obj);
7660 static int StrCmp16(uint16_t* a, uint16_t* b) {
7662 if (*a == 0 && *b == 0) return 0;
7663 if (*a != *b) return 0 + *a - *b;
7670 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7672 if (n-- == 0) return 0;
7673 if (*a == 0 && *b == 0) return 0;
7674 if (*a != *b) return 0 + *a - *b;
7681 int GetUtf8Length(Handle<String> str) {
7682 int len = str->Utf8Length();
7684 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7685 i::String::Flatten(istr);
7686 len = str->Utf8Length();
7692 THREADED_TEST(StringWrite) {
7693 LocalContext context;
7694 v8::HandleScope scope(context->GetIsolate());
7695 v8::Handle<String> str = v8_str("abcde");
7696 // abc<Icelandic eth><Unicode snowman>.
7697 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7698 v8::Handle<String> str3 = v8::String::NewFromUtf8(
7699 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7700 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7701 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7702 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7703 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7704 // single lead surrogate
7705 uint16_t lead[1] = { 0xd800 };
7706 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7707 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7708 // single trail surrogate
7709 uint16_t trail[1] = { 0xdc00 };
7710 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7711 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7713 uint16_t pair[2] = { 0xd800, 0xdc00 };
7714 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7715 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7716 const int kStride = 4; // Must match stride in for loops in JS below.
7719 "for (var i = 0; i < 0xd800; i += 4) {"
7720 " left = left + String.fromCharCode(i);"
7724 "for (var i = 0; i < 0xd800; i += 4) {"
7725 " right = String.fromCharCode(i) + right;"
7727 v8::Handle<v8::Object> global = context->Global();
7728 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7729 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7731 CHECK_EQ(5, str2->Length());
7732 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7733 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7736 char utf8buf[0xd800 * 3];
7741 memset(utf8buf, 0x1, 1000);
7742 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7744 CHECK_EQ(5, charlen);
7745 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7747 memset(utf8buf, 0x1, 1000);
7748 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7750 CHECK_EQ(5, charlen);
7751 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7753 memset(utf8buf, 0x1, 1000);
7754 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7756 CHECK_EQ(4, charlen);
7757 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7759 memset(utf8buf, 0x1, 1000);
7760 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7762 CHECK_EQ(4, charlen);
7763 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7765 memset(utf8buf, 0x1, 1000);
7766 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7768 CHECK_EQ(4, charlen);
7769 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7771 memset(utf8buf, 0x1, 1000);
7772 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7774 CHECK_EQ(3, charlen);
7775 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7777 memset(utf8buf, 0x1, 1000);
7778 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7780 CHECK_EQ(3, charlen);
7781 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7783 memset(utf8buf, 0x1, 1000);
7784 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7786 CHECK_EQ(2, charlen);
7787 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7789 // allow orphan surrogates by default
7790 memset(utf8buf, 0x1, 1000);
7791 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7793 CHECK_EQ(8, charlen);
7794 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7796 // replace orphan surrogates with unicode replacement character
7797 memset(utf8buf, 0x1, 1000);
7798 len = orphans_str->WriteUtf8(utf8buf,
7801 String::REPLACE_INVALID_UTF8);
7803 CHECK_EQ(8, charlen);
7804 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7806 // replace single lead surrogate with unicode replacement character
7807 memset(utf8buf, 0x1, 1000);
7808 len = lead_str->WriteUtf8(utf8buf,
7811 String::REPLACE_INVALID_UTF8);
7813 CHECK_EQ(1, charlen);
7814 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7816 // replace single trail surrogate with unicode replacement character
7817 memset(utf8buf, 0x1, 1000);
7818 len = trail_str->WriteUtf8(utf8buf,
7821 String::REPLACE_INVALID_UTF8);
7823 CHECK_EQ(1, charlen);
7824 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7826 // do not replace / write anything if surrogate pair does not fit the buffer
7828 memset(utf8buf, 0x1, 1000);
7829 len = pair_str->WriteUtf8(utf8buf,
7832 String::REPLACE_INVALID_UTF8);
7834 CHECK_EQ(0, charlen);
7836 memset(utf8buf, 0x1, sizeof(utf8buf));
7837 len = GetUtf8Length(left_tree);
7839 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7840 CHECK_EQ(utf8_expected, len);
7841 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7842 CHECK_EQ(utf8_expected, len);
7843 CHECK_EQ(0xd800 / kStride, charlen);
7844 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7845 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7846 CHECK_EQ(0xc0 - kStride,
7847 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7848 CHECK_EQ(1, utf8buf[utf8_expected]);
7850 memset(utf8buf, 0x1, sizeof(utf8buf));
7851 len = GetUtf8Length(right_tree);
7852 CHECK_EQ(utf8_expected, len);
7853 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7854 CHECK_EQ(utf8_expected, len);
7855 CHECK_EQ(0xd800 / kStride, charlen);
7856 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7857 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7858 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7859 CHECK_EQ(1, utf8buf[utf8_expected]);
7861 memset(buf, 0x1, sizeof(buf));
7862 memset(wbuf, 0x1, sizeof(wbuf));
7863 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7865 len = str->Write(wbuf);
7867 CHECK_EQ(0, strcmp("abcde", buf));
7868 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7869 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7871 memset(buf, 0x1, sizeof(buf));
7872 memset(wbuf, 0x1, sizeof(wbuf));
7873 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7875 len = str->Write(wbuf, 0, 4);
7877 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7878 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7879 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7881 memset(buf, 0x1, sizeof(buf));
7882 memset(wbuf, 0x1, sizeof(wbuf));
7883 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7885 len = str->Write(wbuf, 0, 5);
7887 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7888 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7889 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7891 memset(buf, 0x1, sizeof(buf));
7892 memset(wbuf, 0x1, sizeof(wbuf));
7893 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7895 len = str->Write(wbuf, 0, 6);
7897 CHECK_EQ(0, strcmp("abcde", buf));
7898 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7899 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7901 memset(buf, 0x1, sizeof(buf));
7902 memset(wbuf, 0x1, sizeof(wbuf));
7903 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7905 len = str->Write(wbuf, 4, -1);
7907 CHECK_EQ(0, strcmp("e", buf));
7908 uint16_t answer5[] = {'e', '\0'};
7909 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7911 memset(buf, 0x1, sizeof(buf));
7912 memset(wbuf, 0x1, sizeof(wbuf));
7913 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7915 len = str->Write(wbuf, 4, 6);
7917 CHECK_EQ(0, strcmp("e", buf));
7918 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7920 memset(buf, 0x1, sizeof(buf));
7921 memset(wbuf, 0x1, sizeof(wbuf));
7922 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7924 len = str->Write(wbuf, 4, 1);
7926 CHECK_EQ(0, strncmp("e\1", buf, 2));
7927 uint16_t answer6[] = {'e', 0x101};
7928 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7930 memset(buf, 0x1, sizeof(buf));
7931 memset(wbuf, 0x1, sizeof(wbuf));
7932 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7934 len = str->Write(wbuf, 3, 1);
7936 CHECK_EQ(0, strncmp("d\1", buf, 2));
7937 uint16_t answer7[] = {'d', 0x101};
7938 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7940 memset(wbuf, 0x1, sizeof(wbuf));
7942 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7944 CHECK_EQ('X', wbuf[5]);
7945 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7946 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7947 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7948 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7950 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7952 memset(buf, 0x1, sizeof(buf));
7954 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7957 String::NO_NULL_TERMINATION);
7959 CHECK_EQ('X', buf[5]);
7960 CHECK_EQ(0, strncmp("abcde", buf, 5));
7961 CHECK_NE(0, strcmp("abcde", buf));
7963 CHECK_EQ(0, strcmp("abcde", buf));
7965 memset(utf8buf, 0x1, sizeof(utf8buf));
7967 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7968 String::NO_NULL_TERMINATION);
7970 CHECK_EQ('X', utf8buf[8]);
7971 CHECK_EQ(5, charlen);
7972 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7973 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7975 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7977 memset(utf8buf, 0x1, sizeof(utf8buf));
7979 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7980 String::NO_NULL_TERMINATION);
7982 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7983 CHECK_EQ(5, charlen);
7985 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7987 memset(buf, 0x1, sizeof(buf));
7988 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7990 CHECK_EQ(0, strcmp("abc", buf));
7991 CHECK_EQ(0, buf[3]);
7992 CHECK_EQ(0, strcmp("def", buf + 4));
7994 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7995 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7996 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8000 static void Utf16Helper(
8001 LocalContext& context, // NOLINT
8003 const char* lengths_name,
8005 Local<v8::Array> a =
8006 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8007 Local<v8::Array> alens =
8008 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8009 for (int i = 0; i < len; i++) {
8010 Local<v8::String> string =
8011 Local<v8::String>::Cast(a->Get(i));
8012 Local<v8::Number> expected_len =
8013 Local<v8::Number>::Cast(alens->Get(i));
8014 int length = GetUtf8Length(string);
8015 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8020 static uint16_t StringGet(Handle<String> str, int index) {
8021 i::Handle<i::String> istring =
8022 v8::Utils::OpenHandle(String::Cast(*str));
8023 return istring->Get(index);
8027 static void WriteUtf8Helper(
8028 LocalContext& context, // NOLINT
8030 const char* lengths_name,
8032 Local<v8::Array> b =
8033 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8034 Local<v8::Array> alens =
8035 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8038 for (int i = 0; i < len; i++) {
8039 Local<v8::String> string =
8040 Local<v8::String>::Cast(b->Get(i));
8041 Local<v8::Number> expected_len =
8042 Local<v8::Number>::Cast(alens->Get(i));
8043 int utf8_length = static_cast<int>(expected_len->Value());
8044 for (int j = utf8_length + 1; j >= 0; j--) {
8045 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8046 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8049 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8051 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8052 CHECK_GE(utf8_length + 1, utf8_written);
8053 CHECK_GE(utf8_length, utf8_written2);
8054 for (int k = 0; k < utf8_written2; k++) {
8055 CHECK_EQ(buffer[k], buffer2[k]);
8057 CHECK(nchars * 3 >= utf8_written - 1);
8058 CHECK(nchars <= utf8_written);
8059 if (j == utf8_length + 1) {
8060 CHECK_EQ(utf8_written2, utf8_length);
8061 CHECK_EQ(utf8_written2 + 1, utf8_written);
8063 CHECK_EQ(buffer[utf8_written], 42);
8064 if (j > utf8_length) {
8065 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8066 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8067 Handle<String> roundtrip = v8_str(buffer);
8068 CHECK(roundtrip->Equals(string));
8070 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8072 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8074 uint16_t trail = StringGet(string, nchars - 1);
8075 uint16_t lead = StringGet(string, nchars - 2);
8076 if (((lead & 0xfc00) == 0xd800) &&
8077 ((trail & 0xfc00) == 0xdc00)) {
8078 unsigned char u1 = buffer2[utf8_written2 - 4];
8079 unsigned char u2 = buffer2[utf8_written2 - 3];
8080 unsigned char u3 = buffer2[utf8_written2 - 2];
8081 unsigned char u4 = buffer2[utf8_written2 - 1];
8082 CHECK_EQ((u1 & 0xf8), 0xf0);
8083 CHECK_EQ((u2 & 0xc0), 0x80);
8084 CHECK_EQ((u3 & 0xc0), 0x80);
8085 CHECK_EQ((u4 & 0xc0), 0x80);
8086 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8087 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8088 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8089 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8090 CHECK_EQ((u1 & 0x3), c >> 18);
8098 THREADED_TEST(Utf16) {
8099 LocalContext context;
8100 v8::HandleScope scope(context->GetIsolate());
8102 "var pad = '01234567890123456789';"
8104 "var plens = [20, 3, 3];"
8105 "p.push('01234567890123456789');"
8106 "var lead = 0xd800;"
8107 "var trail = 0xdc00;"
8108 "p.push(String.fromCharCode(0xd800));"
8109 "p.push(String.fromCharCode(0xdc00));"
8114 "for (var i = 0; i < 3; i++) {"
8115 " p[1] = String.fromCharCode(lead++);"
8116 " for (var j = 0; j < 3; j++) {"
8117 " p[2] = String.fromCharCode(trail++);"
8118 " a.push(p[i] + p[j]);"
8119 " b.push(p[i] + p[j]);"
8120 " c.push(p[i] + p[j]);"
8121 " alens.push(plens[i] + plens[j]);"
8124 "alens[5] -= 2;" // Here the surrogate pairs match up.
8129 "for (var m = 0; m < 9; m++) {"
8130 " for (var n = 0; n < 9; n++) {"
8131 " a2.push(a[m] + a[n]);"
8132 " b2.push(b[m] + b[n]);"
8133 " var newc = 'x' + c[m] + c[n] + 'y';"
8134 " c2.push(newc.substring(1, newc.length - 1));"
8135 " var utf = alens[m] + alens[n];" // And here.
8136 // The 'n's that start with 0xdc.. are 6-8
8137 // The 'm's that end with 0xd8.. are 1, 4 and 7
8138 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8139 " a2lens.push(utf);"
8142 Utf16Helper(context, "a", "alens", 9);
8143 Utf16Helper(context, "a2", "a2lens", 81);
8144 WriteUtf8Helper(context, "b", "alens", 9);
8145 WriteUtf8Helper(context, "b2", "a2lens", 81);
8146 WriteUtf8Helper(context, "c2", "a2lens", 81);
8150 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8151 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8152 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8153 return *is1 == *is2;
8156 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8158 Handle<String> symbol1 =
8159 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8160 Handle<String> symbol2 =
8161 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8162 CHECK(SameSymbol(symbol1, symbol2));
8166 THREADED_TEST(Utf16Symbol) {
8167 LocalContext context;
8168 v8::HandleScope scope(context->GetIsolate());
8170 Handle<String> symbol1 = v8::String::NewFromUtf8(
8171 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8172 Handle<String> symbol2 = v8::String::NewFromUtf8(
8173 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8174 CHECK(SameSymbol(symbol1, symbol2));
8176 SameSymbolHelper(context->GetIsolate(),
8177 "\360\220\220\205", // 4 byte encoding.
8178 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8179 SameSymbolHelper(context->GetIsolate(),
8180 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8181 "\360\220\220\206"); // 4 byte encoding.
8182 SameSymbolHelper(context->GetIsolate(),
8183 "x\360\220\220\205", // 4 byte encoding.
8184 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8185 SameSymbolHelper(context->GetIsolate(),
8186 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8187 "x\360\220\220\206"); // 4 byte encoding.
8189 "var sym0 = 'benedictus';"
8190 "var sym0b = 'S\303\270ren';"
8191 "var sym1 = '\355\240\201\355\260\207';"
8192 "var sym2 = '\360\220\220\210';"
8193 "var sym3 = 'x\355\240\201\355\260\207';"
8194 "var sym4 = 'x\360\220\220\210';"
8195 "if (sym1.length != 2) throw sym1;"
8196 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8197 "if (sym2.length != 2) throw sym2;"
8198 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8199 "if (sym3.length != 3) throw sym3;"
8200 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8201 "if (sym4.length != 3) throw sym4;"
8202 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8203 Handle<String> sym0 = v8::String::NewFromUtf8(
8204 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8205 Handle<String> sym0b = v8::String::NewFromUtf8(
8206 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8207 Handle<String> sym1 =
8208 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8209 v8::String::kInternalizedString);
8210 Handle<String> sym2 =
8211 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8212 v8::String::kInternalizedString);
8213 Handle<String> sym3 = v8::String::NewFromUtf8(
8214 context->GetIsolate(), "x\355\240\201\355\260\207",
8215 v8::String::kInternalizedString);
8216 Handle<String> sym4 =
8217 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8218 v8::String::kInternalizedString);
8219 v8::Local<v8::Object> global = context->Global();
8220 Local<Value> s0 = global->Get(v8_str("sym0"));
8221 Local<Value> s0b = global->Get(v8_str("sym0b"));
8222 Local<Value> s1 = global->Get(v8_str("sym1"));
8223 Local<Value> s2 = global->Get(v8_str("sym2"));
8224 Local<Value> s3 = global->Get(v8_str("sym3"));
8225 Local<Value> s4 = global->Get(v8_str("sym4"));
8226 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8227 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8228 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8229 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8230 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8231 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8235 THREADED_TEST(ToArrayIndex) {
8236 LocalContext context;
8237 v8::Isolate* isolate = context->GetIsolate();
8238 v8::HandleScope scope(isolate);
8240 v8::Handle<String> str = v8_str("42");
8241 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8242 CHECK(!index.IsEmpty());
8243 CHECK_EQ(42.0, index->Uint32Value());
8244 str = v8_str("42asdf");
8245 index = str->ToArrayIndex();
8246 CHECK(index.IsEmpty());
8247 str = v8_str("-42");
8248 index = str->ToArrayIndex();
8249 CHECK(index.IsEmpty());
8250 str = v8_str("4294967295");
8251 index = str->ToArrayIndex();
8252 CHECK(!index.IsEmpty());
8253 CHECK_EQ(4294967295.0, index->Uint32Value());
8254 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8255 index = num->ToArrayIndex();
8256 CHECK(!index.IsEmpty());
8257 CHECK_EQ(1.0, index->Uint32Value());
8258 num = v8::Number::New(isolate, -1);
8259 index = num->ToArrayIndex();
8260 CHECK(index.IsEmpty());
8261 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8262 index = obj->ToArrayIndex();
8263 CHECK(index.IsEmpty());
8267 THREADED_TEST(ErrorConstruction) {
8268 LocalContext context;
8269 v8::HandleScope scope(context->GetIsolate());
8271 v8::Handle<String> foo = v8_str("foo");
8272 v8::Handle<String> message = v8_str("message");
8273 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8274 CHECK(range_error->IsObject());
8275 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8276 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8277 CHECK(reference_error->IsObject());
8278 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8279 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8280 CHECK(syntax_error->IsObject());
8281 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8282 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8283 CHECK(type_error->IsObject());
8284 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8285 v8::Handle<Value> error = v8::Exception::Error(foo);
8286 CHECK(error->IsObject());
8287 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8291 static void YGetter(Local<String> name,
8292 const v8::PropertyCallbackInfo<v8::Value>& info) {
8293 ApiTestFuzzer::Fuzz();
8294 info.GetReturnValue().Set(v8_num(10));
8298 static void YSetter(Local<String> name,
8300 const v8::PropertyCallbackInfo<void>& info) {
8301 Local<Object> this_obj = Local<Object>::Cast(info.This());
8302 if (this_obj->Has(name)) this_obj->Delete(name);
8303 this_obj->Set(name, value);
8307 THREADED_TEST(DeleteAccessor) {
8308 v8::Isolate* isolate = CcTest::isolate();
8309 v8::HandleScope scope(isolate);
8310 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8311 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8312 LocalContext context;
8313 v8::Handle<v8::Object> holder = obj->NewInstance();
8314 context->Global()->Set(v8_str("holder"), holder);
8315 v8::Handle<Value> result = CompileRun(
8316 "holder.y = 11; holder.y = 12; holder.y");
8317 CHECK_EQ(12, result->Uint32Value());
8321 THREADED_TEST(TypeSwitch) {
8322 v8::Isolate* isolate = CcTest::isolate();
8323 v8::HandleScope scope(isolate);
8324 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8325 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8326 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8327 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8328 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8329 LocalContext context;
8330 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8331 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8332 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8333 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8334 for (int i = 0; i < 10; i++) {
8335 CHECK_EQ(0, type_switch->match(obj0));
8336 CHECK_EQ(1, type_switch->match(obj1));
8337 CHECK_EQ(2, type_switch->match(obj2));
8338 CHECK_EQ(3, type_switch->match(obj3));
8339 CHECK_EQ(3, type_switch->match(obj3));
8340 CHECK_EQ(2, type_switch->match(obj2));
8341 CHECK_EQ(1, type_switch->match(obj1));
8342 CHECK_EQ(0, type_switch->match(obj0));
8347 static int trouble_nesting = 0;
8348 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8349 ApiTestFuzzer::Fuzz();
8352 // Call a JS function that throws an uncaught exception.
8353 Local<v8::Object> arg_this =
8354 args.GetIsolate()->GetCurrentContext()->Global();
8355 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8356 arg_this->Get(v8_str("trouble_callee")) :
8357 arg_this->Get(v8_str("trouble_caller"));
8358 CHECK(trouble_callee->IsFunction());
8359 args.GetReturnValue().Set(
8360 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8364 static int report_count = 0;
8365 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8366 v8::Handle<Value>) {
8371 // Counts uncaught exceptions, but other tests running in parallel
8372 // also have uncaught exceptions.
8373 TEST(ApiUncaughtException) {
8376 v8::Isolate* isolate = env->GetIsolate();
8377 v8::HandleScope scope(isolate);
8378 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8380 Local<v8::FunctionTemplate> fun =
8381 v8::FunctionTemplate::New(isolate, TroubleCallback);
8382 v8::Local<v8::Object> global = env->Global();
8383 global->Set(v8_str("trouble"), fun->GetFunction());
8386 "function trouble_callee() {"
8390 "function trouble_caller() {"
8393 Local<Value> trouble = global->Get(v8_str("trouble"));
8394 CHECK(trouble->IsFunction());
8395 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8396 CHECK(trouble_callee->IsFunction());
8397 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8398 CHECK(trouble_caller->IsFunction());
8399 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8400 CHECK_EQ(1, report_count);
8401 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8404 static const char* script_resource_name = "ExceptionInNativeScript.js";
8405 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8406 v8::Handle<Value>) {
8407 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8408 CHECK(!name_val.IsEmpty() && name_val->IsString());
8409 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8410 CHECK_EQ(script_resource_name, *name);
8411 CHECK_EQ(3, message->GetLineNumber());
8412 v8::String::Utf8Value source_line(message->GetSourceLine());
8413 CHECK_EQ(" new o.foo();", *source_line);
8417 TEST(ExceptionInNativeScript) {
8419 v8::Isolate* isolate = env->GetIsolate();
8420 v8::HandleScope scope(isolate);
8421 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8423 Local<v8::FunctionTemplate> fun =
8424 v8::FunctionTemplate::New(isolate, TroubleCallback);
8425 v8::Local<v8::Object> global = env->Global();
8426 global->Set(v8_str("trouble"), fun->GetFunction());
8428 CompileRunWithOrigin(
8429 "function trouble() {\n"
8433 script_resource_name);
8434 Local<Value> trouble = global->Get(v8_str("trouble"));
8435 CHECK(trouble->IsFunction());
8436 Function::Cast(*trouble)->Call(global, 0, NULL);
8437 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8441 TEST(CompilationErrorUsingTryCatchHandler) {
8443 v8::HandleScope scope(env->GetIsolate());
8444 v8::TryCatch try_catch;
8445 v8_compile("This doesn't &*&@#$&*^ compile.");
8446 CHECK_NE(NULL, *try_catch.Exception());
8447 CHECK(try_catch.HasCaught());
8451 TEST(TryCatchFinallyUsingTryCatchHandler) {
8453 v8::HandleScope scope(env->GetIsolate());
8454 v8::TryCatch try_catch;
8455 CompileRun("try { throw ''; } catch (e) {}");
8456 CHECK(!try_catch.HasCaught());
8457 CompileRun("try { throw ''; } finally {}");
8458 CHECK(try_catch.HasCaught());
8462 "try { throw ''; } finally { return; }"
8464 CHECK(!try_catch.HasCaught());
8467 " { try { throw ''; } finally { throw 0; }"
8469 CHECK(try_catch.HasCaught());
8473 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8474 v8::HandleScope scope(args.GetIsolate());
8475 CompileRun(args[0]->ToString());
8479 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8480 v8::Isolate* isolate = CcTest::isolate();
8481 v8::HandleScope scope(isolate);
8482 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8483 templ->Set(v8_str("CEvaluate"),
8484 v8::FunctionTemplate::New(isolate, CEvaluate));
8485 LocalContext context(0, templ);
8486 v8::TryCatch try_catch;
8488 " CEvaluate('throw 1;');"
8491 CHECK(try_catch.HasCaught());
8492 CHECK(!try_catch.Message().IsEmpty());
8493 String::Utf8Value exception_value(try_catch.Exception());
8494 CHECK_EQ(*exception_value, "1");
8497 " CEvaluate('throw 1;');"
8501 CHECK(try_catch.HasCaught());
8502 CHECK(!try_catch.Message().IsEmpty());
8503 String::Utf8Value finally_exception_value(try_catch.Exception());
8504 CHECK_EQ(*finally_exception_value, "2");
8508 // For use within the TestSecurityHandler() test.
8509 static bool g_security_callback_result = false;
8510 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8512 v8::AccessType type,
8513 Local<Value> data) {
8515 // Always allow read access.
8516 if (type == v8::ACCESS_GET)
8519 // Sometimes allow other access.
8520 return g_security_callback_result;
8524 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8526 v8::AccessType type,
8527 Local<Value> data) {
8529 // Always allow read access.
8530 if (type == v8::ACCESS_GET)
8533 // Sometimes allow other access.
8534 return g_security_callback_result;
8538 // SecurityHandler can't be run twice
8539 TEST(SecurityHandler) {
8540 v8::Isolate* isolate = CcTest::isolate();
8541 v8::HandleScope scope0(isolate);
8542 v8::Handle<v8::ObjectTemplate> global_template =
8543 v8::ObjectTemplate::New(isolate);
8544 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8545 IndexedSecurityTestCallback);
8546 // Create an environment
8547 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8550 v8::Handle<v8::Object> global0 = context0->Global();
8551 v8::Handle<Script> script0 = v8_compile("foo = 111");
8553 global0->Set(v8_str("0"), v8_num(999));
8554 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8555 CHECK_EQ(111, foo0->Int32Value());
8556 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8557 CHECK_EQ(999, z0->Int32Value());
8559 // Create another environment, should fail security checks.
8560 v8::HandleScope scope1(isolate);
8562 v8::Handle<Context> context1 =
8563 Context::New(isolate, NULL, global_template);
8566 v8::Handle<v8::Object> global1 = context1->Global();
8567 global1->Set(v8_str("othercontext"), global0);
8568 // This set will fail the security check.
8569 v8::Handle<Script> script1 =
8570 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8572 // This read will pass the security check.
8573 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8574 CHECK_EQ(111, foo1->Int32Value());
8575 // This read will pass the security check.
8576 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8577 CHECK_EQ(999, z1->Int32Value());
8579 // Create another environment, should pass security checks.
8580 { g_security_callback_result = true; // allow security handler to pass.
8581 v8::HandleScope scope2(isolate);
8582 LocalContext context2;
8583 v8::Handle<v8::Object> global2 = context2->Global();
8584 global2->Set(v8_str("othercontext"), global0);
8585 v8::Handle<Script> script2 =
8586 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8588 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8589 CHECK_EQ(333, foo2->Int32Value());
8590 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8591 CHECK_EQ(888, z2->Int32Value());
8599 THREADED_TEST(SecurityChecks) {
8601 v8::HandleScope handle_scope(env1->GetIsolate());
8602 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8604 Local<Value> foo = v8_str("foo");
8605 Local<Value> bar = v8_str("bar");
8607 // Set to the same domain.
8608 env1->SetSecurityToken(foo);
8610 // Create a function in env1.
8611 CompileRun("spy=function(){return spy;}");
8612 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8613 CHECK(spy->IsFunction());
8615 // Create another function accessing global objects.
8616 CompileRun("spy2=function(){return new this.Array();}");
8617 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8618 CHECK(spy2->IsFunction());
8620 // Switch to env2 in the same domain and invoke spy on env2.
8622 env2->SetSecurityToken(foo);
8624 Context::Scope scope_env2(env2);
8625 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8626 CHECK(result->IsFunction());
8630 env2->SetSecurityToken(bar);
8631 Context::Scope scope_env2(env2);
8633 // Call cross_domain_call, it should throw an exception
8634 v8::TryCatch try_catch;
8635 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8636 CHECK(try_catch.HasCaught());
8641 // Regression test case for issue 1183439.
8642 THREADED_TEST(SecurityChecksForPrototypeChain) {
8643 LocalContext current;
8644 v8::HandleScope scope(current->GetIsolate());
8645 v8::Handle<Context> other = Context::New(current->GetIsolate());
8647 // Change context to be able to get to the Object function in the
8648 // other context without hitting the security checks.
8649 v8::Local<Value> other_object;
8650 { Context::Scope scope(other);
8651 other_object = other->Global()->Get(v8_str("Object"));
8652 other->Global()->Set(v8_num(42), v8_num(87));
8655 current->Global()->Set(v8_str("other"), other->Global());
8656 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8658 // Make sure the security check fails here and we get an undefined
8659 // result instead of getting the Object function. Repeat in a loop
8660 // to make sure to exercise the IC code.
8661 v8::Local<Script> access_other0 = v8_compile("other.Object");
8662 v8::Local<Script> access_other1 = v8_compile("other[42]");
8663 for (int i = 0; i < 5; i++) {
8664 CHECK(access_other0->Run().IsEmpty());
8665 CHECK(access_other1->Run().IsEmpty());
8668 // Create an object that has 'other' in its prototype chain and make
8669 // sure we cannot access the Object function indirectly through
8670 // that. Repeat in a loop to make sure to exercise the IC code.
8671 v8_compile("function F() { };"
8672 "F.prototype = other;"
8673 "var f = new F();")->Run();
8674 v8::Local<Script> access_f0 = v8_compile("f.Object");
8675 v8::Local<Script> access_f1 = v8_compile("f[42]");
8676 for (int j = 0; j < 5; j++) {
8677 CHECK(access_f0->Run().IsEmpty());
8678 CHECK(access_f1->Run().IsEmpty());
8681 // Now it gets hairy: Set the prototype for the other global object
8682 // to be the current global object. The prototype chain for 'f' now
8683 // goes through 'other' but ends up in the current global object.
8684 { Context::Scope scope(other);
8685 other->Global()->Set(v8_str("__proto__"), current->Global());
8687 // Set a named and an index property on the current global
8688 // object. To force the lookup to go through the other global object,
8689 // the properties must not exist in the other global object.
8690 current->Global()->Set(v8_str("foo"), v8_num(100));
8691 current->Global()->Set(v8_num(99), v8_num(101));
8692 // Try to read the properties from f and make sure that the access
8693 // gets stopped by the security checks on the other global object.
8694 Local<Script> access_f2 = v8_compile("f.foo");
8695 Local<Script> access_f3 = v8_compile("f[99]");
8696 for (int k = 0; k < 5; k++) {
8697 CHECK(access_f2->Run().IsEmpty());
8698 CHECK(access_f3->Run().IsEmpty());
8703 static bool named_security_check_with_gc_called;
8705 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8707 v8::AccessType type,
8708 Local<Value> data) {
8709 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8710 named_security_check_with_gc_called = true;
8715 static bool indexed_security_check_with_gc_called;
8717 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8719 v8::AccessType type,
8720 Local<Value> data) {
8721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8722 indexed_security_check_with_gc_called = true;
8727 TEST(SecurityTestGCAllowed) {
8728 v8::Isolate* isolate = CcTest::isolate();
8729 v8::HandleScope handle_scope(isolate);
8730 v8::Handle<v8::ObjectTemplate> object_template =
8731 v8::ObjectTemplate::New(isolate);
8732 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8733 IndexedSecurityTestCallbackWithGC);
8735 v8::Handle<Context> context = Context::New(isolate);
8736 v8::Context::Scope context_scope(context);
8738 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8740 named_security_check_with_gc_called = false;
8741 CompileRun("obj.foo = new String(1001);");
8742 CHECK(named_security_check_with_gc_called);
8744 indexed_security_check_with_gc_called = false;
8745 CompileRun("obj[0] = new String(1002);");
8746 CHECK(indexed_security_check_with_gc_called);
8748 named_security_check_with_gc_called = false;
8749 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8750 CHECK(named_security_check_with_gc_called);
8752 indexed_security_check_with_gc_called = false;
8753 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8754 CHECK(indexed_security_check_with_gc_called);
8758 THREADED_TEST(CrossDomainDelete) {
8760 v8::HandleScope handle_scope(env1->GetIsolate());
8761 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8763 Local<Value> foo = v8_str("foo");
8764 Local<Value> bar = v8_str("bar");
8766 // Set to the same domain.
8767 env1->SetSecurityToken(foo);
8768 env2->SetSecurityToken(foo);
8770 env1->Global()->Set(v8_str("prop"), v8_num(3));
8771 env2->Global()->Set(v8_str("env1"), env1->Global());
8773 // Change env2 to a different domain and delete env1.prop.
8774 env2->SetSecurityToken(bar);
8776 Context::Scope scope_env2(env2);
8777 Local<Value> result =
8778 CompileRun("delete env1.prop");
8779 CHECK(result.IsEmpty());
8782 // Check that env1.prop still exists.
8783 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8784 CHECK(v->IsNumber());
8785 CHECK_EQ(3, v->Int32Value());
8789 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8791 v8::HandleScope handle_scope(env1->GetIsolate());
8792 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8794 Local<Value> foo = v8_str("foo");
8795 Local<Value> bar = v8_str("bar");
8797 // Set to the same domain.
8798 env1->SetSecurityToken(foo);
8799 env2->SetSecurityToken(foo);
8801 env1->Global()->Set(v8_str("prop"), v8_num(3));
8802 env2->Global()->Set(v8_str("env1"), env1->Global());
8804 // env1.prop is enumerable in env2.
8805 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8807 Context::Scope scope_env2(env2);
8808 Local<Value> result = CompileRun(test);
8809 CHECK(result->IsTrue());
8812 // Change env2 to a different domain and test again.
8813 env2->SetSecurityToken(bar);
8815 Context::Scope scope_env2(env2);
8816 Local<Value> result = CompileRun(test);
8817 CHECK(result.IsEmpty());
8822 THREADED_TEST(CrossDomainForIn) {
8824 v8::HandleScope handle_scope(env1->GetIsolate());
8825 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8827 Local<Value> foo = v8_str("foo");
8828 Local<Value> bar = v8_str("bar");
8830 // Set to the same domain.
8831 env1->SetSecurityToken(foo);
8832 env2->SetSecurityToken(foo);
8834 env1->Global()->Set(v8_str("prop"), v8_num(3));
8835 env2->Global()->Set(v8_str("env1"), env1->Global());
8837 // Change env2 to a different domain and set env1's global object
8838 // as the __proto__ of an object in env2 and enumerate properties
8839 // in for-in. It shouldn't enumerate properties on env1's global
8841 env2->SetSecurityToken(bar);
8843 Context::Scope scope_env2(env2);
8844 Local<Value> result = CompileRun(
8846 " var obj = { '__proto__': env1 };"
8848 " for (var p in obj) {"
8849 " if (p == 'prop') return false;"
8856 CHECK(result->IsTrue());
8861 TEST(ContextDetachGlobal) {
8863 v8::HandleScope handle_scope(env1->GetIsolate());
8864 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8866 Local<v8::Object> global1 = env1->Global();
8868 Local<Value> foo = v8_str("foo");
8870 // Set to the same domain.
8871 env1->SetSecurityToken(foo);
8872 env2->SetSecurityToken(foo);
8877 // Create a function in env2 and add a reference to it in env1.
8878 Local<v8::Object> global2 = env2->Global();
8879 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8880 CompileRun("function getProp() {return prop;}");
8882 env1->Global()->Set(v8_str("getProp"),
8883 global2->Get(v8_str("getProp")));
8885 // Detach env2's global, and reuse the global object of env2
8887 env2->DetachGlobal();
8889 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8891 v8::Handle<v8::ObjectTemplate>(),
8893 env3->SetSecurityToken(v8_str("bar"));
8896 Local<v8::Object> global3 = env3->Global();
8897 CHECK_EQ(global2, global3);
8898 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8899 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8900 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8901 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8904 // Call getProp in env1, and it should return the value 1
8906 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8907 CHECK(get_prop->IsFunction());
8908 v8::TryCatch try_catch;
8909 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8910 CHECK(!try_catch.HasCaught());
8911 CHECK_EQ(1, r->Int32Value());
8914 // Check that env3 is not accessible from env1
8916 Local<Value> r = global3->Get(v8_str("prop2"));
8922 TEST(DetachGlobal) {
8924 v8::HandleScope scope(env1->GetIsolate());
8926 // Create second environment.
8927 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8929 Local<Value> foo = v8_str("foo");
8931 // Set same security token for env1 and env2.
8932 env1->SetSecurityToken(foo);
8933 env2->SetSecurityToken(foo);
8935 // Create a property on the global object in env2.
8937 v8::Context::Scope scope(env2);
8938 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8941 // Create a reference to env2 global from env1 global.
8942 env1->Global()->Set(v8_str("other"), env2->Global());
8944 // Check that we have access to other.p in env2 from env1.
8945 Local<Value> result = CompileRun("other.p");
8946 CHECK(result->IsInt32());
8947 CHECK_EQ(42, result->Int32Value());
8949 // Hold on to global from env2 and detach global from env2.
8950 Local<v8::Object> global2 = env2->Global();
8951 env2->DetachGlobal();
8953 // Check that the global has been detached. No other.p property can
8955 result = CompileRun("other.p");
8956 CHECK(result.IsEmpty());
8958 // Reuse global2 for env3.
8959 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8961 v8::Handle<v8::ObjectTemplate>(),
8963 CHECK_EQ(global2, env3->Global());
8965 // Start by using the same security token for env3 as for env1 and env2.
8966 env3->SetSecurityToken(foo);
8968 // Create a property on the global object in env3.
8970 v8::Context::Scope scope(env3);
8971 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8974 // Check that other.p is now the property in env3 and that we have access.
8975 result = CompileRun("other.p");
8976 CHECK(result->IsInt32());
8977 CHECK_EQ(24, result->Int32Value());
8979 // Change security token for env3 to something different from env1 and env2.
8980 env3->SetSecurityToken(v8_str("bar"));
8982 // Check that we do not have access to other.p in env1. |other| is now
8983 // the global object for env3 which has a different security token,
8984 // so access should be blocked.
8985 result = CompileRun("other.p");
8986 CHECK(result.IsEmpty());
8990 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8991 info.GetReturnValue().Set(
8992 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8996 TEST(DetachedAccesses) {
8998 v8::HandleScope scope(env1->GetIsolate());
9000 // Create second environment.
9001 Local<ObjectTemplate> inner_global_template =
9002 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9003 inner_global_template ->SetAccessorProperty(
9004 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9005 v8::Local<Context> env2 =
9006 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9008 Local<Value> foo = v8_str("foo");
9010 // Set same security token for env1 and env2.
9011 env1->SetSecurityToken(foo);
9012 env2->SetSecurityToken(foo);
9014 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9017 v8::Context::Scope scope(env2);
9018 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9020 "function bound_x() { return x; }"
9021 "function get_x() { return this.x; }"
9022 "function get_x_w() { return (function() {return this.x;})(); }");
9023 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9024 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9025 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9026 env1->Global()->Set(
9028 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9031 Local<Object> env2_global = env2->Global();
9032 env2_global->TurnOnAccessCheck();
9033 env2->DetachGlobal();
9035 Local<Value> result;
9036 result = CompileRun("bound_x()");
9037 CHECK_EQ(v8_str("env2_x"), result);
9038 result = CompileRun("get_x()");
9039 CHECK(result.IsEmpty());
9040 result = CompileRun("get_x_w()");
9041 CHECK(result.IsEmpty());
9042 result = CompileRun("this_x()");
9043 CHECK_EQ(v8_str("env2_x"), result);
9045 // Reattach env2's proxy
9046 env2 = Context::New(env1->GetIsolate(),
9048 v8::Handle<v8::ObjectTemplate>(),
9050 env2->SetSecurityToken(foo);
9052 v8::Context::Scope scope(env2);
9053 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9054 env2->Global()->Set(v8_str("env1"), env1->Global());
9055 result = CompileRun(
9057 "for (var i = 0; i < 4; i++ ) {"
9058 " results.push(env1.bound_x());"
9059 " results.push(env1.get_x());"
9060 " results.push(env1.get_x_w());"
9061 " results.push(env1.this_x());"
9064 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9065 CHECK_EQ(16, results->Length());
9066 for (int i = 0; i < 16; i += 4) {
9067 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9068 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9069 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9070 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9074 result = CompileRun(
9076 "for (var i = 0; i < 4; i++ ) {"
9077 " results.push(bound_x());"
9078 " results.push(get_x());"
9079 " results.push(get_x_w());"
9080 " results.push(this_x());"
9083 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9084 CHECK_EQ(16, results->Length());
9085 for (int i = 0; i < 16; i += 4) {
9086 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9087 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9088 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9089 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9092 result = CompileRun(
9094 "for (var i = 0; i < 4; i++ ) {"
9095 " results.push(this.bound_x());"
9096 " results.push(this.get_x());"
9097 " results.push(this.get_x_w());"
9098 " results.push(this.this_x());"
9101 results = Local<v8::Array>::Cast(result);
9102 CHECK_EQ(16, results->Length());
9103 for (int i = 0; i < 16; i += 4) {
9104 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9105 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9106 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9107 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9112 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9113 static bool NamedAccessBlocker(Local<v8::Object> global,
9115 v8::AccessType type,
9116 Local<Value> data) {
9117 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9118 allowed_access_type[type];
9122 static bool IndexedAccessBlocker(Local<v8::Object> global,
9124 v8::AccessType type,
9125 Local<Value> data) {
9126 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9127 allowed_access_type[type];
9131 static int g_echo_value = -1;
9134 static void EchoGetter(
9136 const v8::PropertyCallbackInfo<v8::Value>& info) {
9137 info.GetReturnValue().Set(v8_num(g_echo_value));
9141 static void EchoSetter(Local<String> name,
9143 const v8::PropertyCallbackInfo<void>&) {
9144 if (value->IsNumber())
9145 g_echo_value = value->Int32Value();
9149 static void UnreachableGetter(
9151 const v8::PropertyCallbackInfo<v8::Value>& info) {
9152 CHECK(false); // This function should not be called..
9156 static void UnreachableSetter(Local<String>,
9158 const v8::PropertyCallbackInfo<void>&) {
9159 CHECK(false); // This function should nto be called.
9163 static void UnreachableFunction(
9164 const v8::FunctionCallbackInfo<v8::Value>& info) {
9165 CHECK(false); // This function should not be called..
9169 TEST(AccessControl) {
9170 v8::Isolate* isolate = CcTest::isolate();
9171 v8::HandleScope handle_scope(isolate);
9172 v8::Handle<v8::ObjectTemplate> global_template =
9173 v8::ObjectTemplate::New(isolate);
9175 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9176 IndexedAccessBlocker);
9178 // Add an accessor accessible by cross-domain JS code.
9179 global_template->SetAccessor(
9180 v8_str("accessible_prop"),
9181 EchoGetter, EchoSetter,
9182 v8::Handle<Value>(),
9183 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9186 // Add an accessor that is not accessible by cross-domain JS code.
9187 global_template->SetAccessor(v8_str("blocked_prop"),
9188 UnreachableGetter, UnreachableSetter,
9189 v8::Handle<Value>(),
9192 global_template->SetAccessorProperty(
9193 v8_str("blocked_js_prop"),
9194 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9195 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9199 // Create an environment
9200 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9203 v8::Handle<v8::Object> global0 = context0->Global();
9205 // Define a property with JS getter and setter.
9207 "function getter() { return 'getter'; };\n"
9208 "function setter() { return 'setter'; }\n"
9209 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9211 Local<Value> getter = global0->Get(v8_str("getter"));
9212 Local<Value> setter = global0->Get(v8_str("setter"));
9214 // And define normal element.
9215 global0->Set(239, v8_str("239"));
9217 // Define an element with JS getter and setter.
9219 "function el_getter() { return 'el_getter'; };\n"
9220 "function el_setter() { return 'el_setter'; };\n"
9221 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9223 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9224 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9226 v8::HandleScope scope1(isolate);
9228 v8::Local<Context> context1 = Context::New(isolate);
9231 v8::Handle<v8::Object> global1 = context1->Global();
9232 global1->Set(v8_str("other"), global0);
9234 // Access blocked property.
9235 CompileRun("other.blocked_prop = 1");
9237 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9238 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9241 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9243 // Access blocked element.
9244 CHECK(CompileRun("other[239] = 1").IsEmpty());
9246 CHECK(CompileRun("other[239]").IsEmpty());
9247 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9248 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9250 // Enable ACCESS_HAS
9251 allowed_access_type[v8::ACCESS_HAS] = true;
9252 CHECK(CompileRun("other[239]").IsEmpty());
9253 // ... and now we can get the descriptor...
9254 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9256 // ... and enumerate the property.
9257 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9258 allowed_access_type[v8::ACCESS_HAS] = false;
9260 // Access a property with JS accessor.
9261 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9263 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9264 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9267 // Enable both ACCESS_HAS and ACCESS_GET.
9268 allowed_access_type[v8::ACCESS_HAS] = true;
9269 allowed_access_type[v8::ACCESS_GET] = true;
9271 ExpectString("other.js_accessor_p", "getter");
9273 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9275 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9277 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9279 allowed_access_type[v8::ACCESS_HAS] = false;
9280 allowed_access_type[v8::ACCESS_GET] = false;
9282 // Access an element with JS accessor.
9283 CHECK(CompileRun("other[42] = 2").IsEmpty());
9285 CHECK(CompileRun("other[42]").IsEmpty());
9286 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9288 // Enable both ACCESS_HAS and ACCESS_GET.
9289 allowed_access_type[v8::ACCESS_HAS] = true;
9290 allowed_access_type[v8::ACCESS_GET] = true;
9292 ExpectString("other[42]", "el_getter");
9293 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9294 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9295 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9297 allowed_access_type[v8::ACCESS_HAS] = false;
9298 allowed_access_type[v8::ACCESS_GET] = false;
9300 v8::Handle<Value> value;
9302 // Access accessible property
9303 value = CompileRun("other.accessible_prop = 3");
9304 CHECK(value->IsNumber());
9305 CHECK_EQ(3, value->Int32Value());
9306 CHECK_EQ(3, g_echo_value);
9308 value = CompileRun("other.accessible_prop");
9309 CHECK(value->IsNumber());
9310 CHECK_EQ(3, value->Int32Value());
9313 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9314 CHECK(value->IsNumber());
9315 CHECK_EQ(3, value->Int32Value());
9317 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9318 CHECK(value->IsTrue());
9320 // Enumeration doesn't enumerate accessors from inaccessible objects in
9321 // the prototype chain even if the accessors are in themselves accessible.
9324 " var obj = { '__proto__': other };"
9326 " for (var p in obj) {"
9327 " if (p == 'accessible_prop' ||"
9328 " p == 'blocked_js_prop' ||"
9329 " p == 'blocked_js_prop') {"
9338 CHECK(value->IsTrue());
9345 TEST(AccessControlES5) {
9346 v8::Isolate* isolate = CcTest::isolate();
9347 v8::HandleScope handle_scope(isolate);
9348 v8::Handle<v8::ObjectTemplate> global_template =
9349 v8::ObjectTemplate::New(isolate);
9351 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9352 IndexedAccessBlocker);
9354 // Add accessible accessor.
9355 global_template->SetAccessor(
9356 v8_str("accessible_prop"),
9357 EchoGetter, EchoSetter,
9358 v8::Handle<Value>(),
9359 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9362 // Add an accessor that is not accessible by cross-domain JS code.
9363 global_template->SetAccessor(v8_str("blocked_prop"),
9364 UnreachableGetter, UnreachableSetter,
9365 v8::Handle<Value>(),
9368 // Create an environment
9369 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9372 v8::Handle<v8::Object> global0 = context0->Global();
9374 v8::Local<Context> context1 = Context::New(isolate);
9376 v8::Handle<v8::Object> global1 = context1->Global();
9377 global1->Set(v8_str("other"), global0);
9379 // Regression test for issue 1154.
9380 CHECK(CompileRun("Object.keys(other)").IsEmpty());
9381 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9383 // Regression test for issue 1027.
9384 CompileRun("Object.defineProperty(\n"
9385 " other, 'blocked_prop', {configurable: false})");
9386 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9387 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9390 // Regression test for issue 1171.
9391 ExpectTrue("Object.isExtensible(other)");
9392 CompileRun("Object.preventExtensions(other)");
9393 ExpectTrue("Object.isExtensible(other)");
9395 // Object.seal and Object.freeze.
9396 CompileRun("Object.freeze(other)");
9397 ExpectTrue("Object.isExtensible(other)");
9399 CompileRun("Object.seal(other)");
9400 ExpectTrue("Object.isExtensible(other)");
9402 // Regression test for issue 1250.
9403 // Make sure that we can set the accessible accessors value using normal
9405 CompileRun("other.accessible_prop = 42");
9406 CHECK_EQ(42, g_echo_value);
9408 v8::Handle<Value> value;
9409 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9410 value = CompileRun("other.accessible_prop == 42");
9411 CHECK(value->IsTrue());
9415 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9417 v8::AccessType type,
9418 Local<Value> data) {
9423 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9425 v8::AccessType type,
9426 Local<Value> data) {
9431 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9432 v8::Isolate* isolate = CcTest::isolate();
9433 v8::HandleScope handle_scope(isolate);
9434 v8::Handle<v8::ObjectTemplate> obj_template =
9435 v8::ObjectTemplate::New(isolate);
9437 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9438 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9439 GetOwnPropertyNamesIndexedBlocker);
9441 // Create an environment
9442 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9445 v8::Handle<v8::Object> global0 = context0->Global();
9447 v8::HandleScope scope1(CcTest::isolate());
9449 v8::Local<Context> context1 = Context::New(isolate);
9452 v8::Handle<v8::Object> global1 = context1->Global();
9453 global1->Set(v8_str("other"), global0);
9454 global1->Set(v8_str("object"), obj_template->NewInstance());
9456 v8::Handle<Value> value;
9458 // Attempt to get the property names of the other global object and
9459 // of an object that requires access checks. Accessing the other
9460 // global object should be blocked by access checks on the global
9461 // proxy object. Accessing the object that requires access checks
9462 // is blocked by the access checks on the object itself.
9463 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9464 CHECK(value.IsEmpty());
9466 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9467 CHECK(value.IsEmpty());
9474 static void IndexedPropertyEnumerator(
9475 const v8::PropertyCallbackInfo<v8::Array>& info) {
9476 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9477 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9478 result->Set(1, v8::Object::New(info.GetIsolate()));
9479 info.GetReturnValue().Set(result);
9483 static void NamedPropertyEnumerator(
9484 const v8::PropertyCallbackInfo<v8::Array>& info) {
9485 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9486 result->Set(0, v8_str("x"));
9487 result->Set(1, v8::Object::New(info.GetIsolate()));
9488 info.GetReturnValue().Set(result);
9492 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9493 v8::Isolate* isolate = CcTest::isolate();
9494 v8::HandleScope handle_scope(isolate);
9495 v8::Handle<v8::ObjectTemplate> obj_template =
9496 v8::ObjectTemplate::New(isolate);
9498 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9499 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9500 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9501 IndexedPropertyEnumerator);
9502 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9503 NamedPropertyEnumerator);
9505 LocalContext context;
9506 v8::Handle<v8::Object> global = context->Global();
9507 global->Set(v8_str("object"), obj_template->NewInstance());
9509 v8::Handle<v8::Value> result =
9510 CompileRun("Object.getOwnPropertyNames(object)");
9511 CHECK(result->IsArray());
9512 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9513 CHECK_EQ(3, result_array->Length());
9514 CHECK(result_array->Get(0)->IsString());
9515 CHECK(result_array->Get(1)->IsString());
9516 CHECK(result_array->Get(2)->IsString());
9517 CHECK_EQ(v8_str("7"), result_array->Get(0));
9518 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9519 CHECK_EQ(v8_str("x"), result_array->Get(2));
9523 static void ConstTenGetter(Local<String> name,
9524 const v8::PropertyCallbackInfo<v8::Value>& info) {
9525 info.GetReturnValue().Set(v8_num(10));
9529 THREADED_TEST(CrossDomainAccessors) {
9530 v8::Isolate* isolate = CcTest::isolate();
9531 v8::HandleScope handle_scope(isolate);
9533 v8::Handle<v8::FunctionTemplate> func_template =
9534 v8::FunctionTemplate::New(isolate);
9536 v8::Handle<v8::ObjectTemplate> global_template =
9537 func_template->InstanceTemplate();
9539 v8::Handle<v8::ObjectTemplate> proto_template =
9540 func_template->PrototypeTemplate();
9542 // Add an accessor to proto that's accessible by cross-domain JS code.
9543 proto_template->SetAccessor(v8_str("accessible"),
9545 v8::Handle<Value>(),
9548 // Add an accessor that is not accessible by cross-domain JS code.
9549 global_template->SetAccessor(v8_str("unreachable"),
9550 UnreachableGetter, 0,
9551 v8::Handle<Value>(),
9554 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9557 Local<v8::Object> global = context0->Global();
9558 // Add a normal property that shadows 'accessible'
9559 global->Set(v8_str("accessible"), v8_num(11));
9561 // Enter a new context.
9562 v8::HandleScope scope1(CcTest::isolate());
9563 v8::Local<Context> context1 = Context::New(isolate);
9566 v8::Handle<v8::Object> global1 = context1->Global();
9567 global1->Set(v8_str("other"), global);
9569 // Should return 10, instead of 11
9570 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9571 CHECK(value->IsNumber());
9572 CHECK_EQ(10, value->Int32Value());
9574 value = v8_compile("other.unreachable")->Run();
9575 CHECK(value.IsEmpty());
9582 static int named_access_count = 0;
9583 static int indexed_access_count = 0;
9585 static bool NamedAccessCounter(Local<v8::Object> global,
9587 v8::AccessType type,
9588 Local<Value> data) {
9589 named_access_count++;
9594 static bool IndexedAccessCounter(Local<v8::Object> global,
9596 v8::AccessType type,
9597 Local<Value> data) {
9598 indexed_access_count++;
9603 // This one is too easily disturbed by other tests.
9604 TEST(AccessControlIC) {
9605 named_access_count = 0;
9606 indexed_access_count = 0;
9608 v8::Isolate* isolate = CcTest::isolate();
9609 v8::HandleScope handle_scope(isolate);
9611 // Create an environment.
9612 v8::Local<Context> context0 = Context::New(isolate);
9615 // Create an object that requires access-check functions to be
9616 // called for cross-domain access.
9617 v8::Handle<v8::ObjectTemplate> object_template =
9618 v8::ObjectTemplate::New(isolate);
9619 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9620 IndexedAccessCounter);
9621 Local<v8::Object> object = object_template->NewInstance();
9623 v8::HandleScope scope1(isolate);
9625 // Create another environment.
9626 v8::Local<Context> context1 = Context::New(isolate);
9629 // Make easy access to the object from the other environment.
9630 v8::Handle<v8::Object> global1 = context1->Global();
9631 global1->Set(v8_str("obj"), object);
9633 v8::Handle<Value> value;
9635 // Check that the named access-control function is called every time.
9636 CompileRun("function testProp(obj) {"
9637 " for (var i = 0; i < 10; i++) obj.prop = 1;"
9638 " for (var j = 0; j < 10; j++) obj.prop;"
9641 value = CompileRun("testProp(obj)");
9642 CHECK(value->IsNumber());
9643 CHECK_EQ(1, value->Int32Value());
9644 CHECK_EQ(21, named_access_count);
9646 // Check that the named access-control function is called every time.
9647 CompileRun("var p = 'prop';"
9648 "function testKeyed(obj) {"
9649 " for (var i = 0; i < 10; i++) obj[p] = 1;"
9650 " for (var j = 0; j < 10; j++) obj[p];"
9653 // Use obj which requires access checks. No inline caching is used
9655 value = CompileRun("testKeyed(obj)");
9656 CHECK(value->IsNumber());
9657 CHECK_EQ(1, value->Int32Value());
9658 CHECK_EQ(42, named_access_count);
9659 // Force the inline caches into generic state and try again.
9660 CompileRun("testKeyed({ a: 0 })");
9661 CompileRun("testKeyed({ b: 0 })");
9662 value = CompileRun("testKeyed(obj)");
9663 CHECK(value->IsNumber());
9664 CHECK_EQ(1, value->Int32Value());
9665 CHECK_EQ(63, named_access_count);
9667 // Check that the indexed access-control function is called every time.
9668 CompileRun("function testIndexed(obj) {"
9669 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9670 " for (var j = 0; j < 10; j++) obj[0];"
9673 value = CompileRun("testIndexed(obj)");
9674 CHECK(value->IsNumber());
9675 CHECK_EQ(1, value->Int32Value());
9676 CHECK_EQ(21, indexed_access_count);
9677 // Force the inline caches into generic state.
9678 CompileRun("testIndexed(new Array(1))");
9679 // Test that the indexed access check is called.
9680 value = CompileRun("testIndexed(obj)");
9681 CHECK(value->IsNumber());
9682 CHECK_EQ(1, value->Int32Value());
9683 CHECK_EQ(42, indexed_access_count);
9685 // Check that the named access check is called when invoking
9686 // functions on an object that requires access checks.
9687 CompileRun("obj.f = function() {}");
9688 CompileRun("function testCallNormal(obj) {"
9689 " for (var i = 0; i < 10; i++) obj.f();"
9691 CompileRun("testCallNormal(obj)");
9692 CHECK_EQ(74, named_access_count);
9694 // Force obj into slow case.
9695 value = CompileRun("delete obj.prop");
9696 CHECK(value->BooleanValue());
9697 // Force inline caches into dictionary probing mode.
9698 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9699 // Test that the named access check is called.
9700 value = CompileRun("testProp(obj);");
9701 CHECK(value->IsNumber());
9702 CHECK_EQ(1, value->Int32Value());
9703 CHECK_EQ(96, named_access_count);
9705 // Force the call inline cache into dictionary probing mode.
9706 CompileRun("o.f = function() {}; testCallNormal(o)");
9707 // Test that the named access check is still called for each
9708 // invocation of the function.
9709 value = CompileRun("testCallNormal(obj)");
9710 CHECK_EQ(106, named_access_count);
9717 static bool NamedAccessFlatten(Local<v8::Object> global,
9719 v8::AccessType type,
9720 Local<Value> data) {
9724 CHECK(name->IsString());
9726 memset(buf, 0x1, sizeof(buf));
9727 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9732 memset(buf, 0x1, sizeof(buf));
9733 len = name.As<String>()->Write(buf2);
9740 static bool IndexedAccessFlatten(Local<v8::Object> global,
9742 v8::AccessType type,
9743 Local<Value> data) {
9748 // Regression test. In access checks, operations that may cause
9749 // garbage collection are not allowed. It used to be the case that
9750 // using the Write operation on a string could cause a garbage
9751 // collection due to flattening of the string. This is no longer the
9753 THREADED_TEST(AccessControlFlatten) {
9754 named_access_count = 0;
9755 indexed_access_count = 0;
9757 v8::Isolate* isolate = CcTest::isolate();
9758 v8::HandleScope handle_scope(isolate);
9760 // Create an environment.
9761 v8::Local<Context> context0 = Context::New(isolate);
9764 // Create an object that requires access-check functions to be
9765 // called for cross-domain access.
9766 v8::Handle<v8::ObjectTemplate> object_template =
9767 v8::ObjectTemplate::New(isolate);
9768 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9769 IndexedAccessFlatten);
9770 Local<v8::Object> object = object_template->NewInstance();
9772 v8::HandleScope scope1(isolate);
9774 // Create another environment.
9775 v8::Local<Context> context1 = Context::New(isolate);
9778 // Make easy access to the object from the other environment.
9779 v8::Handle<v8::Object> global1 = context1->Global();
9780 global1->Set(v8_str("obj"), object);
9782 v8::Handle<Value> value;
9784 value = v8_compile("var p = 'as' + 'df';")->Run();
9785 value = v8_compile("obj[p];")->Run();
9792 static void AccessControlNamedGetter(
9794 const v8::PropertyCallbackInfo<v8::Value>& info) {
9795 info.GetReturnValue().Set(42);
9799 static void AccessControlNamedSetter(
9802 const v8::PropertyCallbackInfo<v8::Value>& info) {
9803 info.GetReturnValue().Set(value);
9807 static void AccessControlIndexedGetter(
9809 const v8::PropertyCallbackInfo<v8::Value>& info) {
9810 info.GetReturnValue().Set(v8_num(42));
9814 static void AccessControlIndexedSetter(
9817 const v8::PropertyCallbackInfo<v8::Value>& info) {
9818 info.GetReturnValue().Set(value);
9822 THREADED_TEST(AccessControlInterceptorIC) {
9823 named_access_count = 0;
9824 indexed_access_count = 0;
9826 v8::Isolate* isolate = CcTest::isolate();
9827 v8::HandleScope handle_scope(isolate);
9829 // Create an environment.
9830 v8::Local<Context> context0 = Context::New(isolate);
9833 // Create an object that requires access-check functions to be
9834 // called for cross-domain access. The object also has interceptors
9836 v8::Handle<v8::ObjectTemplate> object_template =
9837 v8::ObjectTemplate::New(isolate);
9838 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9839 IndexedAccessCounter);
9840 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9841 AccessControlNamedSetter);
9842 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9843 AccessControlIndexedSetter);
9844 Local<v8::Object> object = object_template->NewInstance();
9846 v8::HandleScope scope1(isolate);
9848 // Create another environment.
9849 v8::Local<Context> context1 = Context::New(isolate);
9852 // Make easy access to the object from the other environment.
9853 v8::Handle<v8::Object> global1 = context1->Global();
9854 global1->Set(v8_str("obj"), object);
9856 v8::Handle<Value> value;
9858 // Check that the named access-control function is called every time
9859 // eventhough there is an interceptor on the object.
9860 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9861 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9863 CHECK(value->IsNumber());
9864 CHECK_EQ(42, value->Int32Value());
9865 CHECK_EQ(21, named_access_count);
9867 value = v8_compile("var p = 'x';")->Run();
9868 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9869 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9871 CHECK(value->IsNumber());
9872 CHECK_EQ(42, value->Int32Value());
9873 CHECK_EQ(42, named_access_count);
9875 // Check that the indexed access-control function is called every
9876 // time eventhough there is an interceptor on the object.
9877 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9878 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9880 CHECK(value->IsNumber());
9881 CHECK_EQ(42, value->Int32Value());
9882 CHECK_EQ(21, indexed_access_count);
9889 THREADED_TEST(Version) {
9890 v8::V8::GetVersion();
9894 static void InstanceFunctionCallback(
9895 const v8::FunctionCallbackInfo<v8::Value>& args) {
9896 ApiTestFuzzer::Fuzz();
9897 args.GetReturnValue().Set(v8_num(12));
9901 THREADED_TEST(InstanceProperties) {
9902 LocalContext context;
9903 v8::Isolate* isolate = context->GetIsolate();
9904 v8::HandleScope handle_scope(isolate);
9906 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9907 Local<ObjectTemplate> instance = t->InstanceTemplate();
9909 instance->Set(v8_str("x"), v8_num(42));
9910 instance->Set(v8_str("f"),
9911 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9913 Local<Value> o = t->GetFunction()->NewInstance();
9915 context->Global()->Set(v8_str("i"), o);
9916 Local<Value> value = CompileRun("i.x");
9917 CHECK_EQ(42, value->Int32Value());
9919 value = CompileRun("i.f()");
9920 CHECK_EQ(12, value->Int32Value());
9924 static void GlobalObjectInstancePropertiesGet(
9926 const v8::PropertyCallbackInfo<v8::Value>&) {
9927 ApiTestFuzzer::Fuzz();
9931 THREADED_TEST(GlobalObjectInstanceProperties) {
9932 v8::Isolate* isolate = CcTest::isolate();
9933 v8::HandleScope handle_scope(isolate);
9935 Local<Value> global_object;
9937 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9938 t->InstanceTemplate()->SetNamedPropertyHandler(
9939 GlobalObjectInstancePropertiesGet);
9940 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9941 instance_template->Set(v8_str("x"), v8_num(42));
9942 instance_template->Set(v8_str("f"),
9943 v8::FunctionTemplate::New(isolate,
9944 InstanceFunctionCallback));
9946 // The script to check how Crankshaft compiles missing global function
9947 // invocations. function g is not defined and should throw on call.
9948 const char* script =
9949 "function wrapper(call) {"
9950 " var x = 0, y = 1;"
9951 " for (var i = 0; i < 1000; i++) {"
9957 "for (var i = 0; i < 17; i++) wrapper(false);"
9959 "try { wrapper(true); } catch (e) { thrown = 1; };"
9963 LocalContext env(NULL, instance_template);
9964 // Hold on to the global object so it can be used again in another
9965 // environment initialization.
9966 global_object = env->Global();
9968 Local<Value> value = CompileRun("x");
9969 CHECK_EQ(42, value->Int32Value());
9970 value = CompileRun("f()");
9971 CHECK_EQ(12, value->Int32Value());
9972 value = CompileRun(script);
9973 CHECK_EQ(1, value->Int32Value());
9977 // Create new environment reusing the global object.
9978 LocalContext env(NULL, instance_template, global_object);
9979 Local<Value> value = CompileRun("x");
9980 CHECK_EQ(42, value->Int32Value());
9981 value = CompileRun("f()");
9982 CHECK_EQ(12, value->Int32Value());
9983 value = CompileRun(script);
9984 CHECK_EQ(1, value->Int32Value());
9989 THREADED_TEST(CallKnownGlobalReceiver) {
9990 v8::Isolate* isolate = CcTest::isolate();
9991 v8::HandleScope handle_scope(isolate);
9993 Local<Value> global_object;
9995 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9996 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9998 // The script to check that we leave global object not
9999 // global object proxy on stack when we deoptimize from inside
10000 // arguments evaluation.
10001 // To provoke error we need to both force deoptimization
10002 // from arguments evaluation and to force CallIC to take
10003 // CallIC_Miss code path that can't cope with global proxy.
10004 const char* script =
10005 "function bar(x, y) { try { } finally { } }"
10006 "function baz(x) { try { } finally { } }"
10007 "function bom(x) { try { } finally { } }"
10008 "function foo(x) { bar([x], bom(2)); }"
10009 "for (var i = 0; i < 10000; i++) foo(1);"
10014 LocalContext env(NULL, instance_template);
10015 // Hold on to the global object so it can be used again in another
10016 // environment initialization.
10017 global_object = env->Global();
10018 foo = CompileRun(script);
10022 // Create new environment reusing the global object.
10023 LocalContext env(NULL, instance_template, global_object);
10024 env->Global()->Set(v8_str("foo"), foo);
10025 CompileRun("foo()");
10030 static void ShadowFunctionCallback(
10031 const v8::FunctionCallbackInfo<v8::Value>& args) {
10032 ApiTestFuzzer::Fuzz();
10033 args.GetReturnValue().Set(v8_num(42));
10037 static int shadow_y;
10038 static int shadow_y_setter_call_count;
10039 static int shadow_y_getter_call_count;
10042 static void ShadowYSetter(Local<String>,
10044 const v8::PropertyCallbackInfo<void>&) {
10045 shadow_y_setter_call_count++;
10050 static void ShadowYGetter(Local<String> name,
10051 const v8::PropertyCallbackInfo<v8::Value>& info) {
10052 ApiTestFuzzer::Fuzz();
10053 shadow_y_getter_call_count++;
10054 info.GetReturnValue().Set(v8_num(shadow_y));
10058 static void ShadowIndexedGet(uint32_t index,
10059 const v8::PropertyCallbackInfo<v8::Value>&) {
10063 static void ShadowNamedGet(Local<String> key,
10064 const v8::PropertyCallbackInfo<v8::Value>&) {
10068 THREADED_TEST(ShadowObject) {
10069 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10070 v8::Isolate* isolate = CcTest::isolate();
10071 v8::HandleScope handle_scope(isolate);
10073 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10074 LocalContext context(NULL, global_template);
10076 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10077 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10078 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10079 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10080 Local<ObjectTemplate> instance = t->InstanceTemplate();
10082 proto->Set(v8_str("f"),
10083 v8::FunctionTemplate::New(isolate,
10084 ShadowFunctionCallback,
10086 proto->Set(v8_str("x"), v8_num(12));
10088 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10090 Local<Value> o = t->GetFunction()->NewInstance();
10091 context->Global()->Set(v8_str("__proto__"), o);
10093 Local<Value> value =
10094 CompileRun("this.propertyIsEnumerable(0)");
10095 CHECK(value->IsBoolean());
10096 CHECK(!value->BooleanValue());
10098 value = CompileRun("x");
10099 CHECK_EQ(12, value->Int32Value());
10101 value = CompileRun("f()");
10102 CHECK_EQ(42, value->Int32Value());
10104 CompileRun("y = 43");
10105 CHECK_EQ(1, shadow_y_setter_call_count);
10106 value = CompileRun("y");
10107 CHECK_EQ(1, shadow_y_getter_call_count);
10108 CHECK_EQ(42, value->Int32Value());
10112 THREADED_TEST(HiddenPrototype) {
10113 LocalContext context;
10114 v8::Isolate* isolate = context->GetIsolate();
10115 v8::HandleScope handle_scope(isolate);
10117 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10118 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10119 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10120 t1->SetHiddenPrototype(true);
10121 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10122 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10123 t2->SetHiddenPrototype(true);
10124 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10125 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10126 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10128 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10129 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10130 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10131 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10133 // Setting the prototype on an object skips hidden prototypes.
10134 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10135 o0->Set(v8_str("__proto__"), o1);
10136 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10137 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10138 o0->Set(v8_str("__proto__"), o2);
10139 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10140 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10141 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10142 o0->Set(v8_str("__proto__"), o3);
10143 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10144 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10145 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10146 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10148 // Getting the prototype of o0 should get the first visible one
10149 // which is o3. Therefore, z should not be defined on the prototype
10151 Local<Value> proto = o0->Get(v8_str("__proto__"));
10152 CHECK(proto->IsObject());
10153 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10157 THREADED_TEST(HiddenPrototypeSet) {
10158 LocalContext context;
10159 v8::Isolate* isolate = context->GetIsolate();
10160 v8::HandleScope handle_scope(isolate);
10162 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10163 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10164 ht->SetHiddenPrototype(true);
10165 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10166 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10168 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10169 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10170 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10171 o->Set(v8_str("__proto__"), h);
10172 h->Set(v8_str("__proto__"), p);
10174 // Setting a property that exists on the hidden prototype goes there.
10175 o->Set(v8_str("x"), v8_num(7));
10176 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10177 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10178 CHECK(p->Get(v8_str("x"))->IsUndefined());
10180 // Setting a new property should not be forwarded to the hidden prototype.
10181 o->Set(v8_str("y"), v8_num(6));
10182 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10183 CHECK(h->Get(v8_str("y"))->IsUndefined());
10184 CHECK(p->Get(v8_str("y"))->IsUndefined());
10186 // Setting a property that only exists on a prototype of the hidden prototype
10187 // is treated normally again.
10188 p->Set(v8_str("z"), v8_num(8));
10189 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10190 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10191 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10192 o->Set(v8_str("z"), v8_num(9));
10193 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10194 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10195 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10199 // Regression test for issue 2457.
10200 THREADED_TEST(HiddenPrototypeIdentityHash) {
10201 LocalContext context;
10202 v8::HandleScope handle_scope(context->GetIsolate());
10204 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10205 t->SetHiddenPrototype(true);
10206 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10207 Handle<Object> p = t->GetFunction()->NewInstance();
10208 Handle<Object> o = Object::New(context->GetIsolate());
10209 o->SetPrototype(p);
10211 int hash = o->GetIdentityHash();
10213 o->Set(v8_str("foo"), v8_num(42));
10214 DCHECK_EQ(hash, o->GetIdentityHash());
10218 THREADED_TEST(SetPrototype) {
10219 LocalContext context;
10220 v8::Isolate* isolate = context->GetIsolate();
10221 v8::HandleScope handle_scope(isolate);
10223 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10224 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10225 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10226 t1->SetHiddenPrototype(true);
10227 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10228 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10229 t2->SetHiddenPrototype(true);
10230 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10231 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10232 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10234 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10235 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10236 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10237 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10239 // Setting the prototype on an object does not skip hidden prototypes.
10240 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10241 CHECK(o0->SetPrototype(o1));
10242 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10243 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10244 CHECK(o1->SetPrototype(o2));
10245 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10246 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10247 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10248 CHECK(o2->SetPrototype(o3));
10249 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10250 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10251 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10252 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10254 // Getting the prototype of o0 should get the first visible one
10255 // which is o3. Therefore, z should not be defined on the prototype
10257 Local<Value> proto = o0->Get(v8_str("__proto__"));
10258 CHECK(proto->IsObject());
10259 CHECK_EQ(proto.As<v8::Object>(), o3);
10261 // However, Object::GetPrototype ignores hidden prototype.
10262 Local<Value> proto0 = o0->GetPrototype();
10263 CHECK(proto0->IsObject());
10264 CHECK_EQ(proto0.As<v8::Object>(), o1);
10266 Local<Value> proto1 = o1->GetPrototype();
10267 CHECK(proto1->IsObject());
10268 CHECK_EQ(proto1.As<v8::Object>(), o2);
10270 Local<Value> proto2 = o2->GetPrototype();
10271 CHECK(proto2->IsObject());
10272 CHECK_EQ(proto2.As<v8::Object>(), o3);
10276 // Getting property names of an object with a prototype chain that
10277 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10278 // crash the runtime.
10279 THREADED_TEST(Regress91517) {
10280 i::FLAG_allow_natives_syntax = true;
10281 LocalContext context;
10282 v8::Isolate* isolate = context->GetIsolate();
10283 v8::HandleScope handle_scope(isolate);
10285 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10286 t1->SetHiddenPrototype(true);
10287 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10288 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10289 t2->SetHiddenPrototype(true);
10290 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10291 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10292 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10293 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10294 t3->SetHiddenPrototype(true);
10295 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10296 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10297 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10299 // Force dictionary-based properties.
10300 i::ScopedVector<char> name_buf(1024);
10301 for (int i = 1; i <= 1000; i++) {
10302 i::SNPrintF(name_buf, "sdf%d", i);
10303 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10306 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10307 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10308 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10309 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10311 // Create prototype chain of hidden prototypes.
10312 CHECK(o4->SetPrototype(o3));
10313 CHECK(o3->SetPrototype(o2));
10314 CHECK(o2->SetPrototype(o1));
10316 // Call the runtime version of GetOwnPropertyNames() on the natively
10317 // created object through JavaScript.
10318 context->Global()->Set(v8_str("obj"), o4);
10319 // PROPERTY_ATTRIBUTES_NONE = 0
10320 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10322 ExpectInt32("names.length", 1006);
10323 ExpectTrue("names.indexOf(\"baz\") >= 0");
10324 ExpectTrue("names.indexOf(\"boo\") >= 0");
10325 ExpectTrue("names.indexOf(\"foo\") >= 0");
10326 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10327 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10328 ExpectFalse("names[1005] == undefined");
10332 // Getting property names of an object with a hidden and inherited
10333 // prototype should not duplicate the accessor properties inherited.
10334 THREADED_TEST(Regress269562) {
10335 i::FLAG_allow_natives_syntax = true;
10336 LocalContext context;
10337 v8::HandleScope handle_scope(context->GetIsolate());
10339 Local<v8::FunctionTemplate> t1 =
10340 v8::FunctionTemplate::New(context->GetIsolate());
10341 t1->SetHiddenPrototype(true);
10343 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10344 i1->SetAccessor(v8_str("foo"),
10345 SimpleAccessorGetter, SimpleAccessorSetter);
10346 i1->SetAccessor(v8_str("bar"),
10347 SimpleAccessorGetter, SimpleAccessorSetter);
10348 i1->SetAccessor(v8_str("baz"),
10349 SimpleAccessorGetter, SimpleAccessorSetter);
10350 i1->Set(v8_str("n1"), v8_num(1));
10351 i1->Set(v8_str("n2"), v8_num(2));
10353 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10354 Local<v8::FunctionTemplate> t2 =
10355 v8::FunctionTemplate::New(context->GetIsolate());
10356 t2->SetHiddenPrototype(true);
10358 // Inherit from t1 and mark prototype as hidden.
10360 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10362 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10363 CHECK(o2->SetPrototype(o1));
10365 v8::Local<v8::Symbol> sym =
10366 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10367 o1->Set(sym, v8_num(3));
10368 o1->SetHiddenValue(
10369 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10371 // Call the runtime version of GetOwnPropertyNames() on
10372 // the natively created object through JavaScript.
10373 context->Global()->Set(v8_str("obj"), o2);
10374 context->Global()->Set(v8_str("sym"), sym);
10375 // PROPERTY_ATTRIBUTES_NONE = 0
10376 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10378 ExpectInt32("names.length", 7);
10379 ExpectTrue("names.indexOf(\"foo\") >= 0");
10380 ExpectTrue("names.indexOf(\"bar\") >= 0");
10381 ExpectTrue("names.indexOf(\"baz\") >= 0");
10382 ExpectTrue("names.indexOf(\"n1\") >= 0");
10383 ExpectTrue("names.indexOf(\"n2\") >= 0");
10384 ExpectTrue("names.indexOf(sym) >= 0");
10385 ExpectTrue("names.indexOf(\"mine\") >= 0");
10389 THREADED_TEST(FunctionReadOnlyPrototype) {
10390 LocalContext context;
10391 v8::Isolate* isolate = context->GetIsolate();
10392 v8::HandleScope handle_scope(isolate);
10394 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10395 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10396 t1->ReadOnlyPrototype();
10397 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10398 // Configured value of ReadOnly flag.
10401 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10402 " return (descriptor['writable'] == false);"
10403 "})()")->BooleanValue());
10404 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10406 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10408 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10409 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10410 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10411 // Default value of ReadOnly flag.
10414 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10415 " return (descriptor['writable'] == true);"
10416 "})()")->BooleanValue());
10417 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10421 THREADED_TEST(SetPrototypeThrows) {
10422 LocalContext context;
10423 v8::Isolate* isolate = context->GetIsolate();
10424 v8::HandleScope handle_scope(isolate);
10426 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10428 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10429 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10431 CHECK(o0->SetPrototype(o1));
10432 // If setting the prototype leads to the cycle, SetPrototype should
10433 // return false and keep VM in sane state.
10434 v8::TryCatch try_catch;
10435 CHECK(!o1->SetPrototype(o0));
10436 CHECK(!try_catch.HasCaught());
10437 DCHECK(!CcTest::i_isolate()->has_pending_exception());
10439 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10443 THREADED_TEST(FunctionRemovePrototype) {
10444 LocalContext context;
10445 v8::Isolate* isolate = context->GetIsolate();
10446 v8::HandleScope handle_scope(isolate);
10448 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10449 t1->RemovePrototype();
10450 Local<v8::Function> fun = t1->GetFunction();
10451 context->Global()->Set(v8_str("fun"), fun);
10452 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10454 v8::TryCatch try_catch;
10455 CompileRun("new fun()");
10456 CHECK(try_catch.HasCaught());
10459 fun->NewInstance();
10460 CHECK(try_catch.HasCaught());
10464 THREADED_TEST(GetterSetterExceptions) {
10465 LocalContext context;
10466 v8::Isolate* isolate = context->GetIsolate();
10467 v8::HandleScope handle_scope(isolate);
10469 "function Foo() { };"
10470 "function Throw() { throw 5; };"
10472 "x.__defineSetter__('set', Throw);"
10473 "x.__defineGetter__('get', Throw);");
10474 Local<v8::Object> x =
10475 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10476 v8::TryCatch try_catch;
10477 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10478 x->Get(v8_str("get"));
10479 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10480 x->Get(v8_str("get"));
10481 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10482 x->Get(v8_str("get"));
10483 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10484 x->Get(v8_str("get"));
10488 THREADED_TEST(Constructor) {
10489 LocalContext context;
10490 v8::Isolate* isolate = context->GetIsolate();
10491 v8::HandleScope handle_scope(isolate);
10492 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10493 templ->SetClassName(v8_str("Fun"));
10494 Local<Function> cons = templ->GetFunction();
10495 context->Global()->Set(v8_str("Fun"), cons);
10496 Local<v8::Object> inst = cons->NewInstance();
10497 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10498 CHECK(obj->IsJSObject());
10499 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10500 CHECK(value->BooleanValue());
10504 static void ConstructorCallback(
10505 const v8::FunctionCallbackInfo<v8::Value>& args) {
10506 ApiTestFuzzer::Fuzz();
10507 Local<Object> This;
10509 if (args.IsConstructCall()) {
10510 Local<Object> Holder = args.Holder();
10511 This = Object::New(args.GetIsolate());
10512 Local<Value> proto = Holder->GetPrototype();
10513 if (proto->IsObject()) {
10514 This->SetPrototype(proto);
10517 This = args.This();
10520 This->Set(v8_str("a"), args[0]);
10521 args.GetReturnValue().Set(This);
10525 static void FakeConstructorCallback(
10526 const v8::FunctionCallbackInfo<v8::Value>& args) {
10527 ApiTestFuzzer::Fuzz();
10528 args.GetReturnValue().Set(args[0]);
10532 THREADED_TEST(ConstructorForObject) {
10533 LocalContext context;
10534 v8::Isolate* isolate = context->GetIsolate();
10535 v8::HandleScope handle_scope(isolate);
10537 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10538 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10539 Local<Object> instance = instance_template->NewInstance();
10540 context->Global()->Set(v8_str("obj"), instance);
10541 v8::TryCatch try_catch;
10542 Local<Value> value;
10543 CHECK(!try_catch.HasCaught());
10545 // Call the Object's constructor with a 32-bit signed integer.
10546 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10547 CHECK(!try_catch.HasCaught());
10548 CHECK(value->IsInt32());
10549 CHECK_EQ(28, value->Int32Value());
10551 Local<Value> args1[] = { v8_num(28) };
10552 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10553 CHECK(value_obj1->IsObject());
10554 Local<Object> object1 = Local<Object>::Cast(value_obj1);
10555 value = object1->Get(v8_str("a"));
10556 CHECK(value->IsInt32());
10557 CHECK(!try_catch.HasCaught());
10558 CHECK_EQ(28, value->Int32Value());
10560 // Call the Object's constructor with a String.
10561 value = CompileRun(
10562 "(function() { var o = new obj('tipli'); return o.a; })()");
10563 CHECK(!try_catch.HasCaught());
10564 CHECK(value->IsString());
10565 String::Utf8Value string_value1(value->ToString());
10566 CHECK_EQ("tipli", *string_value1);
10568 Local<Value> args2[] = { v8_str("tipli") };
10569 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10570 CHECK(value_obj2->IsObject());
10571 Local<Object> object2 = Local<Object>::Cast(value_obj2);
10572 value = object2->Get(v8_str("a"));
10573 CHECK(!try_catch.HasCaught());
10574 CHECK(value->IsString());
10575 String::Utf8Value string_value2(value->ToString());
10576 CHECK_EQ("tipli", *string_value2);
10578 // Call the Object's constructor with a Boolean.
10579 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10580 CHECK(!try_catch.HasCaught());
10581 CHECK(value->IsBoolean());
10582 CHECK_EQ(true, value->BooleanValue());
10584 Handle<Value> args3[] = { v8::True(isolate) };
10585 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10586 CHECK(value_obj3->IsObject());
10587 Local<Object> object3 = Local<Object>::Cast(value_obj3);
10588 value = object3->Get(v8_str("a"));
10589 CHECK(!try_catch.HasCaught());
10590 CHECK(value->IsBoolean());
10591 CHECK_EQ(true, value->BooleanValue());
10593 // Call the Object's constructor with undefined.
10594 Handle<Value> args4[] = { v8::Undefined(isolate) };
10595 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10596 CHECK(value_obj4->IsObject());
10597 Local<Object> object4 = Local<Object>::Cast(value_obj4);
10598 value = object4->Get(v8_str("a"));
10599 CHECK(!try_catch.HasCaught());
10600 CHECK(value->IsUndefined());
10602 // Call the Object's constructor with null.
10603 Handle<Value> args5[] = { v8::Null(isolate) };
10604 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10605 CHECK(value_obj5->IsObject());
10606 Local<Object> object5 = Local<Object>::Cast(value_obj5);
10607 value = object5->Get(v8_str("a"));
10608 CHECK(!try_catch.HasCaught());
10609 CHECK(value->IsNull());
10612 // Check exception handling when there is no constructor set for the Object.
10613 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10614 Local<Object> instance = instance_template->NewInstance();
10615 context->Global()->Set(v8_str("obj2"), instance);
10616 v8::TryCatch try_catch;
10617 Local<Value> value;
10618 CHECK(!try_catch.HasCaught());
10620 value = CompileRun("new obj2(28)");
10621 CHECK(try_catch.HasCaught());
10622 String::Utf8Value exception_value1(try_catch.Exception());
10623 CHECK_EQ("TypeError: object is not a function", *exception_value1);
10626 Local<Value> args[] = { v8_num(29) };
10627 value = instance->CallAsConstructor(1, args);
10628 CHECK(try_catch.HasCaught());
10629 String::Utf8Value exception_value2(try_catch.Exception());
10630 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10634 // Check the case when constructor throws exception.
10635 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10636 instance_template->SetCallAsFunctionHandler(ThrowValue);
10637 Local<Object> instance = instance_template->NewInstance();
10638 context->Global()->Set(v8_str("obj3"), instance);
10639 v8::TryCatch try_catch;
10640 Local<Value> value;
10641 CHECK(!try_catch.HasCaught());
10643 value = CompileRun("new obj3(22)");
10644 CHECK(try_catch.HasCaught());
10645 String::Utf8Value exception_value1(try_catch.Exception());
10646 CHECK_EQ("22", *exception_value1);
10649 Local<Value> args[] = { v8_num(23) };
10650 value = instance->CallAsConstructor(1, args);
10651 CHECK(try_catch.HasCaught());
10652 String::Utf8Value exception_value2(try_catch.Exception());
10653 CHECK_EQ("23", *exception_value2);
10657 // Check whether constructor returns with an object or non-object.
10658 { Local<FunctionTemplate> function_template =
10659 FunctionTemplate::New(isolate, FakeConstructorCallback);
10660 Local<Function> function = function_template->GetFunction();
10661 Local<Object> instance1 = function;
10662 context->Global()->Set(v8_str("obj4"), instance1);
10663 v8::TryCatch try_catch;
10664 Local<Value> value;
10665 CHECK(!try_catch.HasCaught());
10667 CHECK(instance1->IsObject());
10668 CHECK(instance1->IsFunction());
10670 value = CompileRun("new obj4(28)");
10671 CHECK(!try_catch.HasCaught());
10672 CHECK(value->IsObject());
10674 Local<Value> args1[] = { v8_num(28) };
10675 value = instance1->CallAsConstructor(1, args1);
10676 CHECK(!try_catch.HasCaught());
10677 CHECK(value->IsObject());
10679 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10680 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10681 Local<Object> instance2 = instance_template->NewInstance();
10682 context->Global()->Set(v8_str("obj5"), instance2);
10683 CHECK(!try_catch.HasCaught());
10685 CHECK(instance2->IsObject());
10686 CHECK(!instance2->IsFunction());
10688 value = CompileRun("new obj5(28)");
10689 CHECK(!try_catch.HasCaught());
10690 CHECK(!value->IsObject());
10692 Local<Value> args2[] = { v8_num(28) };
10693 value = instance2->CallAsConstructor(1, args2);
10694 CHECK(!try_catch.HasCaught());
10695 CHECK(!value->IsObject());
10700 THREADED_TEST(FunctionDescriptorException) {
10701 LocalContext context;
10702 v8::Isolate* isolate = context->GetIsolate();
10703 v8::HandleScope handle_scope(isolate);
10704 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10705 templ->SetClassName(v8_str("Fun"));
10706 Local<Function> cons = templ->GetFunction();
10707 context->Global()->Set(v8_str("Fun"), cons);
10708 Local<Value> value = CompileRun(
10709 "function test() {"
10711 " (new Fun()).blah()"
10713 " var str = String(e);"
10714 // " if (str.indexOf('TypeError') == -1) return 1;"
10715 // " if (str.indexOf('[object Fun]') != -1) return 2;"
10716 // " if (str.indexOf('#<Fun>') == -1) return 3;"
10722 CHECK_EQ(0, value->Int32Value());
10726 THREADED_TEST(EvalAliasedDynamic) {
10727 LocalContext current;
10728 v8::HandleScope scope(current->GetIsolate());
10730 // Tests where aliased eval can only be resolved dynamically.
10731 Local<Script> script = v8_compile(
10734 " with (x) { return eval('foo'); }"
10737 "result1 = f(new Object());"
10738 "result2 = f(this);"
10739 "var x = new Object();"
10740 "x.eval = function(x) { return 1; };"
10741 "result3 = f(x);");
10743 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10744 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10745 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10747 v8::TryCatch try_catch;
10748 script = v8_compile(
10751 " with (x) { return eval('bar'); }"
10753 "result4 = f(this)");
10755 CHECK(!try_catch.HasCaught());
10756 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10762 THREADED_TEST(CrossEval) {
10763 v8::HandleScope scope(CcTest::isolate());
10764 LocalContext other;
10765 LocalContext current;
10767 Local<String> token = v8_str("<security token>");
10768 other->SetSecurityToken(token);
10769 current->SetSecurityToken(token);
10771 // Set up reference from current to other.
10772 current->Global()->Set(v8_str("other"), other->Global());
10774 // Check that new variables are introduced in other context.
10775 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10777 Local<Value> foo = other->Global()->Get(v8_str("foo"));
10778 CHECK_EQ(1234, foo->Int32Value());
10779 CHECK(!current->Global()->Has(v8_str("foo")));
10781 // Check that writing to non-existing properties introduces them in
10782 // the other context.
10783 script = v8_compile("other.eval('na = 1234')");
10785 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10786 CHECK(!current->Global()->Has(v8_str("na")));
10788 // Check that global variables in current context are not visible in other
10790 v8::TryCatch try_catch;
10791 script = v8_compile("var bar = 42; other.eval('bar');");
10792 Local<Value> result = script->Run();
10793 CHECK(try_catch.HasCaught());
10796 // Check that local variables in current context are not visible in other
10798 script = v8_compile(
10801 " return other.eval('baz');"
10803 result = script->Run();
10804 CHECK(try_catch.HasCaught());
10807 // Check that global variables in the other environment are visible
10808 // when evaluting code.
10809 other->Global()->Set(v8_str("bis"), v8_num(1234));
10810 script = v8_compile("other.eval('bis')");
10811 CHECK_EQ(1234, script->Run()->Int32Value());
10812 CHECK(!try_catch.HasCaught());
10814 // Check that the 'this' pointer points to the global object evaluating
10816 other->Global()->Set(v8_str("t"), other->Global());
10817 script = v8_compile("other.eval('this == t')");
10818 result = script->Run();
10819 CHECK(result->IsTrue());
10820 CHECK(!try_catch.HasCaught());
10822 // Check that variables introduced in with-statement are not visible in
10824 script = v8_compile("with({x:2}){other.eval('x')}");
10825 result = script->Run();
10826 CHECK(try_catch.HasCaught());
10829 // Check that you cannot use 'eval.call' with another object than the
10830 // current global object.
10831 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10832 result = script->Run();
10833 CHECK(try_catch.HasCaught());
10837 // Test that calling eval in a context which has been detached from
10838 // its global throws an exception. This behavior is consistent with
10839 // other JavaScript implementations.
10840 THREADED_TEST(EvalInDetachedGlobal) {
10841 v8::Isolate* isolate = CcTest::isolate();
10842 v8::HandleScope scope(isolate);
10844 v8::Local<Context> context0 = Context::New(isolate);
10845 v8::Local<Context> context1 = Context::New(isolate);
10847 // Set up function in context0 that uses eval from context0.
10849 v8::Handle<v8::Value> fun =
10850 CompileRun("var x = 42;"
10853 " return function(s) { return e(s); }"
10857 // Put the function into context1 and call it before and after
10858 // detaching the global. Before detaching, the call succeeds and
10859 // after detaching and exception is thrown.
10861 context1->Global()->Set(v8_str("fun"), fun);
10862 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10863 CHECK_EQ(42, x_value->Int32Value());
10864 context0->DetachGlobal();
10865 v8::TryCatch catcher;
10866 x_value = CompileRun("fun('x')");
10867 CHECK(x_value.IsEmpty());
10868 CHECK(catcher.HasCaught());
10873 THREADED_TEST(CrossLazyLoad) {
10874 v8::HandleScope scope(CcTest::isolate());
10875 LocalContext other;
10876 LocalContext current;
10878 Local<String> token = v8_str("<security token>");
10879 other->SetSecurityToken(token);
10880 current->SetSecurityToken(token);
10882 // Set up reference from current to other.
10883 current->Global()->Set(v8_str("other"), other->Global());
10885 // Trigger lazy loading in other context.
10886 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10887 Local<Value> value = script->Run();
10888 CHECK_EQ(42.0, value->NumberValue());
10892 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10893 ApiTestFuzzer::Fuzz();
10894 if (args.IsConstructCall()) {
10895 if (args[0]->IsInt32()) {
10896 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10901 args.GetReturnValue().Set(args[0]);
10905 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10906 args.GetReturnValue().Set(args.This());
10910 // Test that a call handler can be set for objects which will allow
10911 // non-function objects created through the API to be called as
10913 THREADED_TEST(CallAsFunction) {
10914 LocalContext context;
10915 v8::Isolate* isolate = context->GetIsolate();
10916 v8::HandleScope scope(isolate);
10918 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10919 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10920 instance_template->SetCallAsFunctionHandler(call_as_function);
10921 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10922 context->Global()->Set(v8_str("obj"), instance);
10923 v8::TryCatch try_catch;
10924 Local<Value> value;
10925 CHECK(!try_catch.HasCaught());
10927 value = CompileRun("obj(42)");
10928 CHECK(!try_catch.HasCaught());
10929 CHECK_EQ(42, value->Int32Value());
10931 value = CompileRun("(function(o){return o(49)})(obj)");
10932 CHECK(!try_catch.HasCaught());
10933 CHECK_EQ(49, value->Int32Value());
10935 // test special case of call as function
10936 value = CompileRun("[obj]['0'](45)");
10937 CHECK(!try_catch.HasCaught());
10938 CHECK_EQ(45, value->Int32Value());
10940 value = CompileRun("obj.call = Function.prototype.call;"
10941 "obj.call(null, 87)");
10942 CHECK(!try_catch.HasCaught());
10943 CHECK_EQ(87, value->Int32Value());
10945 // Regression tests for bug #1116356: Calling call through call/apply
10946 // must work for non-function receivers.
10947 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10948 value = CompileRun(apply_99);
10949 CHECK(!try_catch.HasCaught());
10950 CHECK_EQ(99, value->Int32Value());
10952 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10953 value = CompileRun(call_17);
10954 CHECK(!try_catch.HasCaught());
10955 CHECK_EQ(17, value->Int32Value());
10957 // Check that the call-as-function handler can be called through
10959 value = CompileRun("new obj(43)");
10960 CHECK(!try_catch.HasCaught());
10961 CHECK_EQ(-43, value->Int32Value());
10963 // Check that the call-as-function handler can be called through
10965 v8::Handle<Value> args[] = { v8_num(28) };
10966 value = instance->CallAsFunction(instance, 1, args);
10967 CHECK(!try_catch.HasCaught());
10968 CHECK_EQ(28, value->Int32Value());
10971 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10972 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10973 USE(instance_template);
10974 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10975 context->Global()->Set(v8_str("obj2"), instance);
10976 v8::TryCatch try_catch;
10977 Local<Value> value;
10978 CHECK(!try_catch.HasCaught());
10980 // Call an object without call-as-function handler through the JS
10981 value = CompileRun("obj2(28)");
10982 CHECK(value.IsEmpty());
10983 CHECK(try_catch.HasCaught());
10984 String::Utf8Value exception_value1(try_catch.Exception());
10985 // TODO(verwaest): Better message
10986 CHECK_EQ("TypeError: object is not a function",
10987 *exception_value1);
10990 // Call an object without call-as-function handler through the API
10991 value = CompileRun("obj2(28)");
10992 v8::Handle<Value> args[] = { v8_num(28) };
10993 value = instance->CallAsFunction(instance, 1, args);
10994 CHECK(value.IsEmpty());
10995 CHECK(try_catch.HasCaught());
10996 String::Utf8Value exception_value2(try_catch.Exception());
10997 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11001 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11002 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11003 instance_template->SetCallAsFunctionHandler(ThrowValue);
11004 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11005 context->Global()->Set(v8_str("obj3"), instance);
11006 v8::TryCatch try_catch;
11007 Local<Value> value;
11008 CHECK(!try_catch.HasCaught());
11010 // Catch the exception which is thrown by call-as-function handler
11011 value = CompileRun("obj3(22)");
11012 CHECK(try_catch.HasCaught());
11013 String::Utf8Value exception_value1(try_catch.Exception());
11014 CHECK_EQ("22", *exception_value1);
11017 v8::Handle<Value> args[] = { v8_num(23) };
11018 value = instance->CallAsFunction(instance, 1, args);
11019 CHECK(try_catch.HasCaught());
11020 String::Utf8Value exception_value2(try_catch.Exception());
11021 CHECK_EQ("23", *exception_value2);
11025 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11026 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11027 instance_template->SetCallAsFunctionHandler(ReturnThis);
11028 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11030 Local<v8::Value> a1 =
11031 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11032 CHECK(a1->StrictEquals(instance));
11033 Local<v8::Value> a2 =
11034 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11035 CHECK(a2->StrictEquals(instance));
11036 Local<v8::Value> a3 =
11037 instance->CallAsFunction(v8_num(42), 0, NULL);
11038 CHECK(a3->StrictEquals(instance));
11039 Local<v8::Value> a4 =
11040 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11041 CHECK(a4->StrictEquals(instance));
11042 Local<v8::Value> a5 =
11043 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11044 CHECK(a5->StrictEquals(instance));
11048 "function ReturnThisSloppy() {"
11051 "function ReturnThisStrict() {"
11055 Local<Function> ReturnThisSloppy =
11056 Local<Function>::Cast(
11057 context->Global()->Get(v8_str("ReturnThisSloppy")));
11058 Local<Function> ReturnThisStrict =
11059 Local<Function>::Cast(
11060 context->Global()->Get(v8_str("ReturnThisStrict")));
11062 Local<v8::Value> a1 =
11063 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11064 CHECK(a1->StrictEquals(context->Global()));
11065 Local<v8::Value> a2 =
11066 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11067 CHECK(a2->StrictEquals(context->Global()));
11068 Local<v8::Value> a3 =
11069 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11070 CHECK(a3->IsNumberObject());
11071 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11072 Local<v8::Value> a4 =
11073 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11074 CHECK(a4->IsStringObject());
11075 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11076 Local<v8::Value> a5 =
11077 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11078 CHECK(a5->IsBooleanObject());
11079 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11081 Local<v8::Value> a6 =
11082 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11083 CHECK(a6->IsUndefined());
11084 Local<v8::Value> a7 =
11085 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11086 CHECK(a7->IsNull());
11087 Local<v8::Value> a8 =
11088 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11089 CHECK(a8->StrictEquals(v8_num(42)));
11090 Local<v8::Value> a9 =
11091 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11092 CHECK(a9->StrictEquals(v8_str("hello")));
11093 Local<v8::Value> a10 =
11094 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11095 CHECK(a10->StrictEquals(v8::True(isolate)));
11100 // Check whether a non-function object is callable.
11101 THREADED_TEST(CallableObject) {
11102 LocalContext context;
11103 v8::Isolate* isolate = context->GetIsolate();
11104 v8::HandleScope scope(isolate);
11106 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11107 instance_template->SetCallAsFunctionHandler(call_as_function);
11108 Local<Object> instance = instance_template->NewInstance();
11109 v8::TryCatch try_catch;
11111 CHECK(instance->IsCallable());
11112 CHECK(!try_catch.HasCaught());
11115 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11116 Local<Object> instance = instance_template->NewInstance();
11117 v8::TryCatch try_catch;
11119 CHECK(!instance->IsCallable());
11120 CHECK(!try_catch.HasCaught());
11123 { Local<FunctionTemplate> function_template =
11124 FunctionTemplate::New(isolate, call_as_function);
11125 Local<Function> function = function_template->GetFunction();
11126 Local<Object> instance = function;
11127 v8::TryCatch try_catch;
11129 CHECK(instance->IsCallable());
11130 CHECK(!try_catch.HasCaught());
11133 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11134 Local<Function> function = function_template->GetFunction();
11135 Local<Object> instance = function;
11136 v8::TryCatch try_catch;
11138 CHECK(instance->IsCallable());
11139 CHECK(!try_catch.HasCaught());
11144 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11145 v8::HandleScope scope(isolate);
11146 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11147 for (int i = 0; i < iterations; i++) {
11148 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11150 return Recurse(isolate, depth - 1, iterations);
11154 THREADED_TEST(HandleIteration) {
11155 static const int kIterations = 500;
11156 static const int kNesting = 200;
11157 LocalContext context;
11158 v8::Isolate* isolate = context->GetIsolate();
11159 v8::HandleScope scope0(isolate);
11160 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11162 v8::HandleScope scope1(isolate);
11163 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11164 for (int i = 0; i < kIterations; i++) {
11165 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11166 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11169 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11171 v8::HandleScope scope2(CcTest::isolate());
11172 for (int j = 0; j < kIterations; j++) {
11173 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11174 CHECK_EQ(j + 1 + kIterations,
11175 v8::HandleScope::NumberOfHandles(isolate));
11178 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11180 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11181 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11185 static void InterceptorHasOwnPropertyGetter(
11186 Local<String> name,
11187 const v8::PropertyCallbackInfo<v8::Value>& info) {
11188 ApiTestFuzzer::Fuzz();
11192 THREADED_TEST(InterceptorHasOwnProperty) {
11193 LocalContext context;
11194 v8::Isolate* isolate = context->GetIsolate();
11195 v8::HandleScope scope(isolate);
11196 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11197 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11198 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11199 Local<Function> function = fun_templ->GetFunction();
11200 context->Global()->Set(v8_str("constructor"), function);
11201 v8::Handle<Value> value = CompileRun(
11202 "var o = new constructor();"
11203 "o.hasOwnProperty('ostehaps');");
11204 CHECK_EQ(false, value->BooleanValue());
11205 value = CompileRun(
11207 "o.hasOwnProperty('ostehaps');");
11208 CHECK_EQ(true, value->BooleanValue());
11209 value = CompileRun(
11210 "var p = new constructor();"
11211 "p.hasOwnProperty('ostehaps');");
11212 CHECK_EQ(false, value->BooleanValue());
11216 static void InterceptorHasOwnPropertyGetterGC(
11217 Local<String> name,
11218 const v8::PropertyCallbackInfo<v8::Value>& info) {
11219 ApiTestFuzzer::Fuzz();
11220 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11224 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11225 LocalContext context;
11226 v8::Isolate* isolate = context->GetIsolate();
11227 v8::HandleScope scope(isolate);
11228 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11229 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11230 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11231 Local<Function> function = fun_templ->GetFunction();
11232 context->Global()->Set(v8_str("constructor"), function);
11233 // Let's first make some stuff so we can be sure to get a good GC.
11235 "function makestr(size) {"
11237 " case 1: return 'f';"
11238 " case 2: return 'fo';"
11239 " case 3: return 'foo';"
11241 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11243 "var x = makestr(12345);"
11244 "x = makestr(31415);"
11245 "x = makestr(23456);");
11246 v8::Handle<Value> value = CompileRun(
11247 "var o = new constructor();"
11248 "o.__proto__ = new String(x);"
11249 "o.hasOwnProperty('ostehaps');");
11250 CHECK_EQ(false, value->BooleanValue());
11254 typedef void (*NamedPropertyGetter)(
11255 Local<String> property,
11256 const v8::PropertyCallbackInfo<v8::Value>& info);
11259 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11260 const char* source,
11262 v8::Isolate* isolate = CcTest::isolate();
11263 v8::HandleScope scope(isolate);
11264 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11265 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11266 LocalContext context;
11267 context->Global()->Set(v8_str("o"), templ->NewInstance());
11268 v8::Handle<Value> value = CompileRun(source);
11269 CHECK_EQ(expected, value->Int32Value());
11273 static void InterceptorLoadICGetter(
11274 Local<String> name,
11275 const v8::PropertyCallbackInfo<v8::Value>& info) {
11276 ApiTestFuzzer::Fuzz();
11277 v8::Isolate* isolate = CcTest::isolate();
11278 CHECK_EQ(isolate, info.GetIsolate());
11279 CHECK_EQ(v8_str("data"), info.Data());
11280 CHECK_EQ(v8_str("x"), name);
11281 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11285 // This test should hit the load IC for the interceptor case.
11286 THREADED_TEST(InterceptorLoadIC) {
11287 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11289 "for (var i = 0; i < 1000; i++) {"
11296 // Below go several tests which verify that JITing for various
11297 // configurations of interceptor and explicit fields works fine
11298 // (those cases are special cased to get better performance).
11300 static void InterceptorLoadXICGetter(
11301 Local<String> name,
11302 const v8::PropertyCallbackInfo<v8::Value>& info) {
11303 ApiTestFuzzer::Fuzz();
11304 info.GetReturnValue().Set(
11305 v8_str("x")->Equals(name) ?
11306 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11307 v8::Handle<v8::Value>());
11311 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11312 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11315 "for (var i = 0; i < 1000; i++) {"
11322 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11323 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11325 "o.__proto__ = { 'y': 239 };"
11326 "for (var i = 0; i < 1000; i++) {"
11327 " result = o.y + o.x;"
11333 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11334 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11336 "o.__proto__.y = 239;"
11337 "for (var i = 0; i < 1000; i++) {"
11338 " result = o.y + o.x;"
11344 THREADED_TEST(InterceptorLoadICUndefined) {
11345 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11347 "for (var i = 0; i < 1000; i++) {"
11348 " result = (o.y == undefined) ? 239 : 42;"
11354 THREADED_TEST(InterceptorLoadICWithOverride) {
11355 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11356 "fst = new Object(); fst.__proto__ = o;"
11357 "snd = new Object(); snd.__proto__ = fst;"
11359 "for (var i = 0; i < 1000; i++) {"
11360 " result1 = snd.x;"
11364 "for (var i = 0; i < 1000; i++) {"
11367 "result + result1",
11372 // Test the case when we stored field into
11373 // a stub, but interceptor produced value on its own.
11374 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11375 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11376 "proto = new Object();"
11377 "o.__proto__ = proto;"
11379 "for (var i = 0; i < 1000; i++) {"
11381 // Now it should be ICed and keep a reference to x defined on proto
11384 "for (var i = 0; i < 1000; i++) {"
11392 // Test the case when we stored field into
11393 // a stub, but it got invalidated later on.
11394 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11395 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11396 "proto1 = new Object();"
11397 "proto2 = new Object();"
11398 "o.__proto__ = proto1;"
11399 "proto1.__proto__ = proto2;"
11401 "for (var i = 0; i < 1000; i++) {"
11403 // Now it should be ICed and keep a reference to y defined on proto2
11407 "for (var i = 0; i < 1000; i++) {"
11415 static int interceptor_load_not_handled_calls = 0;
11416 static void InterceptorLoadNotHandled(
11417 Local<String> name,
11418 const v8::PropertyCallbackInfo<v8::Value>& info) {
11419 ++interceptor_load_not_handled_calls;
11423 // Test how post-interceptor lookups are done in the non-cacheable
11424 // case: the interceptor should not be invoked during this lookup.
11425 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11426 interceptor_load_not_handled_calls = 0;
11427 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11428 "receiver = new Object();"
11429 "receiver.__proto__ = o;"
11430 "proto = new Object();"
11431 "/* Make proto a slow-case object. */"
11432 "for (var i = 0; i < 1000; i++) {"
11433 " proto[\"xxxxxxxx\" + i] = [];"
11436 "o.__proto__ = proto;"
11438 "for (var i = 0; i < 1000; i++) {"
11439 " result += receiver.x;"
11443 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11447 // Test the case when we stored field into
11448 // a stub, but it got invalidated later on due to override on
11449 // global object which is between interceptor and fields' holders.
11450 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11451 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11452 "o.__proto__ = this;" // set a global to be a proto of o.
11453 "this.__proto__.y = 239;"
11454 "for (var i = 0; i < 10; i++) {"
11455 " if (o.y != 239) throw 'oops: ' + o.y;"
11456 // Now it should be ICed and keep a reference to y defined on field_holder.
11458 "this.y = 42;" // Assign on a global.
11460 "for (var i = 0; i < 10; i++) {"
11468 static void SetOnThis(Local<String> name,
11469 Local<Value> value,
11470 const v8::PropertyCallbackInfo<void>& info) {
11471 Local<Object>::Cast(info.This())->ForceSet(name, value);
11475 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11476 v8::Isolate* isolate = CcTest::isolate();
11477 v8::HandleScope scope(isolate);
11478 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11479 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11480 templ->SetAccessor(v8_str("y"), Return239Callback);
11481 LocalContext context;
11482 context->Global()->Set(v8_str("o"), templ->NewInstance());
11484 // Check the case when receiver and interceptor's holder
11485 // are the same objects.
11486 v8::Handle<Value> value = CompileRun(
11488 "for (var i = 0; i < 7; i++) {"
11491 CHECK_EQ(239, value->Int32Value());
11493 // Check the case when interceptor's holder is in proto chain
11495 value = CompileRun(
11496 "r = { __proto__: o };"
11498 "for (var i = 0; i < 7; i++) {"
11501 CHECK_EQ(239, value->Int32Value());
11505 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11506 v8::Isolate* isolate = CcTest::isolate();
11507 v8::HandleScope scope(isolate);
11508 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11509 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11510 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11511 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11513 LocalContext context;
11514 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11515 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11517 // Check the case when receiver and interceptor's holder
11518 // are the same objects.
11519 v8::Handle<Value> value = CompileRun(
11522 "for (var i = 0; i < 7; i++) {"
11523 " result = o.x + o.y;"
11525 CHECK_EQ(239 + 42, value->Int32Value());
11527 // Check the case when interceptor's holder is in proto chain
11529 value = CompileRun(
11530 "r = { __proto__: o };"
11532 "for (var i = 0; i < 7; i++) {"
11533 " result = r.x + r.y;"
11535 CHECK_EQ(239 + 42, value->Int32Value());
11539 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11540 v8::Isolate* isolate = CcTest::isolate();
11541 v8::HandleScope scope(isolate);
11542 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11543 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11544 templ->SetAccessor(v8_str("y"), Return239Callback);
11546 LocalContext context;
11547 context->Global()->Set(v8_str("o"), templ->NewInstance());
11549 v8::Handle<Value> value = CompileRun(
11550 "fst = new Object(); fst.__proto__ = o;"
11551 "snd = new Object(); snd.__proto__ = fst;"
11553 "for (var i = 0; i < 7; i++) {"
11554 " result1 = snd.x;"
11558 "for (var i = 0; i < 7; i++) {"
11561 "result + result1");
11562 CHECK_EQ(239 + 42, value->Int32Value());
11566 // Test the case when we stored callback into
11567 // a stub, but interceptor produced value on its own.
11568 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11569 v8::Isolate* isolate = CcTest::isolate();
11570 v8::HandleScope scope(isolate);
11571 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11572 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11573 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11574 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11576 LocalContext context;
11577 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11578 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11580 v8::Handle<Value> value = CompileRun(
11582 "for (var i = 0; i < 7; i++) {"
11584 // Now it should be ICed and keep a reference to x defined on p
11587 "for (var i = 0; i < 7; i++) {"
11591 CHECK_EQ(42 * 7, value->Int32Value());
11595 // Test the case when we stored callback into
11596 // a stub, but it got invalidated later on.
11597 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11598 v8::Isolate* isolate = CcTest::isolate();
11599 v8::HandleScope scope(isolate);
11600 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11601 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11602 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11603 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11605 LocalContext context;
11606 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11607 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11609 v8::Handle<Value> value = CompileRun(
11610 "inbetween = new Object();"
11611 "o.__proto__ = inbetween;"
11612 "inbetween.__proto__ = p;"
11613 "for (var i = 0; i < 10; i++) {"
11615 // Now it should be ICed and keep a reference to y defined on p
11617 "inbetween.y = 42;"
11619 "for (var i = 0; i < 10; i++) {"
11623 CHECK_EQ(42 * 10, value->Int32Value());
11627 // Test the case when we stored callback into
11628 // a stub, but it got invalidated later on due to override on
11629 // global object which is between interceptor and callbacks' holders.
11630 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11631 v8::Isolate* isolate = CcTest::isolate();
11632 v8::HandleScope scope(isolate);
11633 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11634 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11635 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11636 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11638 LocalContext context;
11639 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11640 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11642 v8::Handle<Value> value = CompileRun(
11643 "o.__proto__ = this;"
11644 "this.__proto__ = p;"
11645 "for (var i = 0; i < 10; i++) {"
11646 " if (o.y != 239) throw 'oops: ' + o.y;"
11647 // Now it should be ICed and keep a reference to y defined on p
11651 "for (var i = 0; i < 10; i++) {"
11655 CHECK_EQ(42 * 10, value->Int32Value());
11659 static void InterceptorLoadICGetter0(
11660 Local<String> name,
11661 const v8::PropertyCallbackInfo<v8::Value>& info) {
11662 ApiTestFuzzer::Fuzz();
11663 CHECK(v8_str("x")->Equals(name));
11664 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11668 THREADED_TEST(InterceptorReturningZero) {
11669 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11670 "o.x == undefined ? 1 : 0",
11675 static void InterceptorStoreICSetter(
11677 Local<Value> value,
11678 const v8::PropertyCallbackInfo<v8::Value>& info) {
11679 CHECK(v8_str("x")->Equals(key));
11680 CHECK_EQ(42, value->Int32Value());
11681 info.GetReturnValue().Set(value);
11685 // This test should hit the store IC for the interceptor case.
11686 THREADED_TEST(InterceptorStoreIC) {
11687 v8::Isolate* isolate = CcTest::isolate();
11688 v8::HandleScope scope(isolate);
11689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11690 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11691 InterceptorStoreICSetter,
11692 0, 0, 0, v8_str("data"));
11693 LocalContext context;
11694 context->Global()->Set(v8_str("o"), templ->NewInstance());
11696 "for (var i = 0; i < 1000; i++) {"
11702 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11703 v8::Isolate* isolate = CcTest::isolate();
11704 v8::HandleScope scope(isolate);
11705 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11706 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11707 LocalContext context;
11708 context->Global()->Set(v8_str("o"), templ->NewInstance());
11709 v8::Handle<Value> value = CompileRun(
11710 "for (var i = 0; i < 1000; i++) {"
11714 CHECK_EQ(239 + 42, value->Int32Value());
11720 v8::Handle<Value> call_ic_function;
11721 v8::Handle<Value> call_ic_function2;
11722 v8::Handle<Value> call_ic_function3;
11724 static void InterceptorCallICGetter(
11725 Local<String> name,
11726 const v8::PropertyCallbackInfo<v8::Value>& info) {
11727 ApiTestFuzzer::Fuzz();
11728 CHECK(v8_str("x")->Equals(name));
11729 info.GetReturnValue().Set(call_ic_function);
11733 // This test should hit the call IC for the interceptor case.
11734 THREADED_TEST(InterceptorCallIC) {
11735 v8::Isolate* isolate = CcTest::isolate();
11736 v8::HandleScope scope(isolate);
11737 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11738 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11739 LocalContext context;
11740 context->Global()->Set(v8_str("o"), templ->NewInstance());
11742 v8_compile("function f(x) { return x + 1; }; f")->Run();
11743 v8::Handle<Value> value = CompileRun(
11745 "for (var i = 0; i < 1000; i++) {"
11746 " result = o.x(41);"
11748 CHECK_EQ(42, value->Int32Value());
11752 // This test checks that if interceptor doesn't provide
11753 // a value, we can fetch regular value.
11754 THREADED_TEST(InterceptorCallICSeesOthers) {
11755 v8::Isolate* isolate = CcTest::isolate();
11756 v8::HandleScope scope(isolate);
11757 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11758 templ->SetNamedPropertyHandler(NoBlockGetterX);
11759 LocalContext context;
11760 context->Global()->Set(v8_str("o"), templ->NewInstance());
11761 v8::Handle<Value> value = CompileRun(
11762 "o.x = function f(x) { return x + 1; };"
11764 "for (var i = 0; i < 7; i++) {"
11765 " result = o.x(41);"
11767 CHECK_EQ(42, value->Int32Value());
11771 static v8::Handle<Value> call_ic_function4;
11772 static void InterceptorCallICGetter4(
11773 Local<String> name,
11774 const v8::PropertyCallbackInfo<v8::Value>& info) {
11775 ApiTestFuzzer::Fuzz();
11776 CHECK(v8_str("x")->Equals(name));
11777 info.GetReturnValue().Set(call_ic_function4);
11781 // This test checks that if interceptor provides a function,
11782 // even if we cached shadowed variant, interceptor's function
11784 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11785 v8::Isolate* isolate = CcTest::isolate();
11786 v8::HandleScope scope(isolate);
11787 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11788 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11789 LocalContext context;
11790 context->Global()->Set(v8_str("o"), templ->NewInstance());
11791 call_ic_function4 =
11792 v8_compile("function f(x) { return x - 1; }; f")->Run();
11793 v8::Handle<Value> value = CompileRun(
11794 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11796 "for (var i = 0; i < 1000; i++) {"
11797 " result = o.x(42);"
11799 CHECK_EQ(41, value->Int32Value());
11803 // Test the case when we stored cacheable lookup into
11804 // a stub, but it got invalidated later on
11805 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11806 v8::Isolate* isolate = CcTest::isolate();
11807 v8::HandleScope scope(isolate);
11808 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11809 templ->SetNamedPropertyHandler(NoBlockGetterX);
11810 LocalContext context;
11811 context->Global()->Set(v8_str("o"), templ->NewInstance());
11812 v8::Handle<Value> value = CompileRun(
11813 "proto1 = new Object();"
11814 "proto2 = new Object();"
11815 "o.__proto__ = proto1;"
11816 "proto1.__proto__ = proto2;"
11817 "proto2.y = function(x) { return x + 1; };"
11818 // Invoke it many times to compile a stub
11819 "for (var i = 0; i < 7; i++) {"
11822 "proto1.y = function(x) { return x - 1; };"
11824 "for (var i = 0; i < 7; i++) {"
11825 " result += o.y(42);"
11827 CHECK_EQ(41 * 7, value->Int32Value());
11831 // This test checks that if interceptor doesn't provide a function,
11832 // cached constant function is used
11833 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11834 v8::Isolate* isolate = CcTest::isolate();
11835 v8::HandleScope scope(isolate);
11836 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11837 templ->SetNamedPropertyHandler(NoBlockGetterX);
11838 LocalContext context;
11839 context->Global()->Set(v8_str("o"), templ->NewInstance());
11840 v8::Handle<Value> value = CompileRun(
11841 "function inc(x) { return x + 1; };"
11845 "for (var i = 0; i < 1000; i++) {"
11846 " result = o.x(42);"
11848 CHECK_EQ(43, value->Int32Value());
11852 static v8::Handle<Value> call_ic_function5;
11853 static void InterceptorCallICGetter5(
11854 Local<String> name,
11855 const v8::PropertyCallbackInfo<v8::Value>& info) {
11856 ApiTestFuzzer::Fuzz();
11857 if (v8_str("x")->Equals(name))
11858 info.GetReturnValue().Set(call_ic_function5);
11862 // This test checks that if interceptor provides a function,
11863 // even if we cached constant function, interceptor's function
11865 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11866 v8::Isolate* isolate = CcTest::isolate();
11867 v8::HandleScope scope(isolate);
11868 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11869 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11870 LocalContext context;
11871 context->Global()->Set(v8_str("o"), templ->NewInstance());
11872 call_ic_function5 =
11873 v8_compile("function f(x) { return x - 1; }; f")->Run();
11874 v8::Handle<Value> value = CompileRun(
11875 "function inc(x) { return x + 1; };"
11879 "for (var i = 0; i < 1000; i++) {"
11880 " result = o.x(42);"
11882 CHECK_EQ(41, value->Int32Value());
11886 static v8::Handle<Value> call_ic_function6;
11887 static void InterceptorCallICGetter6(
11888 Local<String> name,
11889 const v8::PropertyCallbackInfo<v8::Value>& info) {
11890 ApiTestFuzzer::Fuzz();
11891 if (v8_str("x")->Equals(name))
11892 info.GetReturnValue().Set(call_ic_function6);
11896 // Same test as above, except the code is wrapped in a function
11897 // to test the optimized compiler.
11898 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11899 i::FLAG_allow_natives_syntax = true;
11900 v8::Isolate* isolate = CcTest::isolate();
11901 v8::HandleScope scope(isolate);
11902 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11903 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11904 LocalContext context;
11905 context->Global()->Set(v8_str("o"), templ->NewInstance());
11906 call_ic_function6 =
11907 v8_compile("function f(x) { return x - 1; }; f")->Run();
11908 v8::Handle<Value> value = CompileRun(
11909 "function inc(x) { return x + 1; };"
11912 "function test() {"
11914 " for (var i = 0; i < 1000; i++) {"
11915 " result = o.x(42);"
11922 "%OptimizeFunctionOnNextCall(test);"
11924 CHECK_EQ(41, value->Int32Value());
11928 // Test the case when we stored constant function into
11929 // a stub, but it got invalidated later on
11930 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11931 v8::Isolate* isolate = CcTest::isolate();
11932 v8::HandleScope scope(isolate);
11933 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11934 templ->SetNamedPropertyHandler(NoBlockGetterX);
11935 LocalContext context;
11936 context->Global()->Set(v8_str("o"), templ->NewInstance());
11937 v8::Handle<Value> value = CompileRun(
11938 "function inc(x) { return x + 1; };"
11940 "proto1 = new Object();"
11941 "proto2 = new Object();"
11942 "o.__proto__ = proto1;"
11943 "proto1.__proto__ = proto2;"
11945 // Invoke it many times to compile a stub
11946 "for (var i = 0; i < 7; i++) {"
11949 "proto1.y = function(x) { return x - 1; };"
11951 "for (var i = 0; i < 7; i++) {"
11952 " result += o.y(42);"
11954 CHECK_EQ(41 * 7, value->Int32Value());
11958 // Test the case when we stored constant function into
11959 // a stub, but it got invalidated later on due to override on
11960 // global object which is between interceptor and constant function' holders.
11961 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11962 v8::Isolate* isolate = CcTest::isolate();
11963 v8::HandleScope scope(isolate);
11964 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11965 templ->SetNamedPropertyHandler(NoBlockGetterX);
11966 LocalContext context;
11967 context->Global()->Set(v8_str("o"), templ->NewInstance());
11968 v8::Handle<Value> value = CompileRun(
11969 "function inc(x) { return x + 1; };"
11971 "o.__proto__ = this;"
11972 "this.__proto__.y = inc;"
11973 // Invoke it many times to compile a stub
11974 "for (var i = 0; i < 7; i++) {"
11975 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11977 "this.y = function(x) { return x - 1; };"
11979 "for (var i = 0; i < 7; i++) {"
11980 " result += o.y(42);"
11982 CHECK_EQ(41 * 7, value->Int32Value());
11986 // Test the case when actual function to call sits on global object.
11987 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11988 v8::Isolate* isolate = CcTest::isolate();
11989 v8::HandleScope scope(isolate);
11990 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11991 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11993 LocalContext context;
11994 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11996 v8::Handle<Value> value = CompileRun(
11998 " o.__proto__ = this;"
11999 " for (var i = 0; i < 10; i++) {"
12000 " var v = o.parseFloat('239');"
12001 " if (v != 239) throw v;"
12002 // Now it should be ICed and keep a reference to parseFloat.
12005 " for (var i = 0; i < 10; i++) {"
12006 " result += o.parseFloat('239');"
12012 CHECK_EQ(239 * 10, value->Int32Value());
12015 static void InterceptorCallICFastApi(
12016 Local<String> name,
12017 const v8::PropertyCallbackInfo<v8::Value>& info) {
12018 ApiTestFuzzer::Fuzz();
12019 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12021 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12023 if ((*call_count) % 20 == 0) {
12024 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12028 static void FastApiCallback_TrivialSignature(
12029 const v8::FunctionCallbackInfo<v8::Value>& args) {
12030 ApiTestFuzzer::Fuzz();
12031 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12032 v8::Isolate* isolate = CcTest::isolate();
12033 CHECK_EQ(isolate, args.GetIsolate());
12034 CHECK_EQ(args.This(), args.Holder());
12035 CHECK(args.Data()->Equals(v8_str("method_data")));
12036 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12039 static void FastApiCallback_SimpleSignature(
12040 const v8::FunctionCallbackInfo<v8::Value>& args) {
12041 ApiTestFuzzer::Fuzz();
12042 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12043 v8::Isolate* isolate = CcTest::isolate();
12044 CHECK_EQ(isolate, args.GetIsolate());
12045 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12046 CHECK(args.Data()->Equals(v8_str("method_data")));
12047 // Note, we're using HasRealNamedProperty instead of Has to avoid
12048 // invoking the interceptor again.
12049 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12050 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12054 // Helper to maximize the odds of object moving.
12055 static void GenerateSomeGarbage() {
12058 "for (var i = 0; i < 1000; i++) {"
12059 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12061 "garbage = undefined;");
12065 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12066 static int count = 0;
12067 if (count++ % 3 == 0) {
12068 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12069 // This should move the stub
12070 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12075 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12076 LocalContext context;
12077 v8::Isolate* isolate = context->GetIsolate();
12078 v8::HandleScope scope(isolate);
12079 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12080 v8::ObjectTemplate::New(isolate);
12081 nativeobject_templ->Set(isolate, "callback",
12082 v8::FunctionTemplate::New(isolate,
12083 DirectApiCallback));
12084 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12085 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12086 // call the api function multiple times to ensure direct call stub creation.
12089 " for (var i = 1; i <= 30; i++) {"
12090 " nativeobject.callback();"
12097 void ThrowingDirectApiCallback(
12098 const v8::FunctionCallbackInfo<v8::Value>& args) {
12099 args.GetIsolate()->ThrowException(v8_str("g"));
12103 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12104 LocalContext context;
12105 v8::Isolate* isolate = context->GetIsolate();
12106 v8::HandleScope scope(isolate);
12107 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12108 v8::ObjectTemplate::New(isolate);
12109 nativeobject_templ->Set(isolate, "callback",
12110 v8::FunctionTemplate::New(isolate,
12111 ThrowingDirectApiCallback));
12112 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12113 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12114 // call the api function multiple times to ensure direct call stub creation.
12115 v8::Handle<Value> result = CompileRun(
12118 " for (var i = 1; i <= 5; i++) {"
12119 " try { nativeobject.callback(); } catch (e) { result += e; }"
12123 CHECK_EQ(v8_str("ggggg"), result);
12127 static Handle<Value> DoDirectGetter() {
12128 if (++p_getter_count % 3 == 0) {
12129 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12130 GenerateSomeGarbage();
12132 return v8_str("Direct Getter Result");
12135 static void DirectGetterCallback(
12136 Local<String> name,
12137 const v8::PropertyCallbackInfo<v8::Value>& info) {
12138 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12139 info.GetReturnValue().Set(DoDirectGetter());
12143 template<typename Accessor>
12144 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12145 LocalContext context;
12146 v8::Isolate* isolate = context->GetIsolate();
12147 v8::HandleScope scope(isolate);
12148 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12149 obj->SetAccessor(v8_str("p1"), accessor);
12150 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12151 p_getter_count = 0;
12152 v8::Handle<v8::Value> result = CompileRun(
12154 " for (var i = 0; i < 30; i++) o1.p1;"
12158 CHECK_EQ(v8_str("Direct Getter Result"), result);
12159 CHECK_EQ(31, p_getter_count);
12163 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12164 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12168 void ThrowingDirectGetterCallback(
12169 Local<String> name,
12170 const v8::PropertyCallbackInfo<v8::Value>& info) {
12171 info.GetIsolate()->ThrowException(v8_str("g"));
12175 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12176 LocalContext context;
12177 v8::Isolate* isolate = context->GetIsolate();
12178 v8::HandleScope scope(isolate);
12179 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12180 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12181 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12182 v8::Handle<Value> result = CompileRun(
12184 "for (var i = 0; i < 5; i++) {"
12185 " try { o1.p1; } catch (e) { result += e; }"
12188 CHECK_EQ(v8_str("ggggg"), result);
12192 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12193 int interceptor_call_count = 0;
12194 v8::Isolate* isolate = CcTest::isolate();
12195 v8::HandleScope scope(isolate);
12196 v8::Handle<v8::FunctionTemplate> fun_templ =
12197 v8::FunctionTemplate::New(isolate);
12198 v8::Handle<v8::FunctionTemplate> method_templ =
12199 v8::FunctionTemplate::New(isolate,
12200 FastApiCallback_TrivialSignature,
12201 v8_str("method_data"),
12202 v8::Handle<v8::Signature>());
12203 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12204 proto_templ->Set(v8_str("method"), method_templ);
12205 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12206 templ->SetNamedPropertyHandler(
12207 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12208 v8::External::New(isolate, &interceptor_call_count));
12209 LocalContext context;
12210 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12211 GenerateSomeGarbage();
12212 context->Global()->Set(v8_str("o"), fun->NewInstance());
12215 "for (var i = 0; i < 100; i++) {"
12216 " result = o.method(41);"
12218 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12219 CHECK_EQ(100, interceptor_call_count);
12223 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12224 int interceptor_call_count = 0;
12225 v8::Isolate* isolate = CcTest::isolate();
12226 v8::HandleScope scope(isolate);
12227 v8::Handle<v8::FunctionTemplate> fun_templ =
12228 v8::FunctionTemplate::New(isolate);
12229 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12230 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12231 v8::Signature::New(isolate, fun_templ));
12232 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12233 proto_templ->Set(v8_str("method"), method_templ);
12234 fun_templ->SetHiddenPrototype(true);
12235 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12236 templ->SetNamedPropertyHandler(
12237 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12238 v8::External::New(isolate, &interceptor_call_count));
12239 LocalContext context;
12240 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12241 GenerateSomeGarbage();
12242 context->Global()->Set(v8_str("o"), fun->NewInstance());
12245 "var receiver = {};"
12246 "receiver.__proto__ = o;"
12248 "for (var i = 0; i < 100; i++) {"
12249 " result = receiver.method(41);"
12251 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12252 CHECK_EQ(100, interceptor_call_count);
12256 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12257 int interceptor_call_count = 0;
12258 v8::Isolate* isolate = CcTest::isolate();
12259 v8::HandleScope scope(isolate);
12260 v8::Handle<v8::FunctionTemplate> fun_templ =
12261 v8::FunctionTemplate::New(isolate);
12262 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12263 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12264 v8::Signature::New(isolate, fun_templ));
12265 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12266 proto_templ->Set(v8_str("method"), method_templ);
12267 fun_templ->SetHiddenPrototype(true);
12268 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12269 templ->SetNamedPropertyHandler(
12270 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12271 v8::External::New(isolate, &interceptor_call_count));
12272 LocalContext context;
12273 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12274 GenerateSomeGarbage();
12275 context->Global()->Set(v8_str("o"), fun->NewInstance());
12278 "var receiver = {};"
12279 "receiver.__proto__ = o;"
12281 "var saved_result = 0;"
12282 "for (var i = 0; i < 100; i++) {"
12283 " result = receiver.method(41);"
12285 " saved_result = result;"
12286 " receiver = {method: function(x) { return x - 1 }};"
12289 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12290 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12291 CHECK_GE(interceptor_call_count, 50);
12295 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12296 int interceptor_call_count = 0;
12297 v8::Isolate* isolate = CcTest::isolate();
12298 v8::HandleScope scope(isolate);
12299 v8::Handle<v8::FunctionTemplate> fun_templ =
12300 v8::FunctionTemplate::New(isolate);
12301 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12302 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12303 v8::Signature::New(isolate, fun_templ));
12304 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12305 proto_templ->Set(v8_str("method"), method_templ);
12306 fun_templ->SetHiddenPrototype(true);
12307 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12308 templ->SetNamedPropertyHandler(
12309 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12310 v8::External::New(isolate, &interceptor_call_count));
12311 LocalContext context;
12312 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12313 GenerateSomeGarbage();
12314 context->Global()->Set(v8_str("o"), fun->NewInstance());
12317 "var receiver = {};"
12318 "receiver.__proto__ = o;"
12320 "var saved_result = 0;"
12321 "for (var i = 0; i < 100; i++) {"
12322 " result = receiver.method(41);"
12324 " saved_result = result;"
12325 " o.method = function(x) { return x - 1 };"
12328 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12329 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12330 CHECK_GE(interceptor_call_count, 50);
12334 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12335 int interceptor_call_count = 0;
12336 v8::Isolate* isolate = CcTest::isolate();
12337 v8::HandleScope scope(isolate);
12338 v8::Handle<v8::FunctionTemplate> fun_templ =
12339 v8::FunctionTemplate::New(isolate);
12340 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12341 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12342 v8::Signature::New(isolate, fun_templ));
12343 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12344 proto_templ->Set(v8_str("method"), method_templ);
12345 fun_templ->SetHiddenPrototype(true);
12346 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12347 templ->SetNamedPropertyHandler(
12348 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12349 v8::External::New(isolate, &interceptor_call_count));
12350 LocalContext context;
12351 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12352 GenerateSomeGarbage();
12353 context->Global()->Set(v8_str("o"), fun->NewInstance());
12354 v8::TryCatch try_catch;
12357 "var receiver = {};"
12358 "receiver.__proto__ = o;"
12360 "var saved_result = 0;"
12361 "for (var i = 0; i < 100; i++) {"
12362 " result = receiver.method(41);"
12364 " saved_result = result;"
12368 CHECK(try_catch.HasCaught());
12369 // TODO(verwaest): Adjust message.
12370 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12371 try_catch.Exception()->ToString());
12372 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12373 CHECK_GE(interceptor_call_count, 50);
12377 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12378 int interceptor_call_count = 0;
12379 v8::Isolate* isolate = CcTest::isolate();
12380 v8::HandleScope scope(isolate);
12381 v8::Handle<v8::FunctionTemplate> fun_templ =
12382 v8::FunctionTemplate::New(isolate);
12383 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12384 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12385 v8::Signature::New(isolate, fun_templ));
12386 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12387 proto_templ->Set(v8_str("method"), method_templ);
12388 fun_templ->SetHiddenPrototype(true);
12389 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12390 templ->SetNamedPropertyHandler(
12391 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12392 v8::External::New(isolate, &interceptor_call_count));
12393 LocalContext context;
12394 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12395 GenerateSomeGarbage();
12396 context->Global()->Set(v8_str("o"), fun->NewInstance());
12397 v8::TryCatch try_catch;
12400 "var receiver = {};"
12401 "receiver.__proto__ = o;"
12403 "var saved_result = 0;"
12404 "for (var i = 0; i < 100; i++) {"
12405 " result = receiver.method(41);"
12407 " saved_result = result;"
12408 " receiver = {method: receiver.method};"
12411 CHECK(try_catch.HasCaught());
12412 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12413 try_catch.Exception()->ToString());
12414 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12415 CHECK_GE(interceptor_call_count, 50);
12419 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12420 v8::Isolate* isolate = CcTest::isolate();
12421 v8::HandleScope scope(isolate);
12422 v8::Handle<v8::FunctionTemplate> fun_templ =
12423 v8::FunctionTemplate::New(isolate);
12424 v8::Handle<v8::FunctionTemplate> method_templ =
12425 v8::FunctionTemplate::New(isolate,
12426 FastApiCallback_TrivialSignature,
12427 v8_str("method_data"),
12428 v8::Handle<v8::Signature>());
12429 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12430 proto_templ->Set(v8_str("method"), method_templ);
12431 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12433 LocalContext context;
12434 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12435 GenerateSomeGarbage();
12436 context->Global()->Set(v8_str("o"), fun->NewInstance());
12439 "for (var i = 0; i < 100; i++) {"
12440 " result = o.method(41);"
12443 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12447 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12448 v8::Isolate* isolate = CcTest::isolate();
12449 v8::HandleScope scope(isolate);
12450 v8::Handle<v8::FunctionTemplate> fun_templ =
12451 v8::FunctionTemplate::New(isolate);
12452 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12453 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12454 v8::Signature::New(isolate, fun_templ));
12455 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12456 proto_templ->Set(v8_str("method"), method_templ);
12457 fun_templ->SetHiddenPrototype(true);
12458 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12459 CHECK(!templ.IsEmpty());
12460 LocalContext context;
12461 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12462 GenerateSomeGarbage();
12463 context->Global()->Set(v8_str("o"), fun->NewInstance());
12466 "var receiver = {};"
12467 "receiver.__proto__ = o;"
12469 "for (var i = 0; i < 100; i++) {"
12470 " result = receiver.method(41);"
12473 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12477 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12478 v8::Isolate* isolate = CcTest::isolate();
12479 v8::HandleScope scope(isolate);
12480 v8::Handle<v8::FunctionTemplate> fun_templ =
12481 v8::FunctionTemplate::New(isolate);
12482 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12483 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12484 v8::Signature::New(isolate, fun_templ));
12485 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12486 proto_templ->Set(v8_str("method"), method_templ);
12487 fun_templ->SetHiddenPrototype(true);
12488 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12489 CHECK(!templ.IsEmpty());
12490 LocalContext context;
12491 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12492 GenerateSomeGarbage();
12493 context->Global()->Set(v8_str("o"), fun->NewInstance());
12496 "var receiver = {};"
12497 "receiver.__proto__ = o;"
12499 "var saved_result = 0;"
12500 "for (var i = 0; i < 100; i++) {"
12501 " result = receiver.method(41);"
12503 " saved_result = result;"
12504 " receiver = {method: function(x) { return x - 1 }};"
12507 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12508 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12512 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12513 v8::Isolate* isolate = CcTest::isolate();
12514 v8::HandleScope scope(isolate);
12515 v8::Handle<v8::FunctionTemplate> fun_templ =
12516 v8::FunctionTemplate::New(isolate);
12517 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12518 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12519 v8::Signature::New(isolate, fun_templ));
12520 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12521 proto_templ->Set(v8_str("method"), method_templ);
12522 fun_templ->SetHiddenPrototype(true);
12523 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12524 CHECK(!templ.IsEmpty());
12525 LocalContext context;
12526 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12527 GenerateSomeGarbage();
12528 context->Global()->Set(v8_str("o"), fun->NewInstance());
12529 v8::TryCatch try_catch;
12532 "var receiver = {};"
12533 "receiver.__proto__ = o;"
12535 "var saved_result = 0;"
12536 "for (var i = 0; i < 100; i++) {"
12537 " result = receiver.method(41);"
12539 " saved_result = result;"
12543 CHECK(try_catch.HasCaught());
12544 // TODO(verwaest): Adjust message.
12545 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12546 try_catch.Exception()->ToString());
12547 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12551 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12552 v8::Isolate* isolate = CcTest::isolate();
12553 v8::HandleScope scope(isolate);
12554 v8::Handle<v8::FunctionTemplate> fun_templ =
12555 v8::FunctionTemplate::New(isolate);
12556 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12557 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12558 v8::Signature::New(isolate, fun_templ));
12559 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12560 proto_templ->Set(v8_str("method"), method_templ);
12561 fun_templ->SetHiddenPrototype(true);
12562 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12563 CHECK(!templ.IsEmpty());
12564 LocalContext context;
12565 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12566 GenerateSomeGarbage();
12567 context->Global()->Set(v8_str("o"), fun->NewInstance());
12568 v8::TryCatch try_catch;
12571 "var receiver = {};"
12572 "receiver.__proto__ = o;"
12574 "var saved_result = 0;"
12575 "for (var i = 0; i < 100; i++) {"
12576 " result = receiver.method(41);"
12578 " saved_result = result;"
12579 " receiver = Object.create(receiver);"
12582 CHECK(try_catch.HasCaught());
12583 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12584 try_catch.Exception()->ToString());
12585 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12589 v8::Handle<Value> keyed_call_ic_function;
12591 static void InterceptorKeyedCallICGetter(
12592 Local<String> name,
12593 const v8::PropertyCallbackInfo<v8::Value>& info) {
12594 ApiTestFuzzer::Fuzz();
12595 if (v8_str("x")->Equals(name)) {
12596 info.GetReturnValue().Set(keyed_call_ic_function);
12601 // Test the case when we stored cacheable lookup into
12602 // a stub, but the function name changed (to another cacheable function).
12603 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12604 v8::Isolate* isolate = CcTest::isolate();
12605 v8::HandleScope scope(isolate);
12606 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12607 templ->SetNamedPropertyHandler(NoBlockGetterX);
12608 LocalContext context;
12609 context->Global()->Set(v8_str("o"), templ->NewInstance());
12611 "proto = new Object();"
12612 "proto.y = function(x) { return x + 1; };"
12613 "proto.z = function(x) { return x - 1; };"
12614 "o.__proto__ = proto;"
12616 "var method = 'y';"
12617 "for (var i = 0; i < 10; i++) {"
12618 " if (i == 5) { method = 'z'; };"
12619 " result += o[method](41);"
12621 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12625 // Test the case when we stored cacheable lookup into
12626 // a stub, but the function name changed (and the new function is present
12627 // both before and after the interceptor in the prototype chain).
12628 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12629 v8::Isolate* isolate = CcTest::isolate();
12630 v8::HandleScope scope(isolate);
12631 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12632 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12633 LocalContext context;
12634 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12635 keyed_call_ic_function =
12636 v8_compile("function f(x) { return x - 1; }; f")->Run();
12638 "o = new Object();"
12639 "proto2 = new Object();"
12640 "o.y = function(x) { return x + 1; };"
12641 "proto2.y = function(x) { return x + 2; };"
12642 "o.__proto__ = proto1;"
12643 "proto1.__proto__ = proto2;"
12645 "var method = 'x';"
12646 "for (var i = 0; i < 10; i++) {"
12647 " if (i == 5) { method = 'y'; };"
12648 " result += o[method](41);"
12650 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12654 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12655 // on the global object.
12656 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12657 v8::Isolate* isolate = CcTest::isolate();
12658 v8::HandleScope scope(isolate);
12659 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12660 templ->SetNamedPropertyHandler(NoBlockGetterX);
12661 LocalContext context;
12662 context->Global()->Set(v8_str("o"), templ->NewInstance());
12664 "function inc(x) { return x + 1; };"
12666 "function dec(x) { return x - 1; };"
12668 "o.__proto__ = this;"
12669 "this.__proto__.x = inc;"
12670 "this.__proto__.y = dec;"
12672 "var method = 'x';"
12673 "for (var i = 0; i < 10; i++) {"
12674 " if (i == 5) { method = 'y'; };"
12675 " result += o[method](41);"
12677 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12681 // Test the case when actual function to call sits on global object.
12682 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12683 v8::Isolate* isolate = CcTest::isolate();
12684 v8::HandleScope scope(isolate);
12685 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12686 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12687 LocalContext context;
12688 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12691 "function len(x) { return x.length; };"
12692 "o.__proto__ = this;"
12693 "var m = 'parseFloat';"
12695 "for (var i = 0; i < 10; i++) {"
12698 " saved_result = result;"
12700 " result = o[m]('239');"
12702 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12703 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12707 // Test the map transition before the interceptor.
12708 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12709 v8::Isolate* isolate = CcTest::isolate();
12710 v8::HandleScope scope(isolate);
12711 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12712 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12713 LocalContext context;
12714 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12717 "var o = new Object();"
12718 "o.__proto__ = proto;"
12719 "o.method = function(x) { return x + 1; };"
12720 "var m = 'method';"
12722 "for (var i = 0; i < 10; i++) {"
12723 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
12724 " result += o[m](41);"
12726 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12730 // Test the map transition after the interceptor.
12731 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12732 v8::Isolate* isolate = CcTest::isolate();
12733 v8::HandleScope scope(isolate);
12734 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12735 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12736 LocalContext context;
12737 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12740 "var proto = new Object();"
12741 "o.__proto__ = proto;"
12742 "proto.method = function(x) { return x + 1; };"
12743 "var m = 'method';"
12745 "for (var i = 0; i < 10; i++) {"
12746 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12747 " result += o[m](41);"
12749 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12753 static int interceptor_call_count = 0;
12755 static void InterceptorICRefErrorGetter(
12756 Local<String> name,
12757 const v8::PropertyCallbackInfo<v8::Value>& info) {
12758 ApiTestFuzzer::Fuzz();
12759 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12760 info.GetReturnValue().Set(call_ic_function2);
12765 // This test should hit load and call ICs for the interceptor case.
12766 // Once in a while, the interceptor will reply that a property was not
12767 // found in which case we should get a reference error.
12768 THREADED_TEST(InterceptorICReferenceErrors) {
12769 v8::Isolate* isolate = CcTest::isolate();
12770 v8::HandleScope scope(isolate);
12771 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12772 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12773 LocalContext context(0, templ, v8::Handle<Value>());
12774 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12775 v8::Handle<Value> value = CompileRun(
12777 " for (var i = 0; i < 1000; i++) {"
12778 " try { x; } catch(e) { return true; }"
12783 CHECK_EQ(true, value->BooleanValue());
12784 interceptor_call_count = 0;
12785 value = CompileRun(
12787 " for (var i = 0; i < 1000; i++) {"
12788 " try { x(42); } catch(e) { return true; }"
12793 CHECK_EQ(true, value->BooleanValue());
12797 static int interceptor_ic_exception_get_count = 0;
12799 static void InterceptorICExceptionGetter(
12800 Local<String> name,
12801 const v8::PropertyCallbackInfo<v8::Value>& info) {
12802 ApiTestFuzzer::Fuzz();
12803 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12804 info.GetReturnValue().Set(call_ic_function3);
12806 if (interceptor_ic_exception_get_count == 20) {
12807 info.GetIsolate()->ThrowException(v8_num(42));
12813 // Test interceptor load/call IC where the interceptor throws an
12814 // exception once in a while.
12815 THREADED_TEST(InterceptorICGetterExceptions) {
12816 interceptor_ic_exception_get_count = 0;
12817 v8::Isolate* isolate = CcTest::isolate();
12818 v8::HandleScope scope(isolate);
12819 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12820 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12821 LocalContext context(0, templ, v8::Handle<Value>());
12822 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12823 v8::Handle<Value> value = CompileRun(
12825 " for (var i = 0; i < 100; i++) {"
12826 " try { x; } catch(e) { return true; }"
12831 CHECK_EQ(true, value->BooleanValue());
12832 interceptor_ic_exception_get_count = 0;
12833 value = CompileRun(
12835 " for (var i = 0; i < 100; i++) {"
12836 " try { x(42); } catch(e) { return true; }"
12841 CHECK_EQ(true, value->BooleanValue());
12845 static int interceptor_ic_exception_set_count = 0;
12847 static void InterceptorICExceptionSetter(
12849 Local<Value> value,
12850 const v8::PropertyCallbackInfo<v8::Value>& info) {
12851 ApiTestFuzzer::Fuzz();
12852 if (++interceptor_ic_exception_set_count > 20) {
12853 info.GetIsolate()->ThrowException(v8_num(42));
12858 // Test interceptor store IC where the interceptor throws an exception
12859 // once in a while.
12860 THREADED_TEST(InterceptorICSetterExceptions) {
12861 interceptor_ic_exception_set_count = 0;
12862 v8::Isolate* isolate = CcTest::isolate();
12863 v8::HandleScope scope(isolate);
12864 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12865 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12866 LocalContext context(0, templ, v8::Handle<Value>());
12867 v8::Handle<Value> value = CompileRun(
12869 " for (var i = 0; i < 100; i++) {"
12870 " try { x = 42; } catch(e) { return true; }"
12875 CHECK_EQ(true, value->BooleanValue());
12879 // Test that we ignore null interceptors.
12880 THREADED_TEST(NullNamedInterceptor) {
12881 v8::Isolate* isolate = CcTest::isolate();
12882 v8::HandleScope scope(isolate);
12883 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12884 templ->SetNamedPropertyHandler(
12885 static_cast<v8::NamedPropertyGetterCallback>(0));
12886 LocalContext context;
12887 templ->Set(CcTest::isolate(), "x", v8_num(42));
12888 v8::Handle<v8::Object> obj = templ->NewInstance();
12889 context->Global()->Set(v8_str("obj"), obj);
12890 v8::Handle<Value> value = CompileRun("obj.x");
12891 CHECK(value->IsInt32());
12892 CHECK_EQ(42, value->Int32Value());
12896 // Test that we ignore null interceptors.
12897 THREADED_TEST(NullIndexedInterceptor) {
12898 v8::Isolate* isolate = CcTest::isolate();
12899 v8::HandleScope scope(isolate);
12900 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12901 templ->SetIndexedPropertyHandler(
12902 static_cast<v8::IndexedPropertyGetterCallback>(0));
12903 LocalContext context;
12904 templ->Set(CcTest::isolate(), "42", v8_num(42));
12905 v8::Handle<v8::Object> obj = templ->NewInstance();
12906 context->Global()->Set(v8_str("obj"), obj);
12907 v8::Handle<Value> value = CompileRun("obj[42]");
12908 CHECK(value->IsInt32());
12909 CHECK_EQ(42, value->Int32Value());
12913 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12914 v8::Isolate* isolate = CcTest::isolate();
12915 v8::HandleScope scope(isolate);
12916 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12917 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12919 env->Global()->Set(v8_str("obj"),
12920 templ->GetFunction()->NewInstance());
12921 ExpectTrue("obj.x === 42");
12922 ExpectTrue("!obj.propertyIsEnumerable('x')");
12926 static void ThrowingGetter(Local<String> name,
12927 const v8::PropertyCallbackInfo<v8::Value>& info) {
12928 ApiTestFuzzer::Fuzz();
12929 info.GetIsolate()->ThrowException(Handle<Value>());
12930 info.GetReturnValue().SetUndefined();
12934 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12935 LocalContext context;
12936 HandleScope scope(context->GetIsolate());
12938 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12939 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12940 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12942 Local<Object> instance = templ->GetFunction()->NewInstance();
12944 Local<Object> another = Object::New(context->GetIsolate());
12945 another->SetPrototype(instance);
12947 Local<Object> with_js_getter = CompileRun(
12949 "o.__defineGetter__('f', function() { throw undefined; });\n"
12950 "o\n").As<Object>();
12951 CHECK(!with_js_getter.IsEmpty());
12953 TryCatch try_catch;
12955 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12956 CHECK(try_catch.HasCaught());
12958 CHECK(result.IsEmpty());
12960 result = another->GetRealNamedProperty(v8_str("f"));
12961 CHECK(try_catch.HasCaught());
12963 CHECK(result.IsEmpty());
12965 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12966 CHECK(try_catch.HasCaught());
12968 CHECK(result.IsEmpty());
12970 result = another->Get(v8_str("f"));
12971 CHECK(try_catch.HasCaught());
12973 CHECK(result.IsEmpty());
12975 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12976 CHECK(try_catch.HasCaught());
12978 CHECK(result.IsEmpty());
12980 result = with_js_getter->Get(v8_str("f"));
12981 CHECK(try_catch.HasCaught());
12983 CHECK(result.IsEmpty());
12987 static void ThrowingCallbackWithTryCatch(
12988 const v8::FunctionCallbackInfo<v8::Value>& args) {
12989 TryCatch try_catch;
12990 // Verboseness is important: it triggers message delivery which can call into
12992 try_catch.SetVerbose(true);
12993 CompileRun("throw 'from JS';");
12994 CHECK(try_catch.HasCaught());
12995 CHECK(!CcTest::i_isolate()->has_pending_exception());
12996 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13000 static int call_depth;
13003 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13004 TryCatch try_catch;
13008 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13009 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13013 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13014 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13018 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13019 Handle<String> errorMessageString = message->Get();
13020 CHECK(!errorMessageString.IsEmpty());
13021 message->GetStackTrace();
13022 message->GetScriptOrigin().ResourceName();
13026 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13027 LocalContext context;
13028 v8::Isolate* isolate = context->GetIsolate();
13029 HandleScope scope(isolate);
13031 Local<Function> func =
13032 FunctionTemplate::New(isolate,
13033 ThrowingCallbackWithTryCatch)->GetFunction();
13034 context->Global()->Set(v8_str("func"), func);
13036 MessageCallback callbacks[] =
13037 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13038 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13039 MessageCallback callback = callbacks[i];
13040 if (callback != NULL) {
13041 V8::AddMessageListener(callback);
13043 // Some small number to control number of times message handler should
13044 // throw an exception.
13047 "var thrown = false;\n"
13048 "try { func(); } catch(e) { thrown = true; }\n"
13050 if (callback != NULL) {
13051 V8::RemoveMessageListeners(callback);
13057 static void ParentGetter(Local<String> name,
13058 const v8::PropertyCallbackInfo<v8::Value>& info) {
13059 ApiTestFuzzer::Fuzz();
13060 info.GetReturnValue().Set(v8_num(1));
13064 static void ChildGetter(Local<String> name,
13065 const v8::PropertyCallbackInfo<v8::Value>& info) {
13066 ApiTestFuzzer::Fuzz();
13067 info.GetReturnValue().Set(v8_num(42));
13071 THREADED_TEST(Overriding) {
13072 LocalContext context;
13073 v8::Isolate* isolate = context->GetIsolate();
13074 v8::HandleScope scope(isolate);
13076 // Parent template.
13077 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13078 Local<ObjectTemplate> parent_instance_templ =
13079 parent_templ->InstanceTemplate();
13080 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13082 // Template that inherits from the parent template.
13083 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13084 Local<ObjectTemplate> child_instance_templ =
13085 child_templ->InstanceTemplate();
13086 child_templ->Inherit(parent_templ);
13087 // Override 'f'. The child version of 'f' should get called for child
13089 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13090 // Add 'g' twice. The 'g' added last should get called for instances.
13091 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13092 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13094 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13095 // so 'h' can be shadowed on the instance object.
13096 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13097 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13098 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13100 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13101 // but the attribute does not have effect because it is duplicated with
13103 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13104 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13108 // Instantiate the child template.
13109 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13111 // Check that the child function overrides the parent one.
13112 context->Global()->Set(v8_str("o"), instance);
13113 Local<Value> value = v8_compile("o.f")->Run();
13114 // Check that the 'g' that was added last is hit.
13115 CHECK_EQ(42, value->Int32Value());
13116 value = v8_compile("o.g")->Run();
13117 CHECK_EQ(42, value->Int32Value());
13119 // Check that 'h' cannot be shadowed.
13120 value = v8_compile("o.h = 3; o.h")->Run();
13121 CHECK_EQ(1, value->Int32Value());
13123 // Check that 'i' cannot be shadowed or changed.
13124 value = v8_compile("o.i = 3; o.i")->Run();
13125 CHECK_EQ(42, value->Int32Value());
13129 static void IsConstructHandler(
13130 const v8::FunctionCallbackInfo<v8::Value>& args) {
13131 ApiTestFuzzer::Fuzz();
13132 args.GetReturnValue().Set(args.IsConstructCall());
13136 THREADED_TEST(IsConstructCall) {
13137 v8::Isolate* isolate = CcTest::isolate();
13138 v8::HandleScope scope(isolate);
13140 // Function template with call handler.
13141 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13142 templ->SetCallHandler(IsConstructHandler);
13144 LocalContext context;
13146 context->Global()->Set(v8_str("f"), templ->GetFunction());
13147 Local<Value> value = v8_compile("f()")->Run();
13148 CHECK(!value->BooleanValue());
13149 value = v8_compile("new f()")->Run();
13150 CHECK(value->BooleanValue());
13154 THREADED_TEST(ObjectProtoToString) {
13155 v8::Isolate* isolate = CcTest::isolate();
13156 v8::HandleScope scope(isolate);
13157 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13158 templ->SetClassName(v8_str("MyClass"));
13160 LocalContext context;
13162 Local<String> customized_tostring = v8_str("customized toString");
13164 // Replace Object.prototype.toString
13165 v8_compile("Object.prototype.toString = function() {"
13166 " return 'customized toString';"
13169 // Normal ToString call should call replaced Object.prototype.toString
13170 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13171 Local<String> value = instance->ToString();
13172 CHECK(value->IsString() && value->Equals(customized_tostring));
13174 // ObjectProtoToString should not call replace toString function.
13175 value = instance->ObjectProtoToString();
13176 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13179 value = context->Global()->ObjectProtoToString();
13180 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13182 // Check ordinary object
13183 Local<Value> object = v8_compile("new Object()")->Run();
13184 value = object.As<v8::Object>()->ObjectProtoToString();
13185 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13189 THREADED_TEST(ObjectGetConstructorName) {
13190 LocalContext context;
13191 v8::HandleScope scope(context->GetIsolate());
13192 v8_compile("function Parent() {};"
13193 "function Child() {};"
13194 "Child.prototype = new Parent();"
13195 "var outer = { inner: function() { } };"
13196 "var p = new Parent();"
13197 "var c = new Child();"
13198 "var x = new outer.inner();")->Run();
13200 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13201 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13202 v8_str("Parent")));
13204 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13205 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13208 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13209 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13210 v8_str("outer.inner")));
13214 bool ApiTestFuzzer::fuzzing_ = false;
13215 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13216 int ApiTestFuzzer::active_tests_;
13217 int ApiTestFuzzer::tests_being_run_;
13218 int ApiTestFuzzer::current_;
13221 // We are in a callback and want to switch to another thread (if we
13222 // are currently running the thread fuzzing test).
13223 void ApiTestFuzzer::Fuzz() {
13224 if (!fuzzing_) return;
13225 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13226 test->ContextSwitch();
13230 // Let the next thread go. Since it is also waiting on the V8 lock it may
13231 // not start immediately.
13232 bool ApiTestFuzzer::NextThread() {
13233 int test_position = GetNextTestNumber();
13234 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13235 if (test_position == current_) {
13237 printf("Stay with %s\n", test_name);
13240 if (kLogThreading) {
13241 printf("Switch from %s to %s\n",
13243 RegisterThreadedTest::nth(test_position)->name());
13245 current_ = test_position;
13246 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13251 void ApiTestFuzzer::Run() {
13252 // When it is our turn...
13255 // ... get the V8 lock and start running the test.
13256 v8::Locker locker(CcTest::isolate());
13259 // This test finished.
13262 // If it was the last then signal that fact.
13263 if (active_tests_ == 0) {
13264 all_tests_done_.Signal();
13266 // Otherwise select a new test and start that.
13272 static unsigned linear_congruential_generator;
13275 void ApiTestFuzzer::SetUp(PartOfTest part) {
13276 linear_congruential_generator = i::FLAG_testing_prng_seed;
13278 int count = RegisterThreadedTest::count();
13279 int start = count * part / (LAST_PART + 1);
13280 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13281 active_tests_ = tests_being_run_ = end - start + 1;
13282 for (int i = 0; i < tests_being_run_; i++) {
13283 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13285 for (int i = 0; i < active_tests_; i++) {
13286 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13291 static void CallTestNumber(int test_number) {
13292 (RegisterThreadedTest::nth(test_number)->callback())();
13296 void ApiTestFuzzer::RunAllTests() {
13297 // Set off the first test.
13300 // Wait till they are all done.
13301 all_tests_done_.Wait();
13305 int ApiTestFuzzer::GetNextTestNumber() {
13308 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13309 linear_congruential_generator *= 1664525u;
13310 linear_congruential_generator += 1013904223u;
13311 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13316 void ApiTestFuzzer::ContextSwitch() {
13317 // If the new thread is the same as the current thread there is nothing to do.
13318 if (NextThread()) {
13319 // Now it can start.
13320 v8::Unlocker unlocker(CcTest::isolate());
13321 // Wait till someone starts us again.
13328 void ApiTestFuzzer::TearDown() {
13330 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13331 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13332 if (fuzzer != NULL) fuzzer->Join();
13337 // Lets not be needlessly self-referential.
13339 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13340 ApiTestFuzzer::RunAllTests();
13341 ApiTestFuzzer::TearDown();
13346 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13347 ApiTestFuzzer::RunAllTests();
13348 ApiTestFuzzer::TearDown();
13353 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13354 ApiTestFuzzer::RunAllTests();
13355 ApiTestFuzzer::TearDown();
13360 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13361 ApiTestFuzzer::RunAllTests();
13362 ApiTestFuzzer::TearDown();
13366 void ApiTestFuzzer::CallTest() {
13367 v8::Isolate::Scope scope(CcTest::isolate());
13369 printf("Start test %d\n", test_number_);
13370 CallTestNumber(test_number_);
13372 printf("End test %d\n", test_number_);
13376 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13377 v8::Isolate* isolate = args.GetIsolate();
13378 CHECK(v8::Locker::IsLocked(isolate));
13379 ApiTestFuzzer::Fuzz();
13380 v8::Unlocker unlocker(isolate);
13381 const char* code = "throw 7;";
13383 v8::Locker nested_locker(isolate);
13384 v8::HandleScope scope(isolate);
13385 v8::Handle<Value> exception;
13386 { v8::TryCatch try_catch;
13387 v8::Handle<Value> value = CompileRun(code);
13388 CHECK(value.IsEmpty());
13389 CHECK(try_catch.HasCaught());
13390 // Make sure to wrap the exception in a new handle because
13391 // the handle returned from the TryCatch is destroyed
13392 // when the TryCatch is destroyed.
13393 exception = Local<Value>::New(isolate, try_catch.Exception());
13395 args.GetIsolate()->ThrowException(exception);
13400 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13401 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13402 ApiTestFuzzer::Fuzz();
13403 v8::Unlocker unlocker(CcTest::isolate());
13404 const char* code = "throw 7;";
13406 v8::Locker nested_locker(CcTest::isolate());
13407 v8::HandleScope scope(args.GetIsolate());
13408 v8::Handle<Value> value = CompileRun(code);
13409 CHECK(value.IsEmpty());
13410 args.GetReturnValue().Set(v8_str("foo"));
13415 // These are locking tests that don't need to be run again
13416 // as part of the locking aggregation tests.
13417 TEST(NestedLockers) {
13418 v8::Isolate* isolate = CcTest::isolate();
13419 v8::Locker locker(isolate);
13420 CHECK(v8::Locker::IsLocked(isolate));
13422 v8::HandleScope scope(env->GetIsolate());
13423 Local<v8::FunctionTemplate> fun_templ =
13424 v8::FunctionTemplate::New(isolate, ThrowInJS);
13425 Local<Function> fun = fun_templ->GetFunction();
13426 env->Global()->Set(v8_str("throw_in_js"), fun);
13427 Local<Script> script = v8_compile("(function () {"
13435 CHECK_EQ(91, script->Run()->Int32Value());
13439 // These are locking tests that don't need to be run again
13440 // as part of the locking aggregation tests.
13441 TEST(NestedLockersNoTryCatch) {
13442 v8::Locker locker(CcTest::isolate());
13444 v8::HandleScope scope(env->GetIsolate());
13445 Local<v8::FunctionTemplate> fun_templ =
13446 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13447 Local<Function> fun = fun_templ->GetFunction();
13448 env->Global()->Set(v8_str("throw_in_js"), fun);
13449 Local<Script> script = v8_compile("(function () {"
13457 CHECK_EQ(91, script->Run()->Int32Value());
13461 THREADED_TEST(RecursiveLocking) {
13462 v8::Locker locker(CcTest::isolate());
13464 v8::Locker locker2(CcTest::isolate());
13465 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13470 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13471 ApiTestFuzzer::Fuzz();
13472 v8::Unlocker unlocker(CcTest::isolate());
13476 THREADED_TEST(LockUnlockLock) {
13478 v8::Locker locker(CcTest::isolate());
13479 v8::HandleScope scope(CcTest::isolate());
13481 Local<v8::FunctionTemplate> fun_templ =
13482 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13483 Local<Function> fun = fun_templ->GetFunction();
13484 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13485 Local<Script> script = v8_compile("(function () {"
13486 " unlock_for_a_moment();"
13489 CHECK_EQ(42, script->Run()->Int32Value());
13492 v8::Locker locker(CcTest::isolate());
13493 v8::HandleScope scope(CcTest::isolate());
13495 Local<v8::FunctionTemplate> fun_templ =
13496 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13497 Local<Function> fun = fun_templ->GetFunction();
13498 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13499 Local<Script> script = v8_compile("(function () {"
13500 " unlock_for_a_moment();"
13503 CHECK_EQ(42, script->Run()->Int32Value());
13508 static int GetGlobalObjectsCount() {
13510 i::HeapIterator it(CcTest::heap());
13511 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13512 if (object->IsJSGlobalObject()) count++;
13517 static void CheckSurvivingGlobalObjectsCount(int expected) {
13518 // We need to collect all garbage twice to be sure that everything
13519 // has been collected. This is because inline caches are cleared in
13520 // the first garbage collection but some of the maps have already
13521 // been marked at that point. Therefore some of the maps are not
13522 // collected until the second garbage collection.
13523 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13524 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13525 int count = GetGlobalObjectsCount();
13527 if (count != expected) CcTest::heap()->TracePathToGlobal();
13529 CHECK_EQ(expected, count);
13533 TEST(DontLeakGlobalObjects) {
13534 // Regression test for issues 1139850 and 1174891.
13536 i::FLAG_expose_gc = true;
13537 v8::V8::Initialize();
13539 for (int i = 0; i < 5; i++) {
13540 { v8::HandleScope scope(CcTest::isolate());
13541 LocalContext context;
13543 CcTest::isolate()->ContextDisposedNotification();
13544 CheckSurvivingGlobalObjectsCount(0);
13546 { v8::HandleScope scope(CcTest::isolate());
13547 LocalContext context;
13548 v8_compile("Date")->Run();
13550 CcTest::isolate()->ContextDisposedNotification();
13551 CheckSurvivingGlobalObjectsCount(0);
13553 { v8::HandleScope scope(CcTest::isolate());
13554 LocalContext context;
13555 v8_compile("/aaa/")->Run();
13557 CcTest::isolate()->ContextDisposedNotification();
13558 CheckSurvivingGlobalObjectsCount(0);
13560 { v8::HandleScope scope(CcTest::isolate());
13561 const char* extension_list[] = { "v8/gc" };
13562 v8::ExtensionConfiguration extensions(1, extension_list);
13563 LocalContext context(&extensions);
13564 v8_compile("gc();")->Run();
13566 CcTest::isolate()->ContextDisposedNotification();
13567 CheckSurvivingGlobalObjectsCount(0);
13572 TEST(CopyablePersistent) {
13573 LocalContext context;
13574 v8::Isolate* isolate = context->GetIsolate();
13575 i::GlobalHandles* globals =
13576 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13577 int initial_handles = globals->global_handles_count();
13578 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13581 CopyableObject handle1;
13583 v8::HandleScope scope(isolate);
13584 handle1.Reset(isolate, v8::Object::New(isolate));
13586 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13587 CopyableObject handle2;
13589 CHECK(handle1 == handle2);
13590 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13591 CopyableObject handle3(handle2);
13592 CHECK(handle1 == handle3);
13593 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13595 // Verify autodispose
13596 CHECK_EQ(initial_handles, globals->global_handles_count());
13600 static void WeakApiCallback(
13601 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13602 Local<Value> value = data.GetValue()->Get(v8_str("key"));
13603 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13604 data.GetParameter()->Reset();
13605 delete data.GetParameter();
13609 TEST(WeakCallbackApi) {
13610 LocalContext context;
13611 v8::Isolate* isolate = context->GetIsolate();
13612 i::GlobalHandles* globals =
13613 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13614 int initial_handles = globals->global_handles_count();
13616 v8::HandleScope scope(isolate);
13617 v8::Local<v8::Object> obj = v8::Object::New(isolate);
13618 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13619 v8::Persistent<v8::Object>* handle =
13620 new v8::Persistent<v8::Object>(isolate, obj);
13621 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13624 reinterpret_cast<i::Isolate*>(isolate)->heap()->
13625 CollectAllGarbage(i::Heap::kNoGCFlags);
13626 // Verify disposed.
13627 CHECK_EQ(initial_handles, globals->global_handles_count());
13631 v8::Persistent<v8::Object> some_object;
13632 v8::Persistent<v8::Object> bad_handle;
13634 void NewPersistentHandleCallback(
13635 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13636 v8::HandleScope scope(data.GetIsolate());
13637 bad_handle.Reset(data.GetIsolate(), some_object);
13638 data.GetParameter()->Reset();
13642 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13643 LocalContext context;
13644 v8::Isolate* isolate = context->GetIsolate();
13646 v8::Persistent<v8::Object> handle1, handle2;
13648 v8::HandleScope scope(isolate);
13649 some_object.Reset(isolate, v8::Object::New(isolate));
13650 handle1.Reset(isolate, v8::Object::New(isolate));
13651 handle2.Reset(isolate, v8::Object::New(isolate));
13653 // Note: order is implementation dependent alas: currently
13654 // global handle nodes are processed by PostGarbageCollectionProcessing
13655 // in reverse allocation order, so if second allocated handle is deleted,
13656 // weak callback of the first handle would be able to 'reallocate' it.
13657 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13659 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13663 v8::Persistent<v8::Object> to_be_disposed;
13665 void DisposeAndForceGcCallback(
13666 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13667 to_be_disposed.Reset();
13668 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13669 data.GetParameter()->Reset();
13673 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13674 LocalContext context;
13675 v8::Isolate* isolate = context->GetIsolate();
13677 v8::Persistent<v8::Object> handle1, handle2;
13679 v8::HandleScope scope(isolate);
13680 handle1.Reset(isolate, v8::Object::New(isolate));
13681 handle2.Reset(isolate, v8::Object::New(isolate));
13683 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13684 to_be_disposed.Reset(isolate, handle2);
13685 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13688 void DisposingCallback(
13689 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13690 data.GetParameter()->Reset();
13693 void HandleCreatingCallback(
13694 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13695 v8::HandleScope scope(data.GetIsolate());
13696 v8::Persistent<v8::Object>(data.GetIsolate(),
13697 v8::Object::New(data.GetIsolate()));
13698 data.GetParameter()->Reset();
13702 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13703 LocalContext context;
13704 v8::Isolate* isolate = context->GetIsolate();
13706 v8::Persistent<v8::Object> handle1, handle2, handle3;
13708 v8::HandleScope scope(isolate);
13709 handle3.Reset(isolate, v8::Object::New(isolate));
13710 handle2.Reset(isolate, v8::Object::New(isolate));
13711 handle1.Reset(isolate, v8::Object::New(isolate));
13713 handle2.SetWeak(&handle2, DisposingCallback);
13714 handle3.SetWeak(&handle3, HandleCreatingCallback);
13715 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13719 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13720 v8::V8::Initialize();
13723 const char* sources[nof] = {
13724 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13728 for (int i = 0; i < nof; i++) {
13729 const char* source = sources[i];
13730 { v8::HandleScope scope(CcTest::isolate());
13731 LocalContext context;
13732 CompileRun(source);
13734 { v8::HandleScope scope(CcTest::isolate());
13735 LocalContext context;
13736 CompileRun(source);
13742 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13743 v8::EscapableHandleScope inner(env->GetIsolate());
13745 v8::Local<Value> three = v8_num(3);
13746 v8::Local<Value> value = inner.Escape(three);
13752 THREADED_TEST(NestedHandleScopeAndContexts) {
13753 v8::Isolate* isolate = CcTest::isolate();
13754 v8::HandleScope outer(isolate);
13755 v8::Local<Context> env = Context::New(isolate);
13757 v8::Handle<Value> value = NestedScope(env);
13758 v8::Handle<String> str(value->ToString());
13759 CHECK(!str.IsEmpty());
13764 static bool MatchPointers(void* key1, void* key2) {
13765 return key1 == key2;
13769 struct SymbolInfo {
13776 class SetFunctionEntryHookTest {
13778 SetFunctionEntryHookTest() {
13779 CHECK(instance_ == NULL);
13782 ~SetFunctionEntryHookTest() {
13783 CHECK(instance_ == this);
13788 symbol_locations_.clear();
13789 invocations_.clear();
13792 void OnJitEvent(const v8::JitCodeEvent* event);
13793 static void JitEvent(const v8::JitCodeEvent* event) {
13794 CHECK(instance_ != NULL);
13795 instance_->OnJitEvent(event);
13798 void OnEntryHook(uintptr_t function,
13799 uintptr_t return_addr_location);
13800 static void EntryHook(uintptr_t function,
13801 uintptr_t return_addr_location) {
13802 CHECK(instance_ != NULL);
13803 instance_->OnEntryHook(function, return_addr_location);
13806 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13807 CHECK(instance_ != NULL);
13808 args.GetReturnValue().Set(v8_num(42));
13810 void RunLoopInNewEnv(v8::Isolate* isolate);
13812 // Records addr as location of symbol.
13813 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13815 // Finds the symbol containing addr
13816 SymbolInfo* FindSymbolForAddr(i::Address addr);
13817 // Returns the number of invocations where the caller name contains
13818 // \p caller_name and the function name contains \p function_name.
13819 int CountInvocations(const char* caller_name,
13820 const char* function_name);
13822 i::Handle<i::JSFunction> foo_func_;
13823 i::Handle<i::JSFunction> bar_func_;
13825 typedef std::map<size_t, SymbolInfo> SymbolMap;
13826 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13827 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13828 SymbolMap symbols_;
13829 SymbolLocationMap symbol_locations_;
13830 InvocationMap invocations_;
13832 static SetFunctionEntryHookTest* instance_;
13834 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13837 // Returns true if addr is in the range [start, start+len).
13838 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13839 if (start <= addr && start + len > addr)
13845 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13846 SymbolInfo* symbol) {
13847 // Insert the symbol at the new location.
13848 SymbolLocationMap::iterator it =
13849 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13850 // Now erase symbols to the left and right that overlap this one.
13851 while (it != symbol_locations_.begin()) {
13852 SymbolLocationMap::iterator left = it;
13854 if (!Overlaps(left->first, left->second->size, addr))
13856 symbol_locations_.erase(left);
13859 // Now erase symbols to the left and right that overlap this one.
13861 SymbolLocationMap::iterator right = it;
13863 if (right == symbol_locations_.end())
13865 if (!Overlaps(addr, symbol->size, right->first))
13867 symbol_locations_.erase(right);
13872 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13873 switch (event->type) {
13874 case v8::JitCodeEvent::CODE_ADDED: {
13875 CHECK(event->code_start != NULL);
13876 CHECK_NE(0, static_cast<int>(event->code_len));
13877 CHECK(event->name.str != NULL);
13878 size_t symbol_id = symbols_.size();
13880 // Record the new symbol.
13881 SymbolInfo& info = symbols_[symbol_id];
13882 info.id = symbol_id;
13883 info.size = event->code_len;
13884 info.name.assign(event->name.str, event->name.str + event->name.len);
13886 // And record it's location.
13887 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13891 case v8::JitCodeEvent::CODE_MOVED: {
13892 // We would like to never see code move that we haven't seen before,
13893 // but the code creation event does not happen until the line endings
13894 // have been calculated (this is so that we can report the line in the
13895 // script at which the function source is found, see
13896 // Compiler::RecordFunctionCompilation) and the line endings
13897 // calculations can cause a GC, which can move the newly created code
13898 // before its existence can be logged.
13899 SymbolLocationMap::iterator it(
13900 symbol_locations_.find(
13901 reinterpret_cast<i::Address>(event->code_start)));
13902 if (it != symbol_locations_.end()) {
13903 // Found a symbol at this location, move it.
13904 SymbolInfo* info = it->second;
13905 symbol_locations_.erase(it);
13906 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13915 void SetFunctionEntryHookTest::OnEntryHook(
13916 uintptr_t function, uintptr_t return_addr_location) {
13917 // Get the function's code object.
13918 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13919 reinterpret_cast<i::Address>(function));
13920 CHECK(function_code != NULL);
13922 // Then try and look up the caller's code object.
13923 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13925 // Count the invocation.
13926 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13927 SymbolInfo* function_symbol =
13928 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13929 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13931 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13932 // Check that we have a symbol for the "bar" function at the right location.
13933 SymbolLocationMap::iterator it(
13934 symbol_locations_.find(function_code->instruction_start()));
13935 CHECK(it != symbol_locations_.end());
13938 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13939 // Check that we have a symbol for "foo" at the right location.
13940 SymbolLocationMap::iterator it(
13941 symbol_locations_.find(function_code->instruction_start()));
13942 CHECK(it != symbol_locations_.end());
13947 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13948 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13949 // Do we have a direct hit on a symbol?
13950 if (it != symbol_locations_.end()) {
13951 if (it->first == addr)
13955 // If not a direct hit, it'll have to be the previous symbol.
13956 if (it == symbol_locations_.begin())
13960 size_t offs = addr - it->first;
13961 if (offs < it->second->size)
13968 int SetFunctionEntryHookTest::CountInvocations(
13969 const char* caller_name, const char* function_name) {
13970 InvocationMap::iterator it(invocations_.begin());
13971 int invocations = 0;
13972 for (; it != invocations_.end(); ++it) {
13973 SymbolInfo* caller = it->first.first;
13974 SymbolInfo* function = it->first.second;
13976 // Filter out non-matching functions.
13977 if (function_name != NULL) {
13978 if (function->name.find(function_name) == std::string::npos)
13982 // Filter out non-matching callers.
13983 if (caller_name != NULL) {
13984 if (caller == NULL)
13986 if (caller->name.find(caller_name) == std::string::npos)
13990 // It matches add the invocation count to the tally.
13991 invocations += it->second;
13994 return invocations;
13998 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13999 v8::HandleScope outer(isolate);
14000 v8::Local<Context> env = Context::New(isolate);
14003 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14004 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14005 env->Global()->Set(v8_str("obj"), t->NewInstance());
14007 const char* script =
14008 "function bar() {\n"
14010 " for (i = 0; i < 100; ++i)\n"
14014 "function foo(i) { return i * i; }\n"
14015 "// Invoke on the runtime function.\n"
14017 CompileRun(script);
14018 bar_func_ = i::Handle<i::JSFunction>::cast(
14019 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14020 DCHECK(!bar_func_.is_null());
14023 i::Handle<i::JSFunction>::cast(
14024 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14025 DCHECK(!foo_func_.is_null());
14027 v8::Handle<v8::Value> value = CompileRun("bar();");
14028 CHECK(value->IsNumber());
14029 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14031 // Test the optimized codegen path.
14032 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14034 CHECK(value->IsNumber());
14035 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14041 void SetFunctionEntryHookTest::RunTest() {
14042 // Work in a new isolate throughout.
14043 v8::Isolate* isolate = v8::Isolate::New();
14045 // Test setting the entry hook on the new isolate.
14046 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14048 // Replacing the hook, once set should fail.
14049 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14052 v8::Isolate::Scope scope(isolate);
14054 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14056 RunLoopInNewEnv(isolate);
14058 // Check the exepected invocation counts.
14059 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14060 CHECK_EQ(200, CountInvocations("bar", "foo"));
14061 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14063 // Verify that we have an entry hook on some specific stubs.
14064 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14065 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14066 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14068 isolate->Dispose();
14072 // Make sure a second isolate is unaffected by the previous entry hook.
14073 isolate = v8::Isolate::New();
14075 v8::Isolate::Scope scope(isolate);
14077 // Reset the entry count to zero and set the entry hook.
14078 RunLoopInNewEnv(isolate);
14080 // We should record no invocations in this isolate.
14081 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14083 // Since the isolate has been used, we shouldn't be able to set an entry
14085 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14087 isolate->Dispose();
14091 TEST(SetFunctionEntryHook) {
14092 // FunctionEntryHook does not work well with experimental natives.
14093 // Experimental natives are compiled during snapshot deserialization.
14094 // This test breaks because InstallGetter (function from snapshot that
14095 // only gets called from experimental natives) is compiled with entry hooks.
14096 i::FLAG_allow_natives_syntax = true;
14097 i::FLAG_use_inlining = false;
14099 SetFunctionEntryHookTest test;
14104 static i::HashMap* code_map = NULL;
14105 static i::HashMap* jitcode_line_info = NULL;
14106 static int saw_bar = 0;
14107 static int move_events = 0;
14110 static bool FunctionNameIs(const char* expected,
14111 const v8::JitCodeEvent* event) {
14112 // Log lines for functions are of the general form:
14113 // "LazyCompile:<type><function_name>", where the type is one of
14115 static const char kPreamble[] = "LazyCompile:";
14116 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14118 if (event->name.len < sizeof(kPreamble) - 1 ||
14119 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14123 const char* tail = event->name.str + kPreambleLen;
14124 size_t tail_len = event->name.len - kPreambleLen;
14125 size_t expected_len = strlen(expected);
14126 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14131 // Check for tails like 'bar :1'.
14132 if (tail_len > expected_len + 2 &&
14133 tail[expected_len] == ' ' &&
14134 tail[expected_len + 1] == ':' &&
14135 tail[expected_len + 2] &&
14136 !strncmp(tail, expected, expected_len)) {
14140 if (tail_len != expected_len)
14143 return strncmp(tail, expected, expected_len) == 0;
14147 static void event_handler(const v8::JitCodeEvent* event) {
14148 CHECK(event != NULL);
14149 CHECK(code_map != NULL);
14150 CHECK(jitcode_line_info != NULL);
14152 class DummyJitCodeLineInfo {
14155 switch (event->type) {
14156 case v8::JitCodeEvent::CODE_ADDED: {
14157 CHECK(event->code_start != NULL);
14158 CHECK_NE(0, static_cast<int>(event->code_len));
14159 CHECK(event->name.str != NULL);
14160 i::HashMap::Entry* entry =
14161 code_map->Lookup(event->code_start,
14162 i::ComputePointerHash(event->code_start),
14164 entry->value = reinterpret_cast<void*>(event->code_len);
14166 if (FunctionNameIs("bar", event)) {
14172 case v8::JitCodeEvent::CODE_MOVED: {
14173 uint32_t hash = i::ComputePointerHash(event->code_start);
14174 // We would like to never see code move that we haven't seen before,
14175 // but the code creation event does not happen until the line endings
14176 // have been calculated (this is so that we can report the line in the
14177 // script at which the function source is found, see
14178 // Compiler::RecordFunctionCompilation) and the line endings
14179 // calculations can cause a GC, which can move the newly created code
14180 // before its existence can be logged.
14181 i::HashMap::Entry* entry =
14182 code_map->Lookup(event->code_start, hash, false);
14183 if (entry != NULL) {
14186 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14187 code_map->Remove(event->code_start, hash);
14189 entry = code_map->Lookup(event->new_code_start,
14190 i::ComputePointerHash(event->new_code_start),
14192 CHECK(entry != NULL);
14193 entry->value = reinterpret_cast<void*>(event->code_len);
14198 case v8::JitCodeEvent::CODE_REMOVED:
14199 // Object/code removal events are currently not dispatched from the GC.
14203 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14204 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14205 // record it in jitcode_line_info.
14206 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14207 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14208 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14209 temp_event->user_data = line_info;
14210 i::HashMap::Entry* entry =
14211 jitcode_line_info->Lookup(line_info,
14212 i::ComputePointerHash(line_info),
14214 entry->value = reinterpret_cast<void*>(line_info);
14217 // For these two events, we will check whether the event->user_data
14218 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14219 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14220 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14221 CHECK(event->user_data != NULL);
14222 uint32_t hash = i::ComputePointerHash(event->user_data);
14223 i::HashMap::Entry* entry =
14224 jitcode_line_info->Lookup(event->user_data, hash, false);
14225 CHECK(entry != NULL);
14226 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14230 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14231 CHECK(event->user_data != NULL);
14232 uint32_t hash = i::ComputePointerHash(event->user_data);
14233 i::HashMap::Entry* entry =
14234 jitcode_line_info->Lookup(event->user_data, hash, false);
14235 CHECK(entry != NULL);
14240 // Impossible event.
14247 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14248 i::FLAG_stress_compaction = true;
14249 i::FLAG_incremental_marking = false;
14250 if (i::FLAG_never_compact) return;
14251 const char* script =
14254 " for (i = 0; i < 100; ++i)"
14258 "function foo(i) { return i * i; };"
14261 // Run this test in a new isolate to make sure we don't
14262 // have remnants of state from other code.
14263 v8::Isolate* isolate = v8::Isolate::New();
14265 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14266 i::Heap* heap = i_isolate->heap();
14269 v8::HandleScope scope(isolate);
14270 i::HashMap code(MatchPointers);
14273 i::HashMap lineinfo(MatchPointers);
14274 jitcode_line_info = &lineinfo;
14279 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14281 // Generate new code objects sparsely distributed across several
14282 // different fragmented code-space pages.
14283 const int kIterations = 10;
14284 for (int i = 0; i < kIterations; ++i) {
14285 LocalContext env(isolate);
14286 i::AlwaysAllocateScope always_allocate(i_isolate);
14287 SimulateFullSpace(heap->code_space());
14288 CompileRun(script);
14290 // Keep a strong reference to the code object in the handle scope.
14291 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14292 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14293 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14294 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14296 // Clear the compilation cache to get more wastage.
14297 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14300 // Force code movement.
14301 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14303 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14305 CHECK_LE(kIterations, saw_bar);
14306 CHECK_LT(0, move_events);
14309 jitcode_line_info = NULL;
14313 isolate->Dispose();
14315 // Do this in a new isolate.
14316 isolate = v8::Isolate::New();
14319 // Verify that we get callbacks for existing code objects when we
14320 // request enumeration of existing code.
14322 v8::HandleScope scope(isolate);
14323 LocalContext env(isolate);
14324 CompileRun(script);
14326 // Now get code through initial iteration.
14327 i::HashMap code(MatchPointers);
14330 i::HashMap lineinfo(MatchPointers);
14331 jitcode_line_info = &lineinfo;
14333 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14334 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14336 jitcode_line_info = NULL;
14337 // We expect that we got some events. Note that if we could get code removal
14338 // notifications, we could compare two collections, one created by listening
14339 // from the time of creation of an isolate, and the other by subscribing
14340 // with EnumExisting.
14341 CHECK_LT(0, code.occupancy());
14347 isolate->Dispose();
14351 THREADED_TEST(ExternalAllocatedMemory) {
14352 v8::Isolate* isolate = CcTest::isolate();
14353 v8::HandleScope outer(isolate);
14354 v8::Local<Context> env(Context::New(isolate));
14355 CHECK(!env.IsEmpty());
14356 const int64_t kSize = 1024*1024;
14357 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14358 CHECK_EQ(baseline + kSize,
14359 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14361 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14365 // Regression test for issue 54, object templates with internal fields
14366 // but no accessors or interceptors did not get their internal field
14367 // count set on instances.
14368 THREADED_TEST(Regress54) {
14369 LocalContext context;
14370 v8::Isolate* isolate = context->GetIsolate();
14371 v8::HandleScope outer(isolate);
14372 static v8::Persistent<v8::ObjectTemplate> templ;
14373 if (templ.IsEmpty()) {
14374 v8::EscapableHandleScope inner(isolate);
14375 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14376 local->SetInternalFieldCount(1);
14377 templ.Reset(isolate, inner.Escape(local));
14379 v8::Handle<v8::Object> result =
14380 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14381 CHECK_EQ(1, result->InternalFieldCount());
14385 // If part of the threaded tests, this test makes ThreadingTest fail
14387 TEST(CatchStackOverflow) {
14388 LocalContext context;
14389 v8::HandleScope scope(context->GetIsolate());
14390 v8::TryCatch try_catch;
14391 v8::Handle<v8::Value> result = CompileRun(
14397 CHECK(result.IsEmpty());
14401 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14402 const char* resource_name,
14404 v8::HandleScope scope(CcTest::isolate());
14405 v8::TryCatch try_catch;
14406 v8::Handle<v8::Value> result = script->Run();
14407 CHECK(result.IsEmpty());
14408 CHECK(try_catch.HasCaught());
14409 v8::Handle<v8::Message> message = try_catch.Message();
14410 CHECK(!message.IsEmpty());
14411 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14412 CHECK_EQ(91, message->GetStartPosition());
14413 CHECK_EQ(92, message->GetEndPosition());
14414 CHECK_EQ(2, message->GetStartColumn());
14415 CHECK_EQ(3, message->GetEndColumn());
14416 v8::String::Utf8Value line(message->GetSourceLine());
14417 CHECK_EQ(" throw 'nirk';", *line);
14418 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14419 CHECK_EQ(resource_name, *name);
14423 THREADED_TEST(TryCatchSourceInfo) {
14424 LocalContext context;
14425 v8::HandleScope scope(context->GetIsolate());
14426 v8::Local<v8::String> source = v8_str(
14427 "function Foo() {\n"
14431 "function Bar() {\n"
14435 "function Baz() {\n"
14441 const char* resource_name;
14442 v8::Handle<v8::Script> script;
14443 resource_name = "test.js";
14444 script = CompileWithOrigin(source, resource_name);
14445 CheckTryCatchSourceInfo(script, resource_name, 0);
14447 resource_name = "test1.js";
14448 v8::ScriptOrigin origin1(
14449 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14450 script = v8::Script::Compile(source, &origin1);
14451 CheckTryCatchSourceInfo(script, resource_name, 0);
14453 resource_name = "test2.js";
14454 v8::ScriptOrigin origin2(
14455 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14456 v8::Integer::New(context->GetIsolate(), 7));
14457 script = v8::Script::Compile(source, &origin2);
14458 CheckTryCatchSourceInfo(script, resource_name, 7);
14462 THREADED_TEST(CompilationCache) {
14463 LocalContext context;
14464 v8::HandleScope scope(context->GetIsolate());
14465 v8::Handle<v8::String> source0 =
14466 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14467 v8::Handle<v8::String> source1 =
14468 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14469 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14470 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14471 v8::Handle<v8::Script> script2 =
14472 v8::Script::Compile(source0); // different origin
14473 CHECK_EQ(1234, script0->Run()->Int32Value());
14474 CHECK_EQ(1234, script1->Run()->Int32Value());
14475 CHECK_EQ(1234, script2->Run()->Int32Value());
14479 static void FunctionNameCallback(
14480 const v8::FunctionCallbackInfo<v8::Value>& args) {
14481 ApiTestFuzzer::Fuzz();
14482 args.GetReturnValue().Set(v8_num(42));
14486 THREADED_TEST(CallbackFunctionName) {
14487 LocalContext context;
14488 v8::Isolate* isolate = context->GetIsolate();
14489 v8::HandleScope scope(isolate);
14490 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14491 t->Set(v8_str("asdf"),
14492 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14493 context->Global()->Set(v8_str("obj"), t->NewInstance());
14494 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14495 CHECK(value->IsString());
14496 v8::String::Utf8Value name(value);
14497 CHECK_EQ("asdf", *name);
14501 THREADED_TEST(DateAccess) {
14502 LocalContext context;
14503 v8::HandleScope scope(context->GetIsolate());
14504 v8::Handle<v8::Value> date =
14505 v8::Date::New(context->GetIsolate(), 1224744689038.0);
14506 CHECK(date->IsDate());
14507 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14511 void CheckProperties(v8::Isolate* isolate,
14512 v8::Handle<v8::Value> val,
14514 const char* elmv[]) {
14515 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14516 v8::Handle<v8::Array> props = obj->GetPropertyNames();
14517 CHECK_EQ(elmc, props->Length());
14518 for (int i = 0; i < elmc; i++) {
14519 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14520 CHECK_EQ(elmv[i], *elm);
14525 void CheckOwnProperties(v8::Isolate* isolate,
14526 v8::Handle<v8::Value> val,
14528 const char* elmv[]) {
14529 v8::Handle<v8::Object> obj = val.As<v8::Object>();
14530 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14531 CHECK_EQ(elmc, props->Length());
14532 for (int i = 0; i < elmc; i++) {
14533 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14534 CHECK_EQ(elmv[i], *elm);
14539 THREADED_TEST(PropertyEnumeration) {
14540 LocalContext context;
14541 v8::Isolate* isolate = context->GetIsolate();
14542 v8::HandleScope scope(isolate);
14543 v8::Handle<v8::Value> obj = CompileRun(
14546 "result[1] = {a: 1, b: 2};"
14547 "result[2] = [1, 2, 3];"
14548 "var proto = {x: 1, y: 2, z: 3};"
14549 "var x = { __proto__: proto, w: 0, z: 1 };"
14552 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14553 CHECK_EQ(4, elms->Length());
14555 const char** elmv0 = NULL;
14557 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14558 CheckOwnProperties(
14559 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14561 const char* elmv1[] = {"a", "b"};
14563 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14564 CheckOwnProperties(
14565 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14567 const char* elmv2[] = {"0", "1", "2"};
14569 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14570 CheckOwnProperties(
14571 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14573 const char* elmv3[] = {"w", "z", "x", "y"};
14575 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14577 const char* elmv4[] = {"w", "z"};
14578 CheckOwnProperties(
14579 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14583 THREADED_TEST(PropertyEnumeration2) {
14584 LocalContext context;
14585 v8::Isolate* isolate = context->GetIsolate();
14586 v8::HandleScope scope(isolate);
14587 v8::Handle<v8::Value> obj = CompileRun(
14590 "result[1] = {a: 1, b: 2};"
14591 "result[2] = [1, 2, 3];"
14592 "var proto = {x: 1, y: 2, z: 3};"
14593 "var x = { __proto__: proto, w: 0, z: 1 };"
14596 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14597 CHECK_EQ(4, elms->Length());
14599 const char** elmv0 = NULL;
14600 CheckProperties(isolate,
14601 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14603 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14604 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14605 CHECK_EQ(0, props->Length());
14606 for (uint32_t i = 0; i < props->Length(); i++) {
14607 printf("p[%d]\n", i);
14611 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14613 v8::AccessType type,
14614 Local<Value> data) {
14615 return type != v8::ACCESS_SET;
14619 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14621 v8::AccessType type,
14622 Local<Value> data) {
14623 return type != v8::ACCESS_SET;
14627 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14628 LocalContext context;
14629 v8::Isolate* isolate = context->GetIsolate();
14630 v8::HandleScope scope(isolate);
14631 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14632 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14633 IndexedSetAccessBlocker);
14634 templ->Set(v8_str("x"), v8::True(isolate));
14635 Local<v8::Object> instance = templ->NewInstance();
14636 context->Global()->Set(v8_str("obj"), instance);
14637 Local<Value> value = CompileRun("obj.x");
14638 CHECK(value->BooleanValue());
14642 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14644 v8::AccessType type,
14645 Local<Value> data) {
14650 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14652 v8::AccessType type,
14653 Local<Value> data) {
14659 THREADED_TEST(AccessChecksReenabledCorrectly) {
14660 LocalContext context;
14661 v8::Isolate* isolate = context->GetIsolate();
14662 v8::HandleScope scope(isolate);
14663 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14664 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14665 IndexedGetAccessBlocker);
14666 templ->Set(v8_str("a"), v8_str("a"));
14667 // Add more than 8 (see kMaxFastProperties) properties
14668 // so that the constructor will force copying map.
14669 // Cannot sprintf, gcc complains unsafety.
14671 for (char i = '0'; i <= '9' ; i++) {
14673 for (char j = '0'; j <= '9'; j++) {
14675 for (char k = '0'; k <= '9'; k++) {
14678 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14683 Local<v8::Object> instance_1 = templ->NewInstance();
14684 context->Global()->Set(v8_str("obj_1"), instance_1);
14686 Local<Value> value_1 = CompileRun("obj_1.a");
14687 CHECK(value_1.IsEmpty());
14689 Local<v8::Object> instance_2 = templ->NewInstance();
14690 context->Global()->Set(v8_str("obj_2"), instance_2);
14692 Local<Value> value_2 = CompileRun("obj_2.a");
14693 CHECK(value_2.IsEmpty());
14697 // This tests that access check information remains on the global
14698 // object template when creating contexts.
14699 THREADED_TEST(AccessControlRepeatedContextCreation) {
14700 v8::Isolate* isolate = CcTest::isolate();
14701 v8::HandleScope handle_scope(isolate);
14702 v8::Handle<v8::ObjectTemplate> global_template =
14703 v8::ObjectTemplate::New(isolate);
14704 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14705 IndexedSetAccessBlocker);
14706 i::Handle<i::ObjectTemplateInfo> internal_template =
14707 v8::Utils::OpenHandle(*global_template);
14708 CHECK(!internal_template->constructor()->IsUndefined());
14709 i::Handle<i::FunctionTemplateInfo> constructor(
14710 i::FunctionTemplateInfo::cast(internal_template->constructor()));
14711 CHECK(!constructor->access_check_info()->IsUndefined());
14712 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14713 CHECK(!context0.IsEmpty());
14714 CHECK(!constructor->access_check_info()->IsUndefined());
14718 THREADED_TEST(TurnOnAccessCheck) {
14719 v8::Isolate* isolate = CcTest::isolate();
14720 v8::HandleScope handle_scope(isolate);
14722 // Create an environment with access check to the global object disabled by
14724 v8::Handle<v8::ObjectTemplate> global_template =
14725 v8::ObjectTemplate::New(isolate);
14726 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14727 IndexedGetAccessBlocker,
14728 v8::Handle<v8::Value>(),
14730 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14731 Context::Scope context_scope(context);
14733 // Set up a property and a number of functions.
14734 context->Global()->Set(v8_str("a"), v8_num(1));
14735 CompileRun("function f1() {return a;}"
14736 "function f2() {return a;}"
14737 "function g1() {return h();}"
14738 "function g2() {return h();}"
14739 "function h() {return 1;}");
14740 Local<Function> f1 =
14741 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14742 Local<Function> f2 =
14743 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14744 Local<Function> g1 =
14745 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14746 Local<Function> g2 =
14747 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14748 Local<Function> h =
14749 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14751 // Get the global object.
14752 v8::Handle<v8::Object> global = context->Global();
14754 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14755 // uses the runtime system to retreive property a whereas f2 uses global load
14757 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14758 for (int i = 0; i < 4; i++) {
14759 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14762 // Same for g1 and g2.
14763 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14764 for (int i = 0; i < 4; i++) {
14765 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14768 // Detach the global and turn on access check.
14769 Local<Object> hidden_global = Local<Object>::Cast(
14770 context->Global()->GetPrototype());
14771 context->DetachGlobal();
14772 hidden_global->TurnOnAccessCheck();
14774 // Failing access check results in exception.
14775 CHECK(f1->Call(global, 0, NULL).IsEmpty());
14776 CHECK(f2->Call(global, 0, NULL).IsEmpty());
14777 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14778 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14780 // No failing access check when just returning a constant.
14781 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14785 static const char* kPropertyA = "a";
14786 static const char* kPropertyH = "h";
14788 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14790 v8::AccessType type,
14791 Local<Value> data) {
14792 if (!name->IsString()) return false;
14793 i::Handle<i::String> name_handle =
14794 v8::Utils::OpenHandle(String::Cast(*name));
14795 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14796 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14800 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14801 v8::Isolate* isolate = CcTest::isolate();
14802 v8::HandleScope handle_scope(isolate);
14804 // Create an environment with access check to the global object disabled by
14805 // default. When the registered access checker will block access to properties
14807 v8::Handle<v8::ObjectTemplate> global_template =
14808 v8::ObjectTemplate::New(isolate);
14809 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14810 IndexedGetAccessBlocker,
14811 v8::Handle<v8::Value>(),
14813 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14814 Context::Scope context_scope(context);
14816 // Set up a property and a number of functions.
14817 context->Global()->Set(v8_str("a"), v8_num(1));
14818 static const char* source = "function f1() {return a;}"
14819 "function f2() {return a;}"
14820 "function g1() {return h();}"
14821 "function g2() {return h();}"
14822 "function h() {return 1;}";
14824 CompileRun(source);
14825 Local<Function> f1;
14826 Local<Function> f2;
14827 Local<Function> g1;
14828 Local<Function> g2;
14830 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14831 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14832 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14833 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14834 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14836 // Get the global object.
14837 v8::Handle<v8::Object> global = context->Global();
14839 // Call f1 one time and f2 a number of times. This will ensure that f1 still
14840 // uses the runtime system to retreive property a whereas f2 uses global load
14842 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14843 for (int i = 0; i < 4; i++) {
14844 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14847 // Same for g1 and g2.
14848 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14849 for (int i = 0; i < 4; i++) {
14850 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14853 // Detach the global and turn on access check now blocking access to property
14854 // a and function h.
14855 Local<Object> hidden_global = Local<Object>::Cast(
14856 context->Global()->GetPrototype());
14857 context->DetachGlobal();
14858 hidden_global->TurnOnAccessCheck();
14860 // Failing access check results in exception.
14861 CHECK(f1->Call(global, 0, NULL).IsEmpty());
14862 CHECK(f2->Call(global, 0, NULL).IsEmpty());
14863 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14864 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14866 // No failing access check when just returning a constant.
14867 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14869 // Now compile the source again. And get the newly compiled functions, except
14870 // for h for which access is blocked.
14871 CompileRun(source);
14872 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14873 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14874 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14875 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14876 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
14878 // Failing access check results in exception.
14879 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
14880 CHECK(result.IsEmpty());
14881 CHECK(f1->Call(global, 0, NULL).IsEmpty());
14882 CHECK(f2->Call(global, 0, NULL).IsEmpty());
14883 CHECK(g1->Call(global, 0, NULL).IsEmpty());
14884 CHECK(g2->Call(global, 0, NULL).IsEmpty());
14888 // Tests that ScriptData can be serialized and deserialized.
14889 TEST(PreCompileSerialization) {
14890 v8::V8::Initialize();
14892 v8::Isolate* isolate = env->GetIsolate();
14893 HandleScope handle_scope(isolate);
14895 i::FLAG_min_preparse_length = 0;
14896 const char* script = "function foo(a) { return a+1; }";
14897 v8::ScriptCompiler::Source source(v8_str(script));
14898 v8::ScriptCompiler::Compile(isolate, &source,
14899 v8::ScriptCompiler::kProduceParserCache);
14901 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14902 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
14903 i::MemCopy(serialized_data, cd->data, cd->length);
14906 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
14908 // Verify that the original is the same as the deserialized.
14909 CHECK_EQ(cd->length, deserialized->length());
14910 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
14912 delete deserialized;
14913 i::DeleteArray(serialized_data);
14917 // This tests that we do not allow dictionary load/call inline caches
14918 // to use functions that have not yet been compiled. The potential
14919 // problem of loading a function that has not yet been compiled can
14920 // arise because we share code between contexts via the compilation
14922 THREADED_TEST(DictionaryICLoadedFunction) {
14923 v8::HandleScope scope(CcTest::isolate());
14925 for (int i = 0; i < 2; i++) {
14926 LocalContext context;
14927 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14928 context->Global()->Delete(v8_str("tmp"));
14929 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14932 for (int i = 0; i < 2; i++) {
14933 LocalContext context;
14934 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14935 context->Global()->Delete(v8_str("tmp"));
14936 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14941 // Test that cross-context new calls use the context of the callee to
14942 // create the new JavaScript object.
14943 THREADED_TEST(CrossContextNew) {
14944 v8::Isolate* isolate = CcTest::isolate();
14945 v8::HandleScope scope(isolate);
14946 v8::Local<Context> context0 = Context::New(isolate);
14947 v8::Local<Context> context1 = Context::New(isolate);
14949 // Allow cross-domain access.
14950 Local<String> token = v8_str("<security token>");
14951 context0->SetSecurityToken(token);
14952 context1->SetSecurityToken(token);
14954 // Set an 'x' property on the Object prototype and define a
14955 // constructor function in context0.
14957 CompileRun("Object.prototype.x = 42; function C() {};");
14960 // Call the constructor function from context0 and check that the
14961 // result has the 'x' property.
14963 context1->Global()->Set(v8_str("other"), context0->Global());
14964 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14965 CHECK(value->IsInt32());
14966 CHECK_EQ(42, value->Int32Value());
14971 // Verify that we can clone an object
14972 TEST(ObjectClone) {
14974 v8::Isolate* isolate = env->GetIsolate();
14975 v8::HandleScope scope(isolate);
14977 const char* sample =
14979 "rv.alpha = 'hello';" \
14983 // Create an object, verify basics.
14984 Local<Value> val = CompileRun(sample);
14985 CHECK(val->IsObject());
14986 Local<v8::Object> obj = val.As<v8::Object>();
14987 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14989 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14990 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14991 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14994 Local<v8::Object> clone = obj->Clone();
14995 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14996 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14997 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14999 // Set a property on the clone, verify each object.
15000 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15001 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15002 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15006 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15008 explicit AsciiVectorResource(i::Vector<const char> vector)
15010 virtual ~AsciiVectorResource() {}
15011 virtual size_t length() const { return data_.length(); }
15012 virtual const char* data() const { return data_.start(); }
15014 i::Vector<const char> data_;
15018 class UC16VectorResource : public v8::String::ExternalStringResource {
15020 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15022 virtual ~UC16VectorResource() {}
15023 virtual size_t length() const { return data_.length(); }
15024 virtual const i::uc16* data() const { return data_.start(); }
15026 i::Vector<const i::uc16> data_;
15030 static void MorphAString(i::String* string,
15031 AsciiVectorResource* ascii_resource,
15032 UC16VectorResource* uc16_resource) {
15033 CHECK(i::StringShape(string).IsExternal());
15034 if (string->IsOneByteRepresentation()) {
15035 // Check old map is not internalized or long.
15036 CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15037 // Morph external string to be TwoByte string.
15038 string->set_map(CcTest::heap()->external_string_map());
15039 i::ExternalTwoByteString* morphed =
15040 i::ExternalTwoByteString::cast(string);
15041 morphed->set_resource(uc16_resource);
15043 // Check old map is not internalized or long.
15044 CHECK(string->map() == CcTest::heap()->external_string_map());
15045 // Morph external string to be ASCII string.
15046 string->set_map(CcTest::heap()->external_ascii_string_map());
15047 i::ExternalAsciiString* morphed =
15048 i::ExternalAsciiString::cast(string);
15049 morphed->set_resource(ascii_resource);
15054 // Test that we can still flatten a string if the components it is built up
15055 // from have been turned into 16 bit strings in the mean time.
15056 THREADED_TEST(MorphCompositeStringTest) {
15057 char utf_buffer[129];
15058 const char* c_string = "Now is the time for all good men"
15059 " to come to the aid of the party";
15060 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15063 i::Factory* factory = CcTest::i_isolate()->factory();
15064 v8::HandleScope scope(env->GetIsolate());
15065 AsciiVectorResource ascii_resource(
15066 i::Vector<const char>(c_string, i::StrLength(c_string)));
15067 UC16VectorResource uc16_resource(
15068 i::Vector<const uint16_t>(two_byte_string,
15069 i::StrLength(c_string)));
15071 Local<String> lhs(v8::Utils::ToLocal(
15072 factory->NewExternalStringFromAscii(&ascii_resource)
15073 .ToHandleChecked()));
15074 Local<String> rhs(v8::Utils::ToLocal(
15075 factory->NewExternalStringFromAscii(&ascii_resource)
15076 .ToHandleChecked()));
15078 env->Global()->Set(v8_str("lhs"), lhs);
15079 env->Global()->Set(v8_str("rhs"), rhs);
15082 "var cons = lhs + rhs;"
15083 "var slice = lhs.substring(1, lhs.length - 1);"
15084 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15086 CHECK(lhs->IsOneByte());
15087 CHECK(rhs->IsOneByte());
15089 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15090 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15092 // This should UTF-8 without flattening, since everything is ASCII.
15093 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15094 CHECK_EQ(128, cons->Utf8Length());
15096 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15097 CHECK_EQ(128, nchars);
15098 CHECK_EQ(0, strcmp(
15100 "Now is the time for all good men to come to the aid of the party"
15101 "Now is the time for all good men to come to the aid of the party"));
15103 // Now do some stuff to make sure the strings are flattened, etc.
15105 "/[^a-z]/.test(cons);"
15106 "/[^a-z]/.test(slice);"
15107 "/[^a-z]/.test(slice_on_cons);");
15108 const char* expected_cons =
15109 "Now is the time for all good men to come to the aid of the party"
15110 "Now is the time for all good men to come to the aid of the party";
15111 const char* expected_slice =
15112 "ow is the time for all good men to come to the aid of the part";
15113 const char* expected_slice_on_cons =
15114 "ow is the time for all good men to come to the aid of the party"
15115 "Now is the time for all good men to come to the aid of the part";
15116 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15117 env->Global()->Get(v8_str("cons")));
15118 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15119 env->Global()->Get(v8_str("slice")));
15120 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15121 env->Global()->Get(v8_str("slice_on_cons")));
15123 i::DeleteArray(two_byte_string);
15127 TEST(CompileExternalTwoByteSource) {
15128 LocalContext context;
15129 v8::HandleScope scope(context->GetIsolate());
15131 // This is a very short list of sources, which currently is to check for a
15132 // regression caused by r2703.
15133 const char* ascii_sources[] = {
15135 "-0.5", // This mainly testes PushBack in the Scanner.
15136 "--0.5", // This mainly testes PushBack in the Scanner.
15140 // Compile the sources as external two byte strings.
15141 for (int i = 0; ascii_sources[i] != NULL; i++) {
15142 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15143 TestResource* uc16_resource = new TestResource(two_byte_string);
15144 v8::Local<v8::String> source =
15145 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15146 v8::Script::Compile(source);
15151 #ifndef V8_INTERPRETED_REGEXP
15153 struct RegExpInterruptionData {
15155 UC16VectorResource* string_resource;
15156 v8::Persistent<v8::String> string;
15157 } regexp_interruption_data;
15160 class RegExpInterruptionThread : public v8::base::Thread {
15162 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15163 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15165 virtual void Run() {
15166 for (regexp_interruption_data.loop_count = 0;
15167 regexp_interruption_data.loop_count < 7;
15168 regexp_interruption_data.loop_count++) {
15169 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
15170 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15172 v8::base::OS::Sleep(50); // Wait a bit before terminating.
15173 v8::V8::TerminateExecution(isolate_);
15177 v8::Isolate* isolate_;
15181 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15182 if (regexp_interruption_data.loop_count != 2) return;
15183 v8::HandleScope scope(CcTest::isolate());
15184 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15185 CcTest::isolate(), regexp_interruption_data.string);
15186 string->MakeExternal(regexp_interruption_data.string_resource);
15190 // Test that RegExp execution can be interrupted. Specifically, we test
15191 // * interrupting with GC
15192 // * turn the subject string from one-byte internal to two-byte external string
15193 // * force termination
15194 TEST(RegExpInterruption) {
15195 v8::HandleScope scope(CcTest::isolate());
15198 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15200 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15201 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15202 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15203 v8::Local<v8::String> string = v8_str(ascii_content);
15205 CcTest::global()->Set(v8_str("a"), string);
15206 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15207 regexp_interruption_data.string_resource = new UC16VectorResource(
15208 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15210 v8::TryCatch try_catch;
15211 timeout_thread.Start();
15213 CompileRun("/((a*)*)*b/.exec(a)");
15214 CHECK(try_catch.HasTerminated());
15216 timeout_thread.Join();
15218 regexp_interruption_data.string.Reset();
15219 i::DeleteArray(uc16_content);
15222 #endif // V8_INTERPRETED_REGEXP
15225 // Test that we cannot set a property on the global object if there
15226 // is a read-only property in the prototype chain.
15227 TEST(ReadOnlyPropertyInGlobalProto) {
15228 v8::Isolate* isolate = CcTest::isolate();
15229 v8::HandleScope scope(isolate);
15230 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15231 LocalContext context(0, templ);
15232 v8::Handle<v8::Object> global = context->Global();
15233 v8::Handle<v8::Object> global_proto =
15234 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15235 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15237 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15239 // Check without 'eval' or 'with'.
15240 v8::Handle<v8::Value> res =
15241 CompileRun("function f() { x = 42; return x; }; f()");
15242 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15243 // Check with 'eval'.
15244 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15245 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15246 // Check with 'with'.
15247 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15248 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15251 static int force_set_set_count = 0;
15252 static int force_set_get_count = 0;
15253 bool pass_on_get = false;
15255 static void ForceSetGetter(v8::Local<v8::String> name,
15256 const v8::PropertyCallbackInfo<v8::Value>& info) {
15257 force_set_get_count++;
15261 info.GetReturnValue().Set(3);
15264 static void ForceSetSetter(v8::Local<v8::String> name,
15265 v8::Local<v8::Value> value,
15266 const v8::PropertyCallbackInfo<void>& info) {
15267 force_set_set_count++;
15270 static void ForceSetInterceptSetter(
15271 v8::Local<v8::String> name,
15272 v8::Local<v8::Value> value,
15273 const v8::PropertyCallbackInfo<v8::Value>& info) {
15274 force_set_set_count++;
15275 info.GetReturnValue().SetUndefined();
15280 force_set_get_count = 0;
15281 force_set_set_count = 0;
15282 pass_on_get = false;
15284 v8::Isolate* isolate = CcTest::isolate();
15285 v8::HandleScope scope(isolate);
15286 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15287 v8::Handle<v8::String> access_property =
15288 v8::String::NewFromUtf8(isolate, "a");
15289 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15290 LocalContext context(NULL, templ);
15291 v8::Handle<v8::Object> global = context->Global();
15293 // Ordinary properties
15294 v8::Handle<v8::String> simple_property =
15295 v8::String::NewFromUtf8(isolate, "p");
15296 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15297 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15298 // This should fail because the property is read-only
15299 global->Set(simple_property, v8::Int32::New(isolate, 5));
15300 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15301 // This should succeed even though the property is read-only
15302 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15303 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15306 CHECK_EQ(0, force_set_set_count);
15307 CHECK_EQ(0, force_set_get_count);
15308 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15309 // CHECK_EQ the property shouldn't override it, just call the setter
15310 // which in this case does nothing.
15311 global->Set(access_property, v8::Int32::New(isolate, 7));
15312 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15313 CHECK_EQ(1, force_set_set_count);
15314 CHECK_EQ(2, force_set_get_count);
15315 // Forcing the property to be set should override the accessor without
15317 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15318 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15319 CHECK_EQ(1, force_set_set_count);
15320 CHECK_EQ(2, force_set_get_count);
15324 TEST(ForceSetWithInterceptor) {
15325 force_set_get_count = 0;
15326 force_set_set_count = 0;
15327 pass_on_get = false;
15329 v8::Isolate* isolate = CcTest::isolate();
15330 v8::HandleScope scope(isolate);
15331 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15332 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15333 LocalContext context(NULL, templ);
15334 v8::Handle<v8::Object> global = context->Global();
15336 v8::Handle<v8::String> some_property =
15337 v8::String::NewFromUtf8(isolate, "a");
15338 CHECK_EQ(0, force_set_set_count);
15339 CHECK_EQ(0, force_set_get_count);
15340 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15341 // Setting the property shouldn't override it, just call the setter
15342 // which in this case does nothing.
15343 global->Set(some_property, v8::Int32::New(isolate, 7));
15344 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15345 CHECK_EQ(1, force_set_set_count);
15346 CHECK_EQ(2, force_set_get_count);
15347 // Getting the property when the interceptor returns an empty handle
15348 // should yield undefined, since the property isn't present on the
15349 // object itself yet.
15350 pass_on_get = true;
15351 CHECK(global->Get(some_property)->IsUndefined());
15352 CHECK_EQ(1, force_set_set_count);
15353 CHECK_EQ(3, force_set_get_count);
15354 // Forcing the property to be set should cause the value to be
15355 // set locally without calling the interceptor.
15356 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15357 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15358 CHECK_EQ(1, force_set_set_count);
15359 CHECK_EQ(4, force_set_get_count);
15360 // Reenabling the interceptor should cause it to take precedence over
15362 pass_on_get = false;
15363 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15364 CHECK_EQ(1, force_set_set_count);
15365 CHECK_EQ(5, force_set_get_count);
15366 // The interceptor should also work for other properties
15367 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15369 CHECK_EQ(1, force_set_set_count);
15370 CHECK_EQ(6, force_set_get_count);
15374 THREADED_TEST(ForceDelete) {
15375 v8::Isolate* isolate = CcTest::isolate();
15376 v8::HandleScope scope(isolate);
15377 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15378 LocalContext context(NULL, templ);
15379 v8::Handle<v8::Object> global = context->Global();
15381 // Ordinary properties
15382 v8::Handle<v8::String> simple_property =
15383 v8::String::NewFromUtf8(isolate, "p");
15384 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15385 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15386 // This should fail because the property is dont-delete.
15387 CHECK(!global->Delete(simple_property));
15388 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15389 // This should succeed even though the property is dont-delete.
15390 CHECK(global->ForceDelete(simple_property));
15391 CHECK(global->Get(simple_property)->IsUndefined());
15395 static int force_delete_interceptor_count = 0;
15396 static bool pass_on_delete = false;
15399 static void ForceDeleteDeleter(
15400 v8::Local<v8::String> name,
15401 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15402 force_delete_interceptor_count++;
15403 if (pass_on_delete) return;
15404 info.GetReturnValue().Set(true);
15408 THREADED_TEST(ForceDeleteWithInterceptor) {
15409 force_delete_interceptor_count = 0;
15410 pass_on_delete = false;
15412 v8::Isolate* isolate = CcTest::isolate();
15413 v8::HandleScope scope(isolate);
15414 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15415 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15416 LocalContext context(NULL, templ);
15417 v8::Handle<v8::Object> global = context->Global();
15419 v8::Handle<v8::String> some_property =
15420 v8::String::NewFromUtf8(isolate, "a");
15421 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15424 // Deleting a property should get intercepted and nothing should
15426 CHECK_EQ(0, force_delete_interceptor_count);
15427 CHECK(global->Delete(some_property));
15428 CHECK_EQ(1, force_delete_interceptor_count);
15429 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15430 // Deleting the property when the interceptor returns an empty
15431 // handle should not delete the property since it is DontDelete.
15432 pass_on_delete = true;
15433 CHECK(!global->Delete(some_property));
15434 CHECK_EQ(2, force_delete_interceptor_count);
15435 CHECK_EQ(42, global->Get(some_property)->Int32Value());
15436 // Forcing the property to be deleted should delete the value
15437 // without calling the interceptor.
15438 CHECK(global->ForceDelete(some_property));
15439 CHECK(global->Get(some_property)->IsUndefined());
15440 CHECK_EQ(2, force_delete_interceptor_count);
15444 // Make sure that forcing a delete invalidates any IC stubs, so we
15445 // don't read the hole value.
15446 THREADED_TEST(ForceDeleteIC) {
15447 LocalContext context;
15448 v8::HandleScope scope(context->GetIsolate());
15449 // Create a DontDelete variable on the global object.
15450 CompileRun("this.__proto__ = { foo: 'horse' };"
15451 "var foo = 'fish';"
15452 "function f() { return foo.length; }");
15453 // Initialize the IC for foo in f.
15454 CompileRun("for (var i = 0; i < 4; i++) f();");
15455 // Make sure the value of foo is correct before the deletion.
15456 CHECK_EQ(4, CompileRun("f()")->Int32Value());
15457 // Force the deletion of foo.
15458 CHECK(context->Global()->ForceDelete(v8_str("foo")));
15459 // Make sure the value for foo is read from the prototype, and that
15460 // we don't get in trouble with reading the deleted cell value
15462 CHECK_EQ(5, CompileRun("f()")->Int32Value());
15466 TEST(InlinedFunctionAcrossContexts) {
15467 i::FLAG_allow_natives_syntax = true;
15468 v8::Isolate* isolate = CcTest::isolate();
15469 v8::HandleScope outer_scope(isolate);
15470 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15471 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15475 v8::HandleScope inner_scope(CcTest::isolate());
15476 CompileRun("var G = 42; function foo() { return G; }");
15477 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15479 ctx2->Global()->Set(v8_str("o"), foo);
15480 v8::Local<v8::Value> res = CompileRun(
15481 "function f() { return o(); }"
15482 "for (var i = 0; i < 10; ++i) f();"
15483 "%OptimizeFunctionOnNextCall(f);"
15485 CHECK_EQ(42, res->Int32Value());
15487 v8::Handle<v8::String> G_property =
15488 v8::String::NewFromUtf8(CcTest::isolate(), "G");
15489 CHECK(ctx1->Global()->ForceDelete(G_property));
15496 " return e.toString();"
15499 "ReferenceError: G is not defined");
15506 static v8::Local<Context> calling_context0;
15507 static v8::Local<Context> calling_context1;
15508 static v8::Local<Context> calling_context2;
15511 // Check that the call to the callback is initiated in
15512 // calling_context2, the directly calling context is calling_context1
15513 // and the callback itself is in calling_context0.
15514 static void GetCallingContextCallback(
15515 const v8::FunctionCallbackInfo<v8::Value>& args) {
15516 ApiTestFuzzer::Fuzz();
15517 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15518 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15519 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15520 args.GetReturnValue().Set(42);
15524 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15525 i::Isolate* isolate = CcTest::i_isolate();
15526 CHECK(isolate != NULL);
15527 CHECK(isolate->context() == NULL);
15528 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15529 v8::HandleScope scope(v8_isolate);
15530 // The following should not crash, but return an empty handle.
15531 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15532 CHECK(current.IsEmpty());
15536 THREADED_TEST(GetCallingContext) {
15537 v8::Isolate* isolate = CcTest::isolate();
15538 v8::HandleScope scope(isolate);
15540 Local<Context> calling_context0(Context::New(isolate));
15541 Local<Context> calling_context1(Context::New(isolate));
15542 Local<Context> calling_context2(Context::New(isolate));
15543 ::calling_context0 = calling_context0;
15544 ::calling_context1 = calling_context1;
15545 ::calling_context2 = calling_context2;
15547 // Allow cross-domain access.
15548 Local<String> token = v8_str("<security token>");
15549 calling_context0->SetSecurityToken(token);
15550 calling_context1->SetSecurityToken(token);
15551 calling_context2->SetSecurityToken(token);
15553 // Create an object with a C++ callback in context0.
15554 calling_context0->Enter();
15555 Local<v8::FunctionTemplate> callback_templ =
15556 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15557 calling_context0->Global()->Set(v8_str("callback"),
15558 callback_templ->GetFunction());
15559 calling_context0->Exit();
15561 // Expose context0 in context1 and set up a function that calls the
15562 // callback function.
15563 calling_context1->Enter();
15564 calling_context1->Global()->Set(v8_str("context0"),
15565 calling_context0->Global());
15566 CompileRun("function f() { context0.callback() }");
15567 calling_context1->Exit();
15569 // Expose context1 in context2 and call the callback function in
15570 // context0 indirectly through f in context1.
15571 calling_context2->Enter();
15572 calling_context2->Global()->Set(v8_str("context1"),
15573 calling_context1->Global());
15574 CompileRun("context1.f()");
15575 calling_context2->Exit();
15576 ::calling_context0.Clear();
15577 ::calling_context1.Clear();
15578 ::calling_context2.Clear();
15582 // Check that a variable declaration with no explicit initialization
15583 // value does shadow an existing property in the prototype chain.
15584 THREADED_TEST(InitGlobalVarInProtoChain) {
15585 LocalContext context;
15586 v8::HandleScope scope(context->GetIsolate());
15587 // Introduce a variable in the prototype chain.
15588 CompileRun("__proto__.x = 42");
15589 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15590 CHECK(!result->IsUndefined());
15591 CHECK_EQ(43, result->Int32Value());
15595 // Regression test for issue 398.
15596 // If a function is added to an object, creating a constant function
15597 // field, and the result is cloned, replacing the constant function on the
15598 // original should not affect the clone.
15599 // See http://code.google.com/p/v8/issues/detail?id=398
15600 THREADED_TEST(ReplaceConstantFunction) {
15601 LocalContext context;
15602 v8::Isolate* isolate = context->GetIsolate();
15603 v8::HandleScope scope(isolate);
15604 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15605 v8::Handle<v8::FunctionTemplate> func_templ =
15606 v8::FunctionTemplate::New(isolate);
15607 v8::Handle<v8::String> foo_string =
15608 v8::String::NewFromUtf8(isolate, "foo");
15609 obj->Set(foo_string, func_templ->GetFunction());
15610 v8::Handle<v8::Object> obj_clone = obj->Clone();
15611 obj_clone->Set(foo_string,
15612 v8::String::NewFromUtf8(isolate, "Hello"));
15613 CHECK(!obj->Get(foo_string)->IsUndefined());
15617 static void CheckElementValue(i::Isolate* isolate,
15619 i::Handle<i::Object> obj,
15621 i::Object* element =
15622 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15623 CHECK_EQ(expected, i::Smi::cast(element)->value());
15627 THREADED_TEST(PixelArray) {
15628 LocalContext context;
15629 i::Isolate* isolate = CcTest::i_isolate();
15630 i::Factory* factory = isolate->factory();
15631 v8::HandleScope scope(context->GetIsolate());
15632 const int kElementCount = 260;
15633 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15634 i::Handle<i::ExternalUint8ClampedArray> pixels =
15635 i::Handle<i::ExternalUint8ClampedArray>::cast(
15636 factory->NewExternalArray(kElementCount,
15637 v8::kExternalUint8ClampedArray,
15639 // Force GC to trigger verification.
15640 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15641 for (int i = 0; i < kElementCount; i++) {
15642 pixels->set(i, i % 256);
15644 // Force GC to trigger verification.
15645 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15646 for (int i = 0; i < kElementCount; i++) {
15647 CHECK_EQ(i % 256, pixels->get_scalar(i));
15648 CHECK_EQ(i % 256, pixel_data[i]);
15651 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15652 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15653 // Set the elements to be the pixels.
15654 // jsobj->set_elements(*pixels);
15655 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15656 CheckElementValue(isolate, 1, jsobj, 1);
15657 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15658 context->Global()->Set(v8_str("pixels"), obj);
15659 v8::Handle<v8::Value> result = CompileRun("pixels.field");
15660 CHECK_EQ(1503, result->Int32Value());
15661 result = CompileRun("pixels[1]");
15662 CHECK_EQ(1, result->Int32Value());
15664 result = CompileRun("var sum = 0;"
15665 "for (var i = 0; i < 8; i++) {"
15666 " sum += pixels[i] = pixels[i] = -i;"
15669 CHECK_EQ(-28, result->Int32Value());
15671 result = CompileRun("var sum = 0;"
15672 "for (var i = 0; i < 8; i++) {"
15673 " sum += pixels[i] = pixels[i] = 0;"
15676 CHECK_EQ(0, result->Int32Value());
15678 result = CompileRun("var sum = 0;"
15679 "for (var i = 0; i < 8; i++) {"
15680 " sum += pixels[i] = pixels[i] = 255;"
15683 CHECK_EQ(8 * 255, result->Int32Value());
15685 result = CompileRun("var sum = 0;"
15686 "for (var i = 0; i < 8; i++) {"
15687 " sum += pixels[i] = pixels[i] = 256 + i;"
15690 CHECK_EQ(2076, result->Int32Value());
15692 result = CompileRun("var sum = 0;"
15693 "for (var i = 0; i < 8; i++) {"
15694 " sum += pixels[i] = pixels[i] = i;"
15697 CHECK_EQ(28, result->Int32Value());
15699 result = CompileRun("var sum = 0;"
15700 "for (var i = 0; i < 8; i++) {"
15701 " sum += pixels[i];"
15704 CHECK_EQ(28, result->Int32Value());
15706 i::Handle<i::Smi> value(i::Smi::FromInt(2),
15707 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15708 i::Handle<i::Object> no_failure;
15709 no_failure = i::JSObject::SetElement(
15710 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15711 DCHECK(!no_failure.is_null());
15713 CheckElementValue(isolate, 2, jsobj, 1);
15714 *value.location() = i::Smi::FromInt(256);
15715 no_failure = i::JSObject::SetElement(
15716 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15717 DCHECK(!no_failure.is_null());
15719 CheckElementValue(isolate, 255, jsobj, 1);
15720 *value.location() = i::Smi::FromInt(-1);
15721 no_failure = i::JSObject::SetElement(
15722 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15723 DCHECK(!no_failure.is_null());
15725 CheckElementValue(isolate, 0, jsobj, 1);
15727 result = CompileRun("for (var i = 0; i < 8; i++) {"
15728 " pixels[i] = (i * 65) - 109;"
15730 "pixels[1] + pixels[6];");
15731 CHECK_EQ(255, result->Int32Value());
15732 CheckElementValue(isolate, 0, jsobj, 0);
15733 CheckElementValue(isolate, 0, jsobj, 1);
15734 CheckElementValue(isolate, 21, jsobj, 2);
15735 CheckElementValue(isolate, 86, jsobj, 3);
15736 CheckElementValue(isolate, 151, jsobj, 4);
15737 CheckElementValue(isolate, 216, jsobj, 5);
15738 CheckElementValue(isolate, 255, jsobj, 6);
15739 CheckElementValue(isolate, 255, jsobj, 7);
15740 result = CompileRun("var sum = 0;"
15741 "for (var i = 0; i < 8; i++) {"
15742 " sum += pixels[i];"
15745 CHECK_EQ(984, result->Int32Value());
15747 result = CompileRun("for (var i = 0; i < 8; i++) {"
15748 " pixels[i] = (i * 1.1);"
15750 "pixels[1] + pixels[6];");
15751 CHECK_EQ(8, result->Int32Value());
15752 CheckElementValue(isolate, 0, jsobj, 0);
15753 CheckElementValue(isolate, 1, jsobj, 1);
15754 CheckElementValue(isolate, 2, jsobj, 2);
15755 CheckElementValue(isolate, 3, jsobj, 3);
15756 CheckElementValue(isolate, 4, jsobj, 4);
15757 CheckElementValue(isolate, 6, jsobj, 5);
15758 CheckElementValue(isolate, 7, jsobj, 6);
15759 CheckElementValue(isolate, 8, jsobj, 7);
15761 result = CompileRun("for (var i = 0; i < 8; i++) {"
15762 " pixels[7] = undefined;"
15765 CHECK_EQ(0, result->Int32Value());
15766 CheckElementValue(isolate, 0, jsobj, 7);
15768 result = CompileRun("for (var i = 0; i < 8; i++) {"
15769 " pixels[6] = '2.3';"
15772 CHECK_EQ(2, result->Int32Value());
15773 CheckElementValue(isolate, 2, jsobj, 6);
15775 result = CompileRun("for (var i = 0; i < 8; i++) {"
15776 " pixels[5] = NaN;"
15779 CHECK_EQ(0, result->Int32Value());
15780 CheckElementValue(isolate, 0, jsobj, 5);
15782 result = CompileRun("for (var i = 0; i < 8; i++) {"
15783 " pixels[8] = Infinity;"
15786 CHECK_EQ(255, result->Int32Value());
15787 CheckElementValue(isolate, 255, jsobj, 8);
15789 result = CompileRun("for (var i = 0; i < 8; i++) {"
15790 " pixels[9] = -Infinity;"
15793 CHECK_EQ(0, result->Int32Value());
15794 CheckElementValue(isolate, 0, jsobj, 9);
15796 result = CompileRun("pixels[3] = 33;"
15797 "delete pixels[3];"
15799 CHECK_EQ(33, result->Int32Value());
15801 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15802 "pixels[2] = 12; pixels[3] = 13;"
15803 "pixels.__defineGetter__('2',"
15804 "function() { return 120; });"
15806 CHECK_EQ(12, result->Int32Value());
15808 result = CompileRun("var js_array = new Array(40);"
15809 "js_array[0] = 77;"
15811 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15813 result = CompileRun("pixels[1] = 23;"
15814 "pixels.__proto__ = [];"
15815 "js_array.__proto__ = pixels;"
15816 "js_array.concat(pixels);");
15817 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15818 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15820 result = CompileRun("pixels[1] = 23;");
15821 CHECK_EQ(23, result->Int32Value());
15823 // Test for index greater than 255. Regression test for:
15824 // http://code.google.com/p/chromium/issues/detail?id=26337.
15825 result = CompileRun("pixels[256] = 255;");
15826 CHECK_EQ(255, result->Int32Value());
15827 result = CompileRun("var i = 0;"
15828 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15830 CHECK_EQ(255, result->Int32Value());
15832 // Make sure that pixel array ICs recognize when a non-pixel array
15833 // is passed to it.
15834 result = CompileRun("function pa_load(p) {"
15836 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15839 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15840 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15841 "just_ints = new Object();"
15842 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15843 "for (var i = 0; i < 10; ++i) {"
15844 " result = pa_load(just_ints);"
15847 CHECK_EQ(32640, result->Int32Value());
15849 // Make sure that pixel array ICs recognize out-of-bound accesses.
15850 result = CompileRun("function pa_load(p, start) {"
15852 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15855 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15856 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15857 "for (var i = 0; i < 10; ++i) {"
15858 " result = pa_load(pixels,-10);"
15861 CHECK_EQ(0, result->Int32Value());
15863 // Make sure that generic ICs properly handles a pixel array.
15864 result = CompileRun("function pa_load(p) {"
15866 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15869 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15870 "just_ints = new Object();"
15871 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15872 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15873 "for (var i = 0; i < 10; ++i) {"
15874 " result = pa_load(pixels);"
15877 CHECK_EQ(32640, result->Int32Value());
15879 // Make sure that generic load ICs recognize out-of-bound accesses in
15881 result = CompileRun("function pa_load(p, start) {"
15883 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15886 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15887 "just_ints = new Object();"
15888 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15889 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15890 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15891 "for (var i = 0; i < 10; ++i) {"
15892 " result = pa_load(pixels,-10);"
15895 CHECK_EQ(0, result->Int32Value());
15897 // Make sure that generic ICs properly handles other types than pixel
15898 // arrays (that the inlined fast pixel array test leaves the right information
15899 // in the right registers).
15900 result = CompileRun("function pa_load(p) {"
15902 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15905 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15906 "just_ints = new Object();"
15907 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15908 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15909 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15910 "sparse_array = new Object();"
15911 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15912 "sparse_array[1000000] = 3;"
15913 "for (var i = 0; i < 10; ++i) {"
15914 " result = pa_load(sparse_array);"
15917 CHECK_EQ(32640, result->Int32Value());
15919 // Make sure that pixel array store ICs clamp values correctly.
15920 result = CompileRun("function pa_store(p) {"
15921 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15923 "pa_store(pixels);"
15925 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15927 CHECK_EQ(48896, result->Int32Value());
15929 // Make sure that pixel array stores correctly handle accesses outside
15930 // of the pixel array..
15931 result = CompileRun("function pa_store(p,start) {"
15932 " for (var j = 0; j < 256; j++) {"
15933 " p[j+start] = j * 2;"
15936 "pa_store(pixels,0);"
15937 "pa_store(pixels,-128);"
15939 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15941 CHECK_EQ(65280, result->Int32Value());
15943 // Make sure that the generic store stub correctly handle accesses outside
15944 // of the pixel array..
15945 result = CompileRun("function pa_store(p,start) {"
15946 " for (var j = 0; j < 256; j++) {"
15947 " p[j+start] = j * 2;"
15950 "pa_store(pixels,0);"
15951 "just_ints = new Object();"
15952 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15953 "pa_store(just_ints, 0);"
15954 "pa_store(pixels,-128);"
15956 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15958 CHECK_EQ(65280, result->Int32Value());
15960 // Make sure that the generic keyed store stub clamps pixel array values
15962 result = CompileRun("function pa_store(p) {"
15963 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15965 "pa_store(pixels);"
15966 "just_ints = new Object();"
15967 "pa_store(just_ints);"
15968 "pa_store(pixels);"
15970 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15972 CHECK_EQ(48896, result->Int32Value());
15974 // Make sure that pixel array loads are optimized by crankshaft.
15975 result = CompileRun("function pa_load(p) {"
15977 " for (var i=0; i<256; ++i) {"
15982 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15983 "for (var i = 0; i < 5000; ++i) {"
15984 " result = pa_load(pixels);"
15987 CHECK_EQ(32640, result->Int32Value());
15989 // Make sure that pixel array stores are optimized by crankshaft.
15990 result = CompileRun("function pa_init(p) {"
15991 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15993 "function pa_load(p) {"
15995 " for (var i=0; i<256; ++i) {"
16000 "for (var i = 0; i < 5000; ++i) {"
16001 " pa_init(pixels);"
16003 "result = pa_load(pixels);"
16005 CHECK_EQ(32640, result->Int32Value());
16011 THREADED_TEST(PixelArrayInfo) {
16012 LocalContext context;
16013 v8::HandleScope scope(context->GetIsolate());
16014 for (int size = 0; size < 100; size += 10) {
16015 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16016 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16017 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16018 CHECK(obj->HasIndexedPropertiesInPixelData());
16019 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16020 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16026 static void NotHandledIndexedPropertyGetter(
16028 const v8::PropertyCallbackInfo<v8::Value>& info) {
16029 ApiTestFuzzer::Fuzz();
16033 static void NotHandledIndexedPropertySetter(
16035 Local<Value> value,
16036 const v8::PropertyCallbackInfo<v8::Value>& info) {
16037 ApiTestFuzzer::Fuzz();
16041 THREADED_TEST(PixelArrayWithInterceptor) {
16042 LocalContext context;
16043 i::Factory* factory = CcTest::i_isolate()->factory();
16044 v8::Isolate* isolate = context->GetIsolate();
16045 v8::HandleScope scope(isolate);
16046 const int kElementCount = 260;
16047 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16048 i::Handle<i::ExternalUint8ClampedArray> pixels =
16049 i::Handle<i::ExternalUint8ClampedArray>::cast(
16050 factory->NewExternalArray(kElementCount,
16051 v8::kExternalUint8ClampedArray,
16053 for (int i = 0; i < kElementCount; i++) {
16054 pixels->set(i, i % 256);
16056 v8::Handle<v8::ObjectTemplate> templ =
16057 v8::ObjectTemplate::New(context->GetIsolate());
16058 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16059 NotHandledIndexedPropertySetter);
16060 v8::Handle<v8::Object> obj = templ->NewInstance();
16061 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16062 context->Global()->Set(v8_str("pixels"), obj);
16063 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16064 CHECK_EQ(1, result->Int32Value());
16065 result = CompileRun("var sum = 0;"
16066 "for (var i = 0; i < 8; i++) {"
16067 " sum += pixels[i] = pixels[i] = -i;"
16070 CHECK_EQ(-28, result->Int32Value());
16071 result = CompileRun("pixels.hasOwnProperty('1')");
16072 CHECK(result->BooleanValue());
16077 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16078 switch (array_type) {
16079 case v8::kExternalInt8Array:
16080 case v8::kExternalUint8Array:
16081 case v8::kExternalUint8ClampedArray:
16084 case v8::kExternalInt16Array:
16085 case v8::kExternalUint16Array:
16088 case v8::kExternalInt32Array:
16089 case v8::kExternalUint32Array:
16090 case v8::kExternalFloat32Array:
16093 case v8::kExternalFloat64Array:
16105 template <class ExternalArrayClass, class ElementType>
16106 static void ObjectWithExternalArrayTestHelper(
16107 Handle<Context> context,
16108 v8::Handle<Object> obj,
16110 v8::ExternalArrayType array_type,
16111 int64_t low, int64_t high) {
16112 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16113 i::Isolate* isolate = jsobj->GetIsolate();
16114 obj->Set(v8_str("field"),
16115 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16116 context->Global()->Set(v8_str("ext_array"), obj);
16117 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16118 CHECK_EQ(1503, result->Int32Value());
16119 result = CompileRun("ext_array[1]");
16120 CHECK_EQ(1, result->Int32Value());
16122 // Check assigned smis
16123 result = CompileRun("for (var i = 0; i < 8; i++) {"
16124 " ext_array[i] = i;"
16127 "for (var i = 0; i < 8; i++) {"
16128 " sum += ext_array[i];"
16132 CHECK_EQ(28, result->Int32Value());
16133 // Check pass through of assigned smis
16134 result = CompileRun("var sum = 0;"
16135 "for (var i = 0; i < 8; i++) {"
16136 " sum += ext_array[i] = ext_array[i] = -i;"
16139 CHECK_EQ(-28, result->Int32Value());
16142 // Check assigned smis in reverse order
16143 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16144 " ext_array[i] = i;"
16147 "for (var i = 0; i < 8; i++) {"
16148 " sum += ext_array[i];"
16151 CHECK_EQ(28, result->Int32Value());
16153 // Check pass through of assigned HeapNumbers
16154 result = CompileRun("var sum = 0;"
16155 "for (var i = 0; i < 16; i+=2) {"
16156 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16159 CHECK_EQ(-28, result->Int32Value());
16161 // Check assigned HeapNumbers
16162 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16163 " ext_array[i] = (i * 0.5);"
16166 "for (var i = 0; i < 16; i+=2) {"
16167 " sum += ext_array[i];"
16170 CHECK_EQ(28, result->Int32Value());
16172 // Check assigned HeapNumbers in reverse order
16173 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16174 " ext_array[i] = (i * 0.5);"
16177 "for (var i = 0; i < 16; i+=2) {"
16178 " sum += ext_array[i];"
16181 CHECK_EQ(28, result->Int32Value());
16183 i::ScopedVector<char> test_buf(1024);
16185 // Check legal boundary conditions.
16186 // The repeated loads and stores ensure the ICs are exercised.
16187 const char* boundary_program =
16189 "for (var i = 0; i < 16; i++) {"
16190 " ext_array[i] = %lld;"
16192 " res = ext_array[i];"
16196 i::SNPrintF(test_buf,
16199 result = CompileRun(test_buf.start());
16200 CHECK_EQ(low, result->IntegerValue());
16202 i::SNPrintF(test_buf,
16205 result = CompileRun(test_buf.start());
16206 CHECK_EQ(high, result->IntegerValue());
16208 // Check misprediction of type in IC.
16209 result = CompileRun("var tmp_array = ext_array;"
16211 "for (var i = 0; i < 8; i++) {"
16212 " tmp_array[i] = i;"
16213 " sum += tmp_array[i];"
16219 // Force GC to trigger verification.
16220 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16221 CHECK_EQ(28, result->Int32Value());
16223 // Make sure out-of-range loads do not throw.
16224 i::SNPrintF(test_buf,
16225 "var caught_exception = false;"
16229 " caught_exception = true;"
16231 "caught_exception;",
16233 result = CompileRun(test_buf.start());
16234 CHECK_EQ(false, result->BooleanValue());
16236 // Make sure out-of-range stores do not throw.
16237 i::SNPrintF(test_buf,
16238 "var caught_exception = false;"
16240 " ext_array[%d] = 1;"
16242 " caught_exception = true;"
16244 "caught_exception;",
16246 result = CompileRun(test_buf.start());
16247 CHECK_EQ(false, result->BooleanValue());
16249 // Check other boundary conditions, values and operations.
16250 result = CompileRun("for (var i = 0; i < 8; i++) {"
16251 " ext_array[7] = undefined;"
16254 CHECK_EQ(0, result->Int32Value());
16255 if (array_type == v8::kExternalFloat64Array ||
16256 array_type == v8::kExternalFloat32Array) {
16257 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16259 i::Object::GetElement(
16260 isolate, jsobj, 7).ToHandleChecked()->Number()));
16262 CheckElementValue(isolate, 0, jsobj, 7);
16265 result = CompileRun("for (var i = 0; i < 8; i++) {"
16266 " ext_array[6] = '2.3';"
16269 CHECK_EQ(2, result->Int32Value());
16272 i::Object::GetElement(
16273 isolate, jsobj, 6).ToHandleChecked()->Number()));
16275 if (array_type != v8::kExternalFloat32Array &&
16276 array_type != v8::kExternalFloat64Array) {
16277 // Though the specification doesn't state it, be explicit about
16278 // converting NaNs and +/-Infinity to zero.
16279 result = CompileRun("for (var i = 0; i < 8; i++) {"
16280 " ext_array[i] = 5;"
16282 "for (var i = 0; i < 8; i++) {"
16283 " ext_array[i] = NaN;"
16286 CHECK_EQ(0, result->Int32Value());
16287 CheckElementValue(isolate, 0, jsobj, 5);
16289 result = CompileRun("for (var i = 0; i < 8; i++) {"
16290 " ext_array[i] = 5;"
16292 "for (var i = 0; i < 8; i++) {"
16293 " ext_array[i] = Infinity;"
16296 int expected_value =
16297 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16298 CHECK_EQ(expected_value, result->Int32Value());
16299 CheckElementValue(isolate, expected_value, jsobj, 5);
16301 result = CompileRun("for (var i = 0; i < 8; i++) {"
16302 " ext_array[i] = 5;"
16304 "for (var i = 0; i < 8; i++) {"
16305 " ext_array[i] = -Infinity;"
16308 CHECK_EQ(0, result->Int32Value());
16309 CheckElementValue(isolate, 0, jsobj, 5);
16311 // Check truncation behavior of integral arrays.
16312 const char* unsigned_data =
16313 "var source_data = [0.6, 10.6];"
16314 "var expected_results = [0, 10];";
16315 const char* signed_data =
16316 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16317 "var expected_results = [0, 10, 0, -10];";
16318 const char* pixel_data =
16319 "var source_data = [0.6, 10.6];"
16320 "var expected_results = [1, 11];";
16322 (array_type == v8::kExternalUint8Array ||
16323 array_type == v8::kExternalUint16Array ||
16324 array_type == v8::kExternalUint32Array);
16325 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16327 i::SNPrintF(test_buf,
16329 "var all_passed = true;"
16330 "for (var i = 0; i < source_data.length; i++) {"
16331 " for (var j = 0; j < 8; j++) {"
16332 " ext_array[j] = source_data[i];"
16334 " all_passed = all_passed &&"
16335 " (ext_array[5] == expected_results[i]);"
16340 (is_pixel_data ? pixel_data : signed_data)));
16341 result = CompileRun(test_buf.start());
16342 CHECK_EQ(true, result->BooleanValue());
16345 i::Handle<ExternalArrayClass> array(
16346 ExternalArrayClass::cast(jsobj->elements()));
16347 for (int i = 0; i < element_count; i++) {
16348 array->set(i, static_cast<ElementType>(i));
16351 // Test complex assignments
16352 result = CompileRun("function ee_op_test_complex_func(sum) {"
16353 " for (var i = 0; i < 40; ++i) {"
16354 " sum += (ext_array[i] += 1);"
16355 " sum += (ext_array[i] -= 1);"
16360 "for (var i=0;i<10000;++i) {"
16361 " sum=ee_op_test_complex_func(sum);"
16364 CHECK_EQ(16000000, result->Int32Value());
16366 // Test count operations
16367 result = CompileRun("function ee_op_test_count_func(sum) {"
16368 " for (var i = 0; i < 40; ++i) {"
16369 " sum += (++ext_array[i]);"
16370 " sum += (--ext_array[i]);"
16375 "for (var i=0;i<10000;++i) {"
16376 " sum=ee_op_test_count_func(sum);"
16379 CHECK_EQ(16000000, result->Int32Value());
16381 result = CompileRun("ext_array[3] = 33;"
16382 "delete ext_array[3];"
16384 CHECK_EQ(33, result->Int32Value());
16386 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16387 "ext_array[2] = 12; ext_array[3] = 13;"
16388 "ext_array.__defineGetter__('2',"
16389 "function() { return 120; });"
16391 CHECK_EQ(12, result->Int32Value());
16393 result = CompileRun("var js_array = new Array(40);"
16394 "js_array[0] = 77;"
16396 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16398 result = CompileRun("ext_array[1] = 23;"
16399 "ext_array.__proto__ = [];"
16400 "js_array.__proto__ = ext_array;"
16401 "js_array.concat(ext_array);");
16402 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16403 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16405 result = CompileRun("ext_array[1] = 23;");
16406 CHECK_EQ(23, result->Int32Value());
16410 template <class FixedTypedArrayClass,
16411 i::ElementsKind elements_kind,
16413 static void FixedTypedArrayTestHelper(
16414 v8::ExternalArrayType array_type,
16416 ElementType high) {
16417 i::FLAG_allow_natives_syntax = true;
16418 LocalContext context;
16419 i::Isolate* isolate = CcTest::i_isolate();
16420 i::Factory* factory = isolate->factory();
16421 v8::HandleScope scope(context->GetIsolate());
16422 const int kElementCount = 260;
16423 i::Handle<FixedTypedArrayClass> fixed_array =
16424 i::Handle<FixedTypedArrayClass>::cast(
16425 factory->NewFixedTypedArray(kElementCount, array_type));
16426 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16427 fixed_array->map()->instance_type());
16428 CHECK_EQ(kElementCount, fixed_array->length());
16429 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16430 for (int i = 0; i < kElementCount; i++) {
16431 fixed_array->set(i, static_cast<ElementType>(i));
16433 // Force GC to trigger verification.
16434 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16435 for (int i = 0; i < kElementCount; i++) {
16436 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16437 static_cast<int64_t>(fixed_array->get_scalar(i)));
16439 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16440 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16441 i::Handle<i::Map> fixed_array_map =
16442 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16443 jsobj->set_map(*fixed_array_map);
16444 jsobj->set_elements(*fixed_array);
16446 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16447 context.local(), obj, kElementCount, array_type,
16448 static_cast<int64_t>(low),
16449 static_cast<int64_t>(high));
16453 THREADED_TEST(FixedUint8Array) {
16454 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16455 v8::kExternalUint8Array,
16460 THREADED_TEST(FixedUint8ClampedArray) {
16461 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16462 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16463 v8::kExternalUint8ClampedArray,
16468 THREADED_TEST(FixedInt8Array) {
16469 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16470 v8::kExternalInt8Array,
16475 THREADED_TEST(FixedUint16Array) {
16476 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16477 v8::kExternalUint16Array,
16482 THREADED_TEST(FixedInt16Array) {
16483 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16484 v8::kExternalInt16Array,
16489 THREADED_TEST(FixedUint32Array) {
16490 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16491 v8::kExternalUint32Array,
16496 THREADED_TEST(FixedInt32Array) {
16497 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16498 v8::kExternalInt32Array,
16503 THREADED_TEST(FixedFloat32Array) {
16504 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16505 v8::kExternalFloat32Array,
16510 THREADED_TEST(FixedFloat64Array) {
16511 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16512 v8::kExternalFloat64Array,
16517 template <class ExternalArrayClass, class ElementType>
16518 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16521 LocalContext context;
16522 i::Isolate* isolate = CcTest::i_isolate();
16523 i::Factory* factory = isolate->factory();
16524 v8::HandleScope scope(context->GetIsolate());
16525 const int kElementCount = 40;
16526 int element_size = ExternalArrayElementSize(array_type);
16527 ElementType* array_data =
16528 static_cast<ElementType*>(malloc(kElementCount * element_size));
16529 i::Handle<ExternalArrayClass> array =
16530 i::Handle<ExternalArrayClass>::cast(
16531 factory->NewExternalArray(kElementCount, array_type, array_data));
16532 // Force GC to trigger verification.
16533 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16534 for (int i = 0; i < kElementCount; i++) {
16535 array->set(i, static_cast<ElementType>(i));
16537 // Force GC to trigger verification.
16538 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16539 for (int i = 0; i < kElementCount; i++) {
16540 CHECK_EQ(static_cast<int64_t>(i),
16541 static_cast<int64_t>(array->get_scalar(i)));
16542 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16545 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16546 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16547 // Set the elements to be the external array.
16548 obj->SetIndexedPropertiesToExternalArrayData(array_data,
16553 i::Object::GetElement(
16554 isolate, jsobj, 1).ToHandleChecked()->Number()));
16556 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16557 context.local(), obj, kElementCount, array_type, low, high);
16559 v8::Handle<v8::Value> result;
16561 // Test more complex manipulations which cause eax to contain values
16562 // that won't be completely overwritten by loads from the arrays.
16563 // This catches bugs in the instructions used for the KeyedLoadIC
16564 // for byte and word types.
16566 const int kXSize = 300;
16567 const int kYSize = 300;
16568 const int kLargeElementCount = kXSize * kYSize * 4;
16569 ElementType* large_array_data =
16570 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16571 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16572 // Set the elements to be the external array.
16573 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16575 kLargeElementCount);
16576 context->Global()->Set(v8_str("large_array"), large_obj);
16577 // Initialize contents of a few rows.
16578 for (int x = 0; x < 300; x++) {
16580 int offset = row * 300 * 4;
16581 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16582 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16583 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16584 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16586 offset = row * 300 * 4;
16587 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16588 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16589 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16590 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16592 offset = row * 300 * 4;
16593 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16594 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16595 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16596 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16598 // The goal of the code below is to make "offset" large enough
16599 // that the computation of the index (which goes into eax) has
16600 // high bits set which will not be overwritten by a byte or short
16602 result = CompileRun("var failed = false;"
16604 "for (var i = 0; i < 300; i++) {"
16605 " if (large_array[4 * i] != 127 ||"
16606 " large_array[4 * i + 1] != 0 ||"
16607 " large_array[4 * i + 2] != 0 ||"
16608 " large_array[4 * i + 3] != 127) {"
16612 "offset = 150 * 300 * 4;"
16613 "for (var i = 0; i < 300; i++) {"
16614 " if (large_array[offset + 4 * i] != 127 ||"
16615 " large_array[offset + 4 * i + 1] != 0 ||"
16616 " large_array[offset + 4 * i + 2] != 0 ||"
16617 " large_array[offset + 4 * i + 3] != 127) {"
16621 "offset = 298 * 300 * 4;"
16622 "for (var i = 0; i < 300; i++) {"
16623 " if (large_array[offset + 4 * i] != 127 ||"
16624 " large_array[offset + 4 * i + 1] != 0 ||"
16625 " large_array[offset + 4 * i + 2] != 0 ||"
16626 " large_array[offset + 4 * i + 3] != 127) {"
16631 CHECK_EQ(true, result->BooleanValue());
16632 free(large_array_data);
16635 // The "" property descriptor is overloaded to store information about
16636 // the external array. Ensure that setting and accessing the "" property
16637 // works (it should overwrite the information cached about the external
16638 // array in the DescriptorArray) in various situations.
16639 result = CompileRun("ext_array[''] = 23; ext_array['']");
16640 CHECK_EQ(23, result->Int32Value());
16642 // Property "" set after the external array is associated with the object.
16644 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16645 obj2->Set(v8_str("ee_test_field"),
16646 v8::Int32::New(context->GetIsolate(), 256));
16647 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16648 // Set the elements to be the external array.
16649 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16652 context->Global()->Set(v8_str("ext_array"), obj2);
16653 result = CompileRun("ext_array['']");
16654 CHECK_EQ(1503, result->Int32Value());
16657 // Property "" set after the external array is associated with the object.
16659 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16660 obj2->Set(v8_str("ee_test_field_2"),
16661 v8::Int32::New(context->GetIsolate(), 256));
16662 // Set the elements to be the external array.
16663 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16666 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16667 context->Global()->Set(v8_str("ext_array"), obj2);
16668 result = CompileRun("ext_array['']");
16669 CHECK_EQ(1503, result->Int32Value());
16672 // Should reuse the map from previous test.
16674 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16675 obj2->Set(v8_str("ee_test_field_2"),
16676 v8::Int32::New(context->GetIsolate(), 256));
16677 // Set the elements to be the external array. Should re-use the map
16678 // from previous test.
16679 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16682 context->Global()->Set(v8_str("ext_array"), obj2);
16683 result = CompileRun("ext_array['']");
16686 // Property "" is a constant function that shouldn't not be interfered with
16687 // when an external array is set.
16689 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16691 obj2->Set(v8_str("ee_test_field3"),
16692 v8::Int32::New(context->GetIsolate(), 256));
16694 // Add a constant function to an object.
16695 context->Global()->Set(v8_str("ext_array"), obj2);
16696 result = CompileRun("ext_array[''] = function() {return 1503;};"
16697 "ext_array['']();");
16699 // Add an external array transition to the same map that
16700 // has the constant transition.
16701 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16702 obj3->Set(v8_str("ee_test_field3"),
16703 v8::Int32::New(context->GetIsolate(), 256));
16704 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16707 context->Global()->Set(v8_str("ext_array"), obj3);
16710 // If a external array transition is in the map, it should get clobbered
16711 // by a constant function.
16713 // Add an external array transition.
16714 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16715 obj3->Set(v8_str("ee_test_field4"),
16716 v8::Int32::New(context->GetIsolate(), 256));
16717 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16721 // Add a constant function to the same map that just got an external array
16723 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16724 obj2->Set(v8_str("ee_test_field4"),
16725 v8::Int32::New(context->GetIsolate(), 256));
16726 context->Global()->Set(v8_str("ext_array"), obj2);
16727 result = CompileRun("ext_array[''] = function() {return 1503;};"
16728 "ext_array['']();");
16735 THREADED_TEST(ExternalInt8Array) {
16736 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16737 v8::kExternalInt8Array,
16743 THREADED_TEST(ExternalUint8Array) {
16744 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16745 v8::kExternalUint8Array,
16751 THREADED_TEST(ExternalUint8ClampedArray) {
16752 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16753 v8::kExternalUint8ClampedArray,
16759 THREADED_TEST(ExternalInt16Array) {
16760 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16761 v8::kExternalInt16Array,
16767 THREADED_TEST(ExternalUint16Array) {
16768 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16769 v8::kExternalUint16Array,
16775 THREADED_TEST(ExternalInt32Array) {
16776 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16777 v8::kExternalInt32Array,
16778 INT_MIN, // -2147483648
16779 INT_MAX); // 2147483647
16783 THREADED_TEST(ExternalUint32Array) {
16784 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16785 v8::kExternalUint32Array,
16787 UINT_MAX); // 4294967295
16791 THREADED_TEST(ExternalFloat32Array) {
16792 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16793 v8::kExternalFloat32Array,
16799 THREADED_TEST(ExternalFloat64Array) {
16800 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16801 v8::kExternalFloat64Array,
16807 THREADED_TEST(ExternalArrays) {
16808 TestExternalInt8Array();
16809 TestExternalUint8Array();
16810 TestExternalInt16Array();
16811 TestExternalUint16Array();
16812 TestExternalInt32Array();
16813 TestExternalUint32Array();
16814 TestExternalFloat32Array();
16818 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16819 LocalContext context;
16820 v8::HandleScope scope(context->GetIsolate());
16821 for (int size = 0; size < 100; size += 10) {
16822 int element_size = ExternalArrayElementSize(array_type);
16823 void* external_data = malloc(size * element_size);
16824 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16825 obj->SetIndexedPropertiesToExternalArrayData(
16826 external_data, array_type, size);
16827 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16828 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16829 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16830 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16831 free(external_data);
16836 THREADED_TEST(ExternalArrayInfo) {
16837 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16838 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16839 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16840 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16841 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16842 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16843 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16844 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16845 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16849 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16850 v8::ExternalArrayType array_type,
16852 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16853 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16854 last_location = last_message = NULL;
16855 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16856 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16857 CHECK_NE(NULL, last_location);
16858 CHECK_NE(NULL, last_message);
16862 TEST(ExternalArrayLimits) {
16863 LocalContext context;
16864 v8::Isolate* isolate = context->GetIsolate();
16865 v8::HandleScope scope(isolate);
16866 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16867 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16868 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16869 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16870 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16871 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16872 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16873 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16874 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16875 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16876 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16877 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16878 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16879 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16880 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16881 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16882 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16883 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16887 template <typename ElementType, typename TypedArray,
16888 class ExternalArrayClass>
16889 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16890 int64_t low, int64_t high) {
16891 const int kElementCount = 50;
16893 i::ScopedVector<ElementType> backing_store(kElementCount+2);
16896 v8::Isolate* isolate = env->GetIsolate();
16897 v8::HandleScope handle_scope(isolate);
16899 Local<v8::ArrayBuffer> ab =
16900 v8::ArrayBuffer::New(isolate, backing_store.start(),
16901 (kElementCount + 2) * sizeof(ElementType));
16902 Local<TypedArray> ta =
16903 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16904 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16905 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16906 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16907 CHECK_EQ(kElementCount*sizeof(ElementType),
16908 static_cast<int>(ta->ByteLength()));
16909 CHECK_EQ(ab, ta->Buffer());
16911 ElementType* data = backing_store.start() + 2;
16912 for (int i = 0; i < kElementCount; i++) {
16913 data[i] = static_cast<ElementType>(i);
16916 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16917 env.local(), ta, kElementCount, array_type, low, high);
16921 THREADED_TEST(Uint8Array) {
16922 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16923 v8::kExternalUint8Array, 0, 0xFF);
16927 THREADED_TEST(Int8Array) {
16928 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16929 v8::kExternalInt8Array, -0x80, 0x7F);
16933 THREADED_TEST(Uint16Array) {
16934 TypedArrayTestHelper<uint16_t,
16936 i::ExternalUint16Array>(
16937 v8::kExternalUint16Array, 0, 0xFFFF);
16941 THREADED_TEST(Int16Array) {
16942 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16943 v8::kExternalInt16Array, -0x8000, 0x7FFF);
16947 THREADED_TEST(Uint32Array) {
16948 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16949 v8::kExternalUint32Array, 0, UINT_MAX);
16953 THREADED_TEST(Int32Array) {
16954 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16955 v8::kExternalInt32Array, INT_MIN, INT_MAX);
16959 THREADED_TEST(Float32Array) {
16960 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16961 v8::kExternalFloat32Array, -500, 500);
16965 THREADED_TEST(Float64Array) {
16966 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16967 v8::kExternalFloat64Array, -500, 500);
16971 THREADED_TEST(Uint8ClampedArray) {
16972 TypedArrayTestHelper<uint8_t,
16973 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16974 v8::kExternalUint8ClampedArray, 0, 0xFF);
16978 THREADED_TEST(DataView) {
16979 const int kSize = 50;
16981 i::ScopedVector<uint8_t> backing_store(kSize+2);
16984 v8::Isolate* isolate = env->GetIsolate();
16985 v8::HandleScope handle_scope(isolate);
16987 Local<v8::ArrayBuffer> ab =
16988 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16989 Local<v8::DataView> dv =
16990 v8::DataView::New(ab, 2, kSize);
16991 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16992 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16993 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16994 CHECK_EQ(ab, dv->Buffer());
16998 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
16999 THREADED_TEST(Is##View) { \
17000 LocalContext env; \
17001 v8::Isolate* isolate = env->GetIsolate(); \
17002 v8::HandleScope handle_scope(isolate); \
17004 Handle<Value> result = CompileRun( \
17005 "var ab = new ArrayBuffer(128);" \
17006 "new " #View "(ab)"); \
17007 CHECK(result->IsArrayBufferView()); \
17008 CHECK(result->Is##View()); \
17009 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17012 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17013 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17014 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17015 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17016 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17017 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17018 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17019 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17020 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17021 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17023 #undef IS_ARRAY_BUFFER_VIEW_TEST
17027 THREADED_TEST(ScriptContextDependence) {
17029 v8::HandleScope scope(c1->GetIsolate());
17030 const char *source = "foo";
17031 v8::Handle<v8::Script> dep = v8_compile(source);
17032 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17033 c1->GetIsolate(), source));
17034 v8::Handle<v8::UnboundScript> indep =
17035 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17036 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17037 v8::Integer::New(c1->GetIsolate(), 100));
17038 CHECK_EQ(dep->Run()->Int32Value(), 100);
17039 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17041 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17042 v8::Integer::New(c2->GetIsolate(), 101));
17043 CHECK_EQ(dep->Run()->Int32Value(), 100);
17044 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17048 THREADED_TEST(StackTrace) {
17049 LocalContext context;
17050 v8::HandleScope scope(context->GetIsolate());
17051 v8::TryCatch try_catch;
17052 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17053 v8::Handle<v8::String> src =
17054 v8::String::NewFromUtf8(context->GetIsolate(), source);
17055 v8::Handle<v8::String> origin =
17056 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17057 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17058 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17059 ->BindToCurrentContext()
17061 CHECK(try_catch.HasCaught());
17062 v8::String::Utf8Value stack(try_catch.StackTrace());
17063 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17067 // Checks that a StackFrame has certain expected values.
17068 void checkStackFrame(const char* expected_script_name,
17069 const char* expected_func_name, int expected_line_number,
17070 int expected_column, bool is_eval, bool is_constructor,
17071 v8::Handle<v8::StackFrame> frame) {
17072 v8::HandleScope scope(CcTest::isolate());
17073 v8::String::Utf8Value func_name(frame->GetFunctionName());
17074 v8::String::Utf8Value script_name(frame->GetScriptName());
17075 if (*script_name == NULL) {
17076 // The situation where there is no associated script, like for evals.
17077 CHECK(expected_script_name == NULL);
17079 CHECK(strstr(*script_name, expected_script_name) != NULL);
17081 CHECK(strstr(*func_name, expected_func_name) != NULL);
17082 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17083 CHECK_EQ(expected_column, frame->GetColumn());
17084 CHECK_EQ(is_eval, frame->IsEval());
17085 CHECK_EQ(is_constructor, frame->IsConstructor());
17089 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17090 v8::HandleScope scope(args.GetIsolate());
17091 const char* origin = "capture-stack-trace-test";
17092 const int kOverviewTest = 1;
17093 const int kDetailedTest = 2;
17095 DCHECK(args.Length() == 1);
17097 int testGroup = args[0]->Int32Value();
17098 if (testGroup == kOverviewTest) {
17099 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17100 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17101 CHECK_EQ(4, stackTrace->GetFrameCount());
17102 checkStackFrame(origin, "bar", 2, 10, false, false,
17103 stackTrace->GetFrame(0));
17104 checkStackFrame(origin, "foo", 6, 3, false, false,
17105 stackTrace->GetFrame(1));
17106 // This is the source string inside the eval which has the call to foo.
17107 checkStackFrame(NULL, "", 1, 5, false, false,
17108 stackTrace->GetFrame(2));
17109 // The last frame is an anonymous function which has the initial eval call.
17110 checkStackFrame(origin, "", 8, 7, false, false,
17111 stackTrace->GetFrame(3));
17113 CHECK(stackTrace->AsArray()->IsArray());
17114 } else if (testGroup == kDetailedTest) {
17115 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17116 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17117 CHECK_EQ(4, stackTrace->GetFrameCount());
17118 checkStackFrame(origin, "bat", 4, 22, false, false,
17119 stackTrace->GetFrame(0));
17120 checkStackFrame(origin, "baz", 8, 3, false, true,
17121 stackTrace->GetFrame(1));
17122 bool is_eval = true;
17123 // This is the source string inside the eval which has the call to baz.
17124 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17125 stackTrace->GetFrame(2));
17126 // The last frame is an anonymous function which has the initial eval call.
17127 checkStackFrame(origin, "", 10, 1, false, false,
17128 stackTrace->GetFrame(3));
17130 CHECK(stackTrace->AsArray()->IsArray());
17135 // Tests the C++ StackTrace API.
17136 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17137 // THREADED_TEST(CaptureStackTrace) {
17138 TEST(CaptureStackTrace) {
17139 v8::Isolate* isolate = CcTest::isolate();
17140 v8::HandleScope scope(isolate);
17141 v8::Handle<v8::String> origin =
17142 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17143 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17144 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17145 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17146 LocalContext context(0, templ);
17148 // Test getting OVERVIEW information. Should ignore information that is not
17149 // script name, function name, line number, and column offset.
17150 const char *overview_source =
17151 "function bar() {\n"
17152 " var y; AnalyzeStackInNativeCode(1);\n"
17154 "function foo() {\n"
17158 "var x;eval('new foo();');";
17159 v8::Handle<v8::String> overview_src =
17160 v8::String::NewFromUtf8(isolate, overview_source);
17161 v8::ScriptCompiler::Source script_source(overview_src,
17162 v8::ScriptOrigin(origin));
17163 v8::Handle<Value> overview_result(
17164 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17165 ->BindToCurrentContext()
17167 CHECK(!overview_result.IsEmpty());
17168 CHECK(overview_result->IsObject());
17170 // Test getting DETAILED information.
17171 const char *detailed_source =
17172 "function bat() {AnalyzeStackInNativeCode(2);\n"
17175 "function baz() {\n"
17178 "eval('new baz();');";
17179 v8::Handle<v8::String> detailed_src =
17180 v8::String::NewFromUtf8(isolate, detailed_source);
17181 // Make the script using a non-zero line and column offset.
17182 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17183 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17184 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17185 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17186 v8::Handle<v8::UnboundScript> detailed_script(
17187 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17188 v8::Handle<Value> detailed_result(
17189 detailed_script->BindToCurrentContext()->Run());
17190 CHECK(!detailed_result.IsEmpty());
17191 CHECK(detailed_result->IsObject());
17195 static void StackTraceForUncaughtExceptionListener(
17196 v8::Handle<v8::Message> message,
17197 v8::Handle<Value>) {
17198 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17199 CHECK_EQ(2, stack_trace->GetFrameCount());
17200 checkStackFrame("origin", "foo", 2, 3, false, false,
17201 stack_trace->GetFrame(0));
17202 checkStackFrame("origin", "bar", 5, 3, false, false,
17203 stack_trace->GetFrame(1));
17207 TEST(CaptureStackTraceForUncaughtException) {
17210 v8::HandleScope scope(env->GetIsolate());
17211 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17212 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17214 CompileRunWithOrigin(
17215 "function foo() {\n"
17218 "function bar() {\n"
17222 v8::Local<v8::Object> global = env->Global();
17223 Local<Value> trouble = global->Get(v8_str("bar"));
17224 CHECK(trouble->IsFunction());
17225 Function::Cast(*trouble)->Call(global, 0, NULL);
17226 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17227 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17231 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17233 v8::HandleScope scope(env->GetIsolate());
17234 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17236 v8::StackTrace::kDetailed);
17239 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17240 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17241 " 'isConstructor'];\n"
17242 "for (var i = 0; i < setters.length; i++) {\n"
17243 " var prop = setters[i];\n"
17244 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17246 CompileRun("throw 'exception';");
17247 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17251 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17252 v8::Handle<v8::Value> data) {
17253 // Use the frame where JavaScript is called from.
17254 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17255 CHECK(!stack_trace.IsEmpty());
17256 int frame_count = stack_trace->GetFrameCount();
17257 CHECK_EQ(3, frame_count);
17258 int line_number[] = {1, 2, 5};
17259 for (int i = 0; i < frame_count; i++) {
17260 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17265 // Test that we only return the stack trace at the site where the exception
17266 // is first thrown (not where it is rethrown).
17267 TEST(RethrowStackTrace) {
17269 v8::HandleScope scope(env->GetIsolate());
17270 // We make sure that
17271 // - the stack trace of the ReferenceError in g() is reported.
17272 // - the stack trace is not overwritten when e1 is rethrown by t().
17273 // - the stack trace of e2 does not overwrite that of e1.
17274 const char* source =
17275 "function g() { error; } \n"
17276 "function f() { g(); } \n"
17277 "function t(e) { throw e; } \n"
17280 "} catch (e1) { \n"
17283 " } catch (e2) { \n"
17287 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17288 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17289 CompileRun(source);
17290 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17291 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17295 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17296 v8::Handle<v8::Value> data) {
17297 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17298 CHECK(!stack_trace.IsEmpty());
17299 int frame_count = stack_trace->GetFrameCount();
17300 CHECK_EQ(2, frame_count);
17301 int line_number[] = {3, 7};
17302 for (int i = 0; i < frame_count; i++) {
17303 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17308 // Test that we do not recognize identity for primitive exceptions.
17309 TEST(RethrowPrimitiveStackTrace) {
17311 v8::HandleScope scope(env->GetIsolate());
17312 // We do not capture stack trace for non Error objects on creation time.
17313 // Instead, we capture the stack trace on last throw.
17314 const char* source =
17315 "function g() { throw 404; } \n"
17316 "function f() { g(); } \n"
17317 "function t(e) { throw e; } \n"
17320 "} catch (e1) { \n"
17323 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17324 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17325 CompileRun(source);
17326 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17327 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17331 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17332 v8::Handle<v8::Value> data) {
17333 // Use the frame where JavaScript is called from.
17334 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17335 CHECK(!stack_trace.IsEmpty());
17336 CHECK_EQ(1, stack_trace->GetFrameCount());
17337 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17341 // Test that the stack trace is captured when the error object is created and
17342 // not where it is thrown.
17343 TEST(RethrowExistingStackTrace) {
17345 v8::HandleScope scope(env->GetIsolate());
17346 const char* source =
17347 "var e = new Error(); \n"
17349 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17350 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17351 CompileRun(source);
17352 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17353 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17357 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17358 v8::Handle<v8::Value> data) {
17359 // Use the frame where JavaScript is called from.
17360 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17361 CHECK(!stack_trace.IsEmpty());
17362 CHECK_EQ(1, stack_trace->GetFrameCount());
17363 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17367 // Test that the stack trace is captured where the bogus Error object is thrown.
17368 TEST(RethrowBogusErrorStackTrace) {
17370 v8::HandleScope scope(env->GetIsolate());
17371 const char* source =
17372 "var e = {__proto__: new Error()} \n"
17374 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17375 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17376 CompileRun(source);
17377 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17378 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17382 void AnalyzeStackOfEvalWithSourceURL(
17383 const v8::FunctionCallbackInfo<v8::Value>& args) {
17384 v8::HandleScope scope(args.GetIsolate());
17385 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17386 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17387 CHECK_EQ(5, stackTrace->GetFrameCount());
17388 v8::Handle<v8::String> url = v8_str("eval_url");
17389 for (int i = 0; i < 3; i++) {
17390 v8::Handle<v8::String> name =
17391 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17392 CHECK(!name.IsEmpty());
17393 CHECK_EQ(url, name);
17398 TEST(SourceURLInStackTrace) {
17399 v8::Isolate* isolate = CcTest::isolate();
17400 v8::HandleScope scope(isolate);
17401 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17402 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17403 v8::FunctionTemplate::New(isolate,
17404 AnalyzeStackOfEvalWithSourceURL));
17405 LocalContext context(0, templ);
17407 const char *source =
17408 "function outer() {\n"
17409 "function bar() {\n"
17410 " AnalyzeStackOfEvalWithSourceURL();\n"
17412 "function foo() {\n"
17418 "eval('(' + outer +')()%s');";
17420 i::ScopedVector<char> code(1024);
17421 i::SNPrintF(code, source, "//# sourceURL=eval_url");
17422 CHECK(CompileRun(code.start())->IsUndefined());
17423 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17424 CHECK(CompileRun(code.start())->IsUndefined());
17428 static int scriptIdInStack[2];
17430 void AnalyzeScriptIdInStack(
17431 const v8::FunctionCallbackInfo<v8::Value>& args) {
17432 v8::HandleScope scope(args.GetIsolate());
17433 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17434 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17435 CHECK_EQ(2, stackTrace->GetFrameCount());
17436 for (int i = 0; i < 2; i++) {
17437 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17442 TEST(ScriptIdInStackTrace) {
17443 v8::Isolate* isolate = CcTest::isolate();
17444 v8::HandleScope scope(isolate);
17445 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17446 templ->Set(v8_str("AnalyzeScriptIdInStack"),
17447 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17448 LocalContext context(0, templ);
17450 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17452 "function foo() {\n"
17453 " AnalyzeScriptIdInStack();"
17456 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17458 for (int i = 0; i < 2; i++) {
17459 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17460 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17465 void AnalyzeStackOfInlineScriptWithSourceURL(
17466 const v8::FunctionCallbackInfo<v8::Value>& args) {
17467 v8::HandleScope scope(args.GetIsolate());
17468 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17469 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17470 CHECK_EQ(4, stackTrace->GetFrameCount());
17471 v8::Handle<v8::String> url = v8_str("url");
17472 for (int i = 0; i < 3; i++) {
17473 v8::Handle<v8::String> name =
17474 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17475 CHECK(!name.IsEmpty());
17476 CHECK_EQ(url, name);
17481 TEST(InlineScriptWithSourceURLInStackTrace) {
17482 v8::Isolate* isolate = CcTest::isolate();
17483 v8::HandleScope scope(isolate);
17484 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17485 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17486 v8::FunctionTemplate::New(
17487 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17488 LocalContext context(0, templ);
17490 const char *source =
17491 "function outer() {\n"
17492 "function bar() {\n"
17493 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
17495 "function foo() {\n"
17503 i::ScopedVector<char> code(1024);
17504 i::SNPrintF(code, source, "//# sourceURL=source_url");
17505 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17506 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17507 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17511 void AnalyzeStackOfDynamicScriptWithSourceURL(
17512 const v8::FunctionCallbackInfo<v8::Value>& args) {
17513 v8::HandleScope scope(args.GetIsolate());
17514 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17515 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17516 CHECK_EQ(4, stackTrace->GetFrameCount());
17517 v8::Handle<v8::String> url = v8_str("source_url");
17518 for (int i = 0; i < 3; i++) {
17519 v8::Handle<v8::String> name =
17520 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17521 CHECK(!name.IsEmpty());
17522 CHECK_EQ(url, name);
17527 TEST(DynamicWithSourceURLInStackTrace) {
17528 v8::Isolate* isolate = CcTest::isolate();
17529 v8::HandleScope scope(isolate);
17530 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17531 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17532 v8::FunctionTemplate::New(
17533 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17534 LocalContext context(0, templ);
17536 const char *source =
17537 "function outer() {\n"
17538 "function bar() {\n"
17539 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17541 "function foo() {\n"
17549 i::ScopedVector<char> code(1024);
17550 i::SNPrintF(code, source, "//# sourceURL=source_url");
17551 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17552 i::SNPrintF(code, source, "//@ sourceURL=source_url");
17553 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17557 TEST(DynamicWithSourceURLInStackTraceString) {
17558 LocalContext context;
17559 v8::HandleScope scope(context->GetIsolate());
17561 const char *source =
17562 "function outer() {\n"
17563 " function foo() {\n"
17570 i::ScopedVector<char> code(1024);
17571 i::SNPrintF(code, source, "//# sourceURL=source_url");
17572 v8::TryCatch try_catch;
17573 CompileRunWithOrigin(code.start(), "", 0, 0);
17574 CHECK(try_catch.HasCaught());
17575 v8::String::Utf8Value stack(try_catch.StackTrace());
17576 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17580 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17581 LocalContext context;
17582 v8::HandleScope scope(context->GetIsolate());
17584 const char *source =
17585 "function outer() {\n"
17586 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17587 " //# sourceURL=source_url\";\n"
17588 " eval(scriptContents);\n"
17591 "//# sourceURL=outer_url";
17593 v8::TryCatch try_catch;
17594 CompileRun(source);
17595 CHECK(try_catch.HasCaught());
17597 Local<v8::Message> message = try_catch.Message();
17598 Handle<Value> sourceURL =
17599 message->GetScriptOrigin().ResourceName();
17600 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17604 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17605 LocalContext context;
17606 v8::HandleScope scope(context->GetIsolate());
17608 const char *source =
17609 "function outer() {\n"
17610 " var scriptContents = \"function boo(){ boo(); }\\\n"
17611 " //# sourceURL=source_url\";\n"
17612 " eval(scriptContents);\n"
17615 "//# sourceURL=outer_url";
17617 v8::TryCatch try_catch;
17618 CompileRun(source);
17619 CHECK(try_catch.HasCaught());
17621 Local<v8::Message> message = try_catch.Message();
17622 Handle<Value> sourceURL =
17623 message->GetScriptOrigin().ResourceName();
17624 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17628 static void CreateGarbageInOldSpace() {
17629 i::Factory* factory = CcTest::i_isolate()->factory();
17630 v8::HandleScope scope(CcTest::isolate());
17631 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17632 for (int i = 0; i < 1000; i++) {
17633 factory->NewFixedArray(1000, i::TENURED);
17638 // Test that idle notification can be handled and eventually returns true.
17639 TEST(IdleNotification) {
17640 const intptr_t MB = 1024 * 1024;
17641 const int IdlePauseInMs = 1000;
17643 v8::HandleScope scope(env->GetIsolate());
17644 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17645 CreateGarbageInOldSpace();
17646 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17647 CHECK_GT(size_with_garbage, initial_size + MB);
17648 bool finished = false;
17649 for (int i = 0; i < 200 && !finished; i++) {
17650 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17652 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17654 CHECK_LT(final_size, initial_size + 1);
17658 // Test that idle notification can be handled and eventually collects garbage.
17659 TEST(IdleNotificationWithSmallHint) {
17660 const intptr_t MB = 1024 * 1024;
17661 const int IdlePauseInMs = 900;
17663 v8::HandleScope scope(env->GetIsolate());
17664 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17665 CreateGarbageInOldSpace();
17666 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17667 CHECK_GT(size_with_garbage, initial_size + MB);
17668 bool finished = false;
17669 for (int i = 0; i < 200 && !finished; i++) {
17670 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17672 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17674 CHECK_LT(final_size, initial_size + 1);
17678 // Test that idle notification can be handled and eventually collects garbage.
17679 TEST(IdleNotificationWithLargeHint) {
17680 const intptr_t MB = 1024 * 1024;
17681 const int IdlePauseInMs = 900;
17683 v8::HandleScope scope(env->GetIsolate());
17684 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17685 CreateGarbageInOldSpace();
17686 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17687 CHECK_GT(size_with_garbage, initial_size + MB);
17688 bool finished = false;
17689 for (int i = 0; i < 200 && !finished; i++) {
17690 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17692 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17694 CHECK_LT(final_size, initial_size + 1);
17698 TEST(Regress2107) {
17699 const intptr_t MB = 1024 * 1024;
17700 const int kShortIdlePauseInMs = 100;
17701 const int kLongIdlePauseInMs = 1000;
17703 v8::Isolate* isolate = env->GetIsolate();
17704 v8::HandleScope scope(env->GetIsolate());
17705 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17706 // Send idle notification to start a round of incremental GCs.
17707 env->GetIsolate()->IdleNotification(kShortIdlePauseInMs);
17708 // Emulate 7 page reloads.
17709 for (int i = 0; i < 7; i++) {
17711 v8::HandleScope inner_scope(env->GetIsolate());
17712 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17714 CreateGarbageInOldSpace();
17717 env->GetIsolate()->ContextDisposedNotification();
17718 env->GetIsolate()->IdleNotification(kLongIdlePauseInMs);
17720 // Create garbage and check that idle notification still collects it.
17721 CreateGarbageInOldSpace();
17722 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17723 CHECK_GT(size_with_garbage, initial_size + MB);
17724 bool finished = false;
17725 for (int i = 0; i < 200 && !finished; i++) {
17726 finished = env->GetIsolate()->IdleNotification(kShortIdlePauseInMs);
17728 intptr_t final_size = CcTest::heap()->SizeOfObjects();
17729 CHECK_LT(final_size, initial_size + 1);
17733 TEST(Regress2333) {
17735 for (int i = 0; i < 3; i++) {
17736 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17740 static uint32_t* stack_limit;
17742 static void GetStackLimitCallback(
17743 const v8::FunctionCallbackInfo<v8::Value>& args) {
17744 stack_limit = reinterpret_cast<uint32_t*>(
17745 CcTest::i_isolate()->stack_guard()->real_climit());
17749 // Uses the address of a local variable to determine the stack top now.
17750 // Given a size, returns an address that is that far from the current
17752 static uint32_t* ComputeStackLimit(uint32_t size) {
17753 uint32_t* answer = &size - (size / sizeof(size));
17754 // If the size is very large and the stack is very near the bottom of
17755 // memory then the calculation above may wrap around and give an address
17756 // that is above the (downwards-growing) stack. In that case we return
17757 // a very low address.
17758 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17763 // We need at least 165kB for an x64 debug build with clang and ASAN.
17764 static const int stack_breathing_room = 256 * i::KB;
17767 TEST(SetResourceConstraints) {
17768 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17770 // Set stack limit.
17771 v8::ResourceConstraints constraints;
17772 constraints.set_stack_limit(set_limit);
17773 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17775 // Execute a script.
17777 v8::HandleScope scope(env->GetIsolate());
17778 Local<v8::FunctionTemplate> fun_templ =
17779 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17780 Local<Function> fun = fun_templ->GetFunction();
17781 env->Global()->Set(v8_str("get_stack_limit"), fun);
17782 CompileRun("get_stack_limit();");
17784 CHECK(stack_limit == set_limit);
17788 TEST(SetResourceConstraintsInThread) {
17789 uint32_t* set_limit;
17791 v8::Locker locker(CcTest::isolate());
17792 set_limit = ComputeStackLimit(stack_breathing_room);
17794 // Set stack limit.
17795 v8::ResourceConstraints constraints;
17796 constraints.set_stack_limit(set_limit);
17797 CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17799 // Execute a script.
17800 v8::HandleScope scope(CcTest::isolate());
17802 Local<v8::FunctionTemplate> fun_templ =
17803 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17804 Local<Function> fun = fun_templ->GetFunction();
17805 env->Global()->Set(v8_str("get_stack_limit"), fun);
17806 CompileRun("get_stack_limit();");
17808 CHECK(stack_limit == set_limit);
17811 v8::Locker locker(CcTest::isolate());
17812 CHECK(stack_limit == set_limit);
17817 THREADED_TEST(GetHeapStatistics) {
17819 v8::HandleScope scope(c1->GetIsolate());
17820 v8::HeapStatistics heap_statistics;
17821 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17822 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17823 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17824 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17825 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17829 class VisitorImpl : public v8::ExternalResourceVisitor {
17831 explicit VisitorImpl(TestResource** resource) {
17832 for (int i = 0; i < 4; i++) {
17833 resource_[i] = resource[i];
17834 found_resource_[i] = false;
17837 virtual ~VisitorImpl() {}
17838 virtual void VisitExternalString(v8::Handle<v8::String> string) {
17839 if (!string->IsExternal()) {
17840 CHECK(string->IsExternalAscii());
17843 v8::String::ExternalStringResource* resource =
17844 string->GetExternalStringResource();
17846 for (int i = 0; i < 4; i++) {
17847 if (resource_[i] == resource) {
17848 CHECK(!found_resource_[i]);
17849 found_resource_[i] = true;
17853 void CheckVisitedResources() {
17854 for (int i = 0; i < 4; i++) {
17855 CHECK(found_resource_[i]);
17860 v8::String::ExternalStringResource* resource_[4];
17861 bool found_resource_[4];
17865 TEST(ExternalizeOldSpaceTwoByteCons) {
17867 v8::HandleScope scope(env->GetIsolate());
17868 v8::Local<v8::String> cons =
17869 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17870 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17871 CcTest::heap()->CollectAllAvailableGarbage();
17872 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17873 *v8::Utils::OpenHandle(*cons)));
17875 TestResource* resource = new TestResource(
17876 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17877 cons->MakeExternal(resource);
17879 CHECK(cons->IsExternal());
17880 CHECK_EQ(resource, cons->GetExternalStringResource());
17881 String::Encoding encoding;
17882 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17883 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17887 TEST(ExternalizeOldSpaceOneByteCons) {
17889 v8::HandleScope scope(env->GetIsolate());
17890 v8::Local<v8::String> cons =
17891 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17892 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17893 CcTest::heap()->CollectAllAvailableGarbage();
17894 CHECK(CcTest::heap()->old_pointer_space()->Contains(
17895 *v8::Utils::OpenHandle(*cons)));
17897 TestAsciiResource* resource =
17898 new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17899 cons->MakeExternal(resource);
17901 CHECK(cons->IsExternalAscii());
17902 CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17903 String::Encoding encoding;
17904 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17905 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17909 TEST(VisitExternalStrings) {
17911 v8::HandleScope scope(env->GetIsolate());
17912 const char* string = "Some string";
17913 uint16_t* two_byte_string = AsciiToTwoByteString(string);
17914 TestResource* resource[4];
17915 resource[0] = new TestResource(two_byte_string);
17916 v8::Local<v8::String> string0 =
17917 v8::String::NewExternal(env->GetIsolate(), resource[0]);
17918 resource[1] = new TestResource(two_byte_string, NULL, false);
17919 v8::Local<v8::String> string1 =
17920 v8::String::NewExternal(env->GetIsolate(), resource[1]);
17922 // Externalized symbol.
17923 resource[2] = new TestResource(two_byte_string, NULL, false);
17924 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17925 env->GetIsolate(), string, v8::String::kInternalizedString);
17926 CHECK(string2->MakeExternal(resource[2]));
17928 // Symbolized External.
17929 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17930 v8::Local<v8::String> string3 =
17931 v8::String::NewExternal(env->GetIsolate(), resource[3]);
17932 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
17933 // Turn into a symbol.
17934 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17935 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
17936 string3_i).is_null());
17937 CHECK(string3_i->IsInternalizedString());
17939 // We need to add usages for string* to avoid warnings in GCC 4.7
17940 CHECK(string0->IsExternal());
17941 CHECK(string1->IsExternal());
17942 CHECK(string2->IsExternal());
17943 CHECK(string3->IsExternal());
17945 VisitorImpl visitor(resource);
17946 v8::V8::VisitExternalResources(&visitor);
17947 visitor.CheckVisitedResources();
17951 TEST(ExternalStringCollectedAtTearDown) {
17953 v8::Isolate* isolate = v8::Isolate::New();
17954 { v8::Isolate::Scope isolate_scope(isolate);
17955 v8::HandleScope handle_scope(isolate);
17956 const char* s = "One string to test them all, one string to find them.";
17957 TestAsciiResource* inscription =
17958 new TestAsciiResource(i::StrDup(s), &destroyed);
17959 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17960 // Ring is still alive. Orcs are roaming freely across our lands.
17961 CHECK_EQ(0, destroyed);
17965 isolate->Dispose();
17966 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17967 CHECK_EQ(1, destroyed);
17971 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17973 v8::Isolate* isolate = v8::Isolate::New();
17974 { v8::Isolate::Scope isolate_scope(isolate);
17975 LocalContext env(isolate);
17976 v8::HandleScope handle_scope(isolate);
17977 CompileRun("var ring = 'One string to test them all';");
17978 const char* s = "One string to test them all";
17979 TestAsciiResource* inscription =
17980 new TestAsciiResource(i::StrDup(s), &destroyed);
17981 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17982 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17983 ring->MakeExternal(inscription);
17984 // Ring is still alive. Orcs are roaming freely across our lands.
17985 CHECK_EQ(0, destroyed);
17989 isolate->Dispose();
17990 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
17991 CHECK_EQ(1, destroyed);
17995 TEST(ExternalInternalizedStringCollectedAtGC) {
17997 { LocalContext env;
17998 v8::HandleScope handle_scope(env->GetIsolate());
17999 CompileRun("var ring = 'One string to test them all';");
18000 const char* s = "One string to test them all";
18001 TestAsciiResource* inscription =
18002 new TestAsciiResource(i::StrDup(s), &destroyed);
18003 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18004 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18005 ring->MakeExternal(inscription);
18006 // Ring is still alive. Orcs are roaming freely across our lands.
18007 CHECK_EQ(0, destroyed);
18011 // Garbage collector deals swift blows to evil.
18012 CcTest::i_isolate()->compilation_cache()->Clear();
18013 CcTest::heap()->CollectAllAvailableGarbage();
18015 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18016 CHECK_EQ(1, destroyed);
18020 static double DoubleFromBits(uint64_t value) {
18022 i::MemCopy(&target, &value, sizeof(target));
18027 static uint64_t DoubleToBits(double value) {
18029 i::MemCopy(&target, &value, sizeof(target));
18034 static double DoubleToDateTime(double input) {
18035 double date_limit = 864e13;
18036 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18037 return v8::base::OS::nan_value();
18039 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18043 // We don't have a consistent way to write 64-bit constants syntactically, so we
18044 // split them into two 32-bit constants and combine them programmatically.
18045 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18046 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18050 THREADED_TEST(QuietSignalingNaNs) {
18051 LocalContext context;
18052 v8::Isolate* isolate = context->GetIsolate();
18053 v8::HandleScope scope(isolate);
18054 v8::TryCatch try_catch;
18056 // Special double values.
18057 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18058 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18059 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18060 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18061 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18062 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18063 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18065 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18066 // on either side of the epoch.
18067 double date_limit = 864e13;
18069 double test_values[] = {
18091 int num_test_values = 20;
18093 for (int i = 0; i < num_test_values; i++) {
18094 double test_value = test_values[i];
18096 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18097 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18098 double stored_number = number->NumberValue();
18099 if (!std::isnan(test_value)) {
18100 CHECK_EQ(test_value, stored_number);
18102 uint64_t stored_bits = DoubleToBits(stored_number);
18103 // Check if quiet nan (bits 51..62 all set).
18104 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18105 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18106 // Most significant fraction bit for quiet nan is set to 0
18107 // on MIPS architecture. Allowed by IEEE-754.
18108 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18110 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18114 // Check that Date::New preserves non-NaNs in the date range and
18116 v8::Handle<v8::Value> date =
18117 v8::Date::New(isolate, test_value);
18118 double expected_stored_date = DoubleToDateTime(test_value);
18119 double stored_date = date->NumberValue();
18120 if (!std::isnan(expected_stored_date)) {
18121 CHECK_EQ(expected_stored_date, stored_date);
18123 uint64_t stored_bits = DoubleToBits(stored_date);
18124 // Check if quiet nan (bits 51..62 all set).
18125 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18126 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18127 // Most significant fraction bit for quiet nan is set to 0
18128 // on MIPS architecture. Allowed by IEEE-754.
18129 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18131 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18138 static void SpaghettiIncident(
18139 const v8::FunctionCallbackInfo<v8::Value>& args) {
18140 v8::HandleScope scope(args.GetIsolate());
18142 v8::Handle<v8::String> str(args[0]->ToString());
18144 if (tc.HasCaught())
18149 // Test that an exception can be propagated down through a spaghetti
18150 // stack using ReThrow.
18151 THREADED_TEST(SpaghettiStackReThrow) {
18152 v8::Isolate* isolate = CcTest::isolate();
18153 v8::HandleScope scope(isolate);
18154 LocalContext context;
18155 context->Global()->Set(
18156 v8::String::NewFromUtf8(isolate, "s"),
18157 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18158 v8::TryCatch try_catch;
18162 " toString: function () {"
18172 CHECK(try_catch.HasCaught());
18173 v8::String::Utf8Value value(try_catch.Exception());
18174 CHECK_EQ(0, strcmp(*value, "Hey!"));
18179 v8::V8::Initialize();
18180 v8::Isolate* isolate = CcTest::isolate();
18181 v8::HandleScope scope(isolate);
18182 v8::Local<Context> other_context;
18185 // Create a context used to keep the code from aging in the compilation
18187 other_context = Context::New(isolate);
18189 // Context-dependent context data creates reference from the compilation
18190 // cache to the global object.
18191 const char* source_simple = "1";
18193 v8::HandleScope scope(isolate);
18194 v8::Local<Context> context = Context::New(isolate);
18197 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18198 context->SetEmbedderData(0, obj);
18199 CompileRun(source_simple);
18202 isolate->ContextDisposedNotification();
18203 for (gc_count = 1; gc_count < 10; gc_count++) {
18204 other_context->Enter();
18205 CompileRun(source_simple);
18206 other_context->Exit();
18207 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18208 if (GetGlobalObjectsCount() == 1) break;
18210 CHECK_GE(2, gc_count);
18211 CHECK_EQ(1, GetGlobalObjectsCount());
18213 // Eval in a function creates reference from the compilation cache to the
18215 const char* source_eval = "function f(){eval('1')}; f()";
18217 v8::HandleScope scope(isolate);
18218 v8::Local<Context> context = Context::New(isolate);
18221 CompileRun(source_eval);
18224 isolate->ContextDisposedNotification();
18225 for (gc_count = 1; gc_count < 10; gc_count++) {
18226 other_context->Enter();
18227 CompileRun(source_eval);
18228 other_context->Exit();
18229 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18230 if (GetGlobalObjectsCount() == 1) break;
18232 CHECK_GE(2, gc_count);
18233 CHECK_EQ(1, GetGlobalObjectsCount());
18235 // Looking up the line number for an exception creates reference from the
18236 // compilation cache to the global object.
18237 const char* source_exception = "function f(){throw 1;} f()";
18239 v8::HandleScope scope(isolate);
18240 v8::Local<Context> context = Context::New(isolate);
18243 v8::TryCatch try_catch;
18244 CompileRun(source_exception);
18245 CHECK(try_catch.HasCaught());
18246 v8::Handle<v8::Message> message = try_catch.Message();
18247 CHECK(!message.IsEmpty());
18248 CHECK_EQ(1, message->GetLineNumber());
18251 isolate->ContextDisposedNotification();
18252 for (gc_count = 1; gc_count < 10; gc_count++) {
18253 other_context->Enter();
18254 CompileRun(source_exception);
18255 other_context->Exit();
18256 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18257 if (GetGlobalObjectsCount() == 1) break;
18259 CHECK_GE(2, gc_count);
18260 CHECK_EQ(1, GetGlobalObjectsCount());
18262 isolate->ContextDisposedNotification();
18266 THREADED_TEST(ScriptOrigin) {
18268 v8::HandleScope scope(env->GetIsolate());
18269 v8::ScriptOrigin origin =
18270 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18271 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18272 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18273 v8::Script::Compile(script, &origin)->Run();
18274 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18275 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18276 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18277 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18279 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18280 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18281 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18283 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18284 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18285 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18289 THREADED_TEST(FunctionGetInferredName) {
18291 v8::HandleScope scope(env->GetIsolate());
18292 v8::ScriptOrigin origin =
18293 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18294 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18296 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18297 v8::Script::Compile(script, &origin)->Run();
18298 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18299 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18300 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18304 THREADED_TEST(FunctionGetDisplayName) {
18306 v8::HandleScope scope(env->GetIsolate());
18307 const char* code = "var error = false;"
18308 "function a() { this.x = 1; };"
18309 "a.displayName = 'display_a';"
18310 "var b = (function() {"
18311 " var f = function() { this.x = 2; };"
18312 " f.displayName = 'display_b';"
18315 "var c = function() {};"
18316 "c.__defineGetter__('displayName', function() {"
18318 " throw new Error();"
18321 "d.__defineGetter__('displayName', function() {"
18323 " return 'wrong_display_name';"
18326 "e.displayName = 'wrong_display_name';"
18327 "e.__defineSetter__('displayName', function() {"
18329 " throw new Error();"
18332 "f.displayName = { 'foo': 6, toString: function() {"
18334 " return 'wrong_display_name';"
18336 "var g = function() {"
18337 " arguments.callee.displayName = 'set_in_runtime';"
18340 v8::ScriptOrigin origin =
18341 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18342 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18344 v8::Local<v8::Value> error =
18345 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18346 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18347 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18348 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18349 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18350 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18351 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18352 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18353 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18354 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18355 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18356 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18357 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18358 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18359 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18360 CHECK_EQ(false, error->BooleanValue());
18361 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18362 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18363 CHECK(c->GetDisplayName()->IsUndefined());
18364 CHECK(d->GetDisplayName()->IsUndefined());
18365 CHECK(e->GetDisplayName()->IsUndefined());
18366 CHECK(f->GetDisplayName()->IsUndefined());
18367 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18371 THREADED_TEST(ScriptLineNumber) {
18373 v8::HandleScope scope(env->GetIsolate());
18374 v8::ScriptOrigin origin =
18375 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18376 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18377 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18378 v8::Script::Compile(script, &origin)->Run();
18379 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18380 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18381 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18382 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18383 CHECK_EQ(0, f->GetScriptLineNumber());
18384 CHECK_EQ(2, g->GetScriptLineNumber());
18388 THREADED_TEST(ScriptColumnNumber) {
18390 v8::Isolate* isolate = env->GetIsolate();
18391 v8::HandleScope scope(isolate);
18392 v8::ScriptOrigin origin =
18393 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18394 v8::Integer::New(isolate, 3),
18395 v8::Integer::New(isolate, 2));
18396 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18397 isolate, "function foo() {}\n\n function bar() {}");
18398 v8::Script::Compile(script, &origin)->Run();
18399 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18400 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18401 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18402 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18403 CHECK_EQ(14, foo->GetScriptColumnNumber());
18404 CHECK_EQ(17, bar->GetScriptColumnNumber());
18408 THREADED_TEST(FunctionIsBuiltin) {
18410 v8::Isolate* isolate = env->GetIsolate();
18411 v8::HandleScope scope(isolate);
18412 v8::Local<v8::Function> f;
18413 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18414 CHECK(f->IsBuiltin());
18415 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18416 CHECK(f->IsBuiltin());
18417 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18418 CHECK(f->IsBuiltin());
18419 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18420 CHECK(f->IsBuiltin());
18421 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18422 CHECK(!f->IsBuiltin());
18426 THREADED_TEST(FunctionGetScriptId) {
18428 v8::Isolate* isolate = env->GetIsolate();
18429 v8::HandleScope scope(isolate);
18430 v8::ScriptOrigin origin =
18431 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18432 v8::Integer::New(isolate, 3),
18433 v8::Integer::New(isolate, 2));
18434 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18435 isolate, "function foo() {}\n\n function bar() {}");
18436 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18438 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18439 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18440 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18441 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18442 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18443 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18447 THREADED_TEST(FunctionGetBoundFunction) {
18449 v8::HandleScope scope(env->GetIsolate());
18450 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18451 env->GetIsolate(), "test"));
18452 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18454 "var a = new Object();\n"
18456 "function f () { return this.x };\n"
18457 "var g = f.bind(a);\n"
18459 v8::Script::Compile(script, &origin)->Run();
18460 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18461 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18462 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18463 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18464 CHECK(g->GetBoundFunction()->IsFunction());
18465 Local<v8::Function> original_function = Local<v8::Function>::Cast(
18466 g->GetBoundFunction());
18467 CHECK_EQ(f->GetName(), original_function->GetName());
18468 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18469 CHECK_EQ(f->GetScriptColumnNumber(),
18470 original_function->GetScriptColumnNumber());
18474 static void GetterWhichReturns42(
18475 Local<String> name,
18476 const v8::PropertyCallbackInfo<v8::Value>& info) {
18477 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18478 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18479 info.GetReturnValue().Set(v8_num(42));
18483 static void SetterWhichSetsYOnThisTo23(
18484 Local<String> name,
18485 Local<Value> value,
18486 const v8::PropertyCallbackInfo<void>& info) {
18487 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18488 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18489 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18493 void FooGetInterceptor(Local<String> name,
18494 const v8::PropertyCallbackInfo<v8::Value>& info) {
18495 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18496 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18497 if (!name->Equals(v8_str("foo"))) return;
18498 info.GetReturnValue().Set(v8_num(42));
18502 void FooSetInterceptor(Local<String> name,
18503 Local<Value> value,
18504 const v8::PropertyCallbackInfo<v8::Value>& info) {
18505 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18506 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18507 if (!name->Equals(v8_str("foo"))) return;
18508 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18509 info.GetReturnValue().Set(v8_num(23));
18513 TEST(SetterOnConstructorPrototype) {
18514 v8::Isolate* isolate = CcTest::isolate();
18515 v8::HandleScope scope(isolate);
18516 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18517 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18518 SetterWhichSetsYOnThisTo23);
18519 LocalContext context;
18520 context->Global()->Set(v8_str("P"), templ->NewInstance());
18521 CompileRun("function C1() {"
18524 "C1.prototype = P;"
18528 "C2.prototype = { };"
18529 "C2.prototype.__proto__ = P;");
18531 v8::Local<v8::Script> script;
18532 script = v8_compile("new C1();");
18533 for (int i = 0; i < 10; i++) {
18534 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18535 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18536 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18539 script = v8_compile("new C2();");
18540 for (int i = 0; i < 10; i++) {
18541 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18542 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18543 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18548 static void NamedPropertyGetterWhichReturns42(
18549 Local<String> name,
18550 const v8::PropertyCallbackInfo<v8::Value>& info) {
18551 info.GetReturnValue().Set(v8_num(42));
18555 static void NamedPropertySetterWhichSetsYOnThisTo23(
18556 Local<String> name,
18557 Local<Value> value,
18558 const v8::PropertyCallbackInfo<v8::Value>& info) {
18559 if (name->Equals(v8_str("x"))) {
18560 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18565 THREADED_TEST(InterceptorOnConstructorPrototype) {
18566 v8::Isolate* isolate = CcTest::isolate();
18567 v8::HandleScope scope(isolate);
18568 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18569 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18570 NamedPropertySetterWhichSetsYOnThisTo23);
18571 LocalContext context;
18572 context->Global()->Set(v8_str("P"), templ->NewInstance());
18573 CompileRun("function C1() {"
18576 "C1.prototype = P;"
18580 "C2.prototype = { };"
18581 "C2.prototype.__proto__ = P;");
18583 v8::Local<v8::Script> script;
18584 script = v8_compile("new C1();");
18585 for (int i = 0; i < 10; i++) {
18586 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18587 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18588 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18591 script = v8_compile("new C2();");
18592 for (int i = 0; i < 10; i++) {
18593 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18594 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18595 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18601 const char* source = "function C1() {"
18604 "C1.prototype = P;";
18606 LocalContext context;
18607 v8::Isolate* isolate = context->GetIsolate();
18608 v8::HandleScope scope(isolate);
18609 v8::Local<v8::Script> script;
18611 // Use a simple object as prototype.
18612 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18613 prototype->Set(v8_str("y"), v8_num(42));
18614 context->Global()->Set(v8_str("P"), prototype);
18616 // This compile will add the code to the compilation cache.
18617 CompileRun(source);
18619 script = v8_compile("new C1();");
18620 // Allow enough iterations for the inobject slack tracking logic
18621 // to finalize instance size and install the fast construct stub.
18622 for (int i = 0; i < 256; i++) {
18623 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18624 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18625 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18628 // Use an API object with accessors as prototype.
18629 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18630 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18631 SetterWhichSetsYOnThisTo23);
18632 context->Global()->Set(v8_str("P"), templ->NewInstance());
18634 // This compile will get the code from the compilation cache.
18635 CompileRun(source);
18637 script = v8_compile("new C1();");
18638 for (int i = 0; i < 10; i++) {
18639 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18640 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18641 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18645 v8::Isolate* gc_callbacks_isolate = NULL;
18646 int prologue_call_count = 0;
18647 int epilogue_call_count = 0;
18648 int prologue_call_count_second = 0;
18649 int epilogue_call_count_second = 0;
18650 int prologue_call_count_alloc = 0;
18651 int epilogue_call_count_alloc = 0;
18653 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18654 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18655 ++prologue_call_count;
18659 void PrologueCallback(v8::Isolate* isolate,
18661 v8::GCCallbackFlags flags) {
18662 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18663 CHECK_EQ(gc_callbacks_isolate, isolate);
18664 ++prologue_call_count;
18668 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18669 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18670 ++epilogue_call_count;
18674 void EpilogueCallback(v8::Isolate* isolate,
18676 v8::GCCallbackFlags flags) {
18677 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18678 CHECK_EQ(gc_callbacks_isolate, isolate);
18679 ++epilogue_call_count;
18683 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18684 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18685 ++prologue_call_count_second;
18689 void PrologueCallbackSecond(v8::Isolate* isolate,
18691 v8::GCCallbackFlags flags) {
18692 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18693 CHECK_EQ(gc_callbacks_isolate, isolate);
18694 ++prologue_call_count_second;
18698 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18699 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18700 ++epilogue_call_count_second;
18704 void EpilogueCallbackSecond(v8::Isolate* isolate,
18706 v8::GCCallbackFlags flags) {
18707 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18708 CHECK_EQ(gc_callbacks_isolate, isolate);
18709 ++epilogue_call_count_second;
18713 void PrologueCallbackAlloc(v8::Isolate* isolate,
18715 v8::GCCallbackFlags flags) {
18716 v8::HandleScope scope(isolate);
18718 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18719 CHECK_EQ(gc_callbacks_isolate, isolate);
18720 ++prologue_call_count_alloc;
18722 // Simulate full heap to see if we will reenter this callback
18723 SimulateFullSpace(CcTest::heap()->new_space());
18725 Local<Object> obj = Object::New(isolate);
18726 CHECK(!obj.IsEmpty());
18728 CcTest::heap()->CollectAllGarbage(
18729 i::Heap::kAbortIncrementalMarkingMask);
18733 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18735 v8::GCCallbackFlags flags) {
18736 v8::HandleScope scope(isolate);
18738 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18739 CHECK_EQ(gc_callbacks_isolate, isolate);
18740 ++epilogue_call_count_alloc;
18742 // Simulate full heap to see if we will reenter this callback
18743 SimulateFullSpace(CcTest::heap()->new_space());
18745 Local<Object> obj = Object::New(isolate);
18746 CHECK(!obj.IsEmpty());
18748 CcTest::heap()->CollectAllGarbage(
18749 i::Heap::kAbortIncrementalMarkingMask);
18753 TEST(GCCallbacksOld) {
18754 LocalContext context;
18756 v8::V8::AddGCPrologueCallback(PrologueCallback);
18757 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18758 CHECK_EQ(0, prologue_call_count);
18759 CHECK_EQ(0, epilogue_call_count);
18760 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18761 CHECK_EQ(1, prologue_call_count);
18762 CHECK_EQ(1, epilogue_call_count);
18763 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18764 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18765 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18766 CHECK_EQ(2, prologue_call_count);
18767 CHECK_EQ(2, epilogue_call_count);
18768 CHECK_EQ(1, prologue_call_count_second);
18769 CHECK_EQ(1, epilogue_call_count_second);
18770 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18771 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18772 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18773 CHECK_EQ(2, prologue_call_count);
18774 CHECK_EQ(2, epilogue_call_count);
18775 CHECK_EQ(2, prologue_call_count_second);
18776 CHECK_EQ(2, epilogue_call_count_second);
18777 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18778 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18779 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18780 CHECK_EQ(2, prologue_call_count);
18781 CHECK_EQ(2, epilogue_call_count);
18782 CHECK_EQ(2, prologue_call_count_second);
18783 CHECK_EQ(2, epilogue_call_count_second);
18787 TEST(GCCallbacks) {
18788 LocalContext context;
18789 v8::Isolate* isolate = context->GetIsolate();
18790 gc_callbacks_isolate = isolate;
18791 isolate->AddGCPrologueCallback(PrologueCallback);
18792 isolate->AddGCEpilogueCallback(EpilogueCallback);
18793 CHECK_EQ(0, prologue_call_count);
18794 CHECK_EQ(0, epilogue_call_count);
18795 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18796 CHECK_EQ(1, prologue_call_count);
18797 CHECK_EQ(1, epilogue_call_count);
18798 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18799 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18800 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18801 CHECK_EQ(2, prologue_call_count);
18802 CHECK_EQ(2, epilogue_call_count);
18803 CHECK_EQ(1, prologue_call_count_second);
18804 CHECK_EQ(1, epilogue_call_count_second);
18805 isolate->RemoveGCPrologueCallback(PrologueCallback);
18806 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18807 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18808 CHECK_EQ(2, prologue_call_count);
18809 CHECK_EQ(2, epilogue_call_count);
18810 CHECK_EQ(2, prologue_call_count_second);
18811 CHECK_EQ(2, epilogue_call_count_second);
18812 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18813 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18814 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18815 CHECK_EQ(2, prologue_call_count);
18816 CHECK_EQ(2, epilogue_call_count);
18817 CHECK_EQ(2, prologue_call_count_second);
18818 CHECK_EQ(2, epilogue_call_count_second);
18820 CHECK_EQ(0, prologue_call_count_alloc);
18821 CHECK_EQ(0, epilogue_call_count_alloc);
18822 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18823 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18824 CcTest::heap()->CollectAllGarbage(
18825 i::Heap::kAbortIncrementalMarkingMask);
18826 CHECK_EQ(1, prologue_call_count_alloc);
18827 CHECK_EQ(1, epilogue_call_count_alloc);
18828 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18829 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18833 THREADED_TEST(AddToJSFunctionResultCache) {
18834 i::FLAG_stress_compaction = false;
18835 i::FLAG_allow_natives_syntax = true;
18836 v8::HandleScope scope(CcTest::isolate());
18838 LocalContext context;
18844 " var r0 = %_GetFromCache(0, key0);"
18845 " var r1 = %_GetFromCache(0, key1);"
18846 " var r0_ = %_GetFromCache(0, key0);"
18848 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18849 " var r1_ = %_GetFromCache(0, key1);"
18851 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18852 " return 'PASSED';"
18854 CcTest::heap()->ClearJSFunctionResultCaches();
18855 ExpectString(code, "PASSED");
18859 THREADED_TEST(FillJSFunctionResultCache) {
18860 i::FLAG_allow_natives_syntax = true;
18861 LocalContext context;
18862 v8::HandleScope scope(context->GetIsolate());
18867 " var r = %_GetFromCache(0, k);"
18868 " for (var i = 0; i < 16; i++) {"
18869 " %_GetFromCache(0, 'a' + i);"
18871 " if (r === %_GetFromCache(0, k))"
18872 " return 'FAILED: k0CacheSize is too small';"
18873 " return 'PASSED';"
18875 CcTest::heap()->ClearJSFunctionResultCaches();
18876 ExpectString(code, "PASSED");
18880 THREADED_TEST(RoundRobinGetFromCache) {
18881 i::FLAG_allow_natives_syntax = true;
18882 LocalContext context;
18883 v8::HandleScope scope(context->GetIsolate());
18888 " for (var i = 0; i < 16; i++) keys.push(i);"
18889 " var values = [];"
18890 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18891 " for (var i = 0; i < 16; i++) {"
18892 " var v = %_GetFromCache(0, keys[i]);"
18893 " if (v.toString() !== values[i].toString())"
18894 " return 'Wrong value for ' + "
18895 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18897 " return 'PASSED';"
18899 CcTest::heap()->ClearJSFunctionResultCaches();
18900 ExpectString(code, "PASSED");
18904 THREADED_TEST(ReverseGetFromCache) {
18905 i::FLAG_allow_natives_syntax = true;
18906 LocalContext context;
18907 v8::HandleScope scope(context->GetIsolate());
18912 " for (var i = 0; i < 16; i++) keys.push(i);"
18913 " var values = [];"
18914 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18915 " for (var i = 15; i >= 16; i--) {"
18916 " var v = %_GetFromCache(0, keys[i]);"
18917 " if (v !== values[i])"
18918 " return 'Wrong value for ' + "
18919 " keys[i] + ': ' + v + ' vs. ' + values[i];"
18921 " return 'PASSED';"
18923 CcTest::heap()->ClearJSFunctionResultCaches();
18924 ExpectString(code, "PASSED");
18928 THREADED_TEST(TestEviction) {
18929 i::FLAG_allow_natives_syntax = true;
18930 LocalContext context;
18931 v8::HandleScope scope(context->GetIsolate());
18935 " for (var i = 0; i < 2*16; i++) {"
18936 " %_GetFromCache(0, 'a' + i);"
18938 " return 'PASSED';"
18940 CcTest::heap()->ClearJSFunctionResultCaches();
18941 ExpectString(code, "PASSED");
18945 THREADED_TEST(TwoByteStringInAsciiCons) {
18946 // See Chromium issue 47824.
18947 LocalContext context;
18948 v8::HandleScope scope(context->GetIsolate());
18950 const char* init_code =
18951 "var str1 = 'abelspendabel';"
18952 "var str2 = str1 + str1 + str1;"
18954 Local<Value> result = CompileRun(init_code);
18956 Local<Value> indexof = CompileRun("str2.indexOf('els')");
18957 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18959 CHECK(result->IsString());
18960 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18961 int length = string->length();
18962 CHECK(string->IsOneByteRepresentation());
18964 i::Handle<i::String> flat_string = i::String::Flatten(string);
18966 CHECK(string->IsOneByteRepresentation());
18967 CHECK(flat_string->IsOneByteRepresentation());
18969 // Create external resource.
18970 uint16_t* uc16_buffer = new uint16_t[length + 1];
18972 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18973 uc16_buffer[length] = 0;
18975 TestResource resource(uc16_buffer);
18977 flat_string->MakeExternal(&resource);
18979 CHECK(flat_string->IsTwoByteRepresentation());
18981 // If the cons string has been short-circuited, skip the following checks.
18982 if (!string.is_identical_to(flat_string)) {
18983 // At this point, we should have a Cons string which is flat and ASCII,
18984 // with a first half that is a two-byte string (although it only contains
18985 // ASCII characters). This is a valid sequence of steps, and it can happen
18987 CHECK(string->IsOneByteRepresentation());
18988 i::ConsString* cons = i::ConsString::cast(*string);
18989 CHECK_EQ(0, cons->second()->length());
18990 CHECK(cons->first()->IsTwoByteRepresentation());
18993 // Check that some string operations work.
18996 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18997 CHECK_EQ(6, reresult->Int32Value());
19000 reresult = CompileRun("str2.match(/abe./g).length;");
19001 CHECK_EQ(6, reresult->Int32Value());
19003 reresult = CompileRun("str2.search(/bel/g);");
19004 CHECK_EQ(1, reresult->Int32Value());
19006 reresult = CompileRun("str2.search(/be./g);");
19007 CHECK_EQ(1, reresult->Int32Value());
19009 ExpectTrue("/bel/g.test(str2);");
19011 ExpectTrue("/be./g.test(str2);");
19013 reresult = CompileRun("/bel/g.exec(str2);");
19014 CHECK(!reresult->IsNull());
19016 reresult = CompileRun("/be./g.exec(str2);");
19017 CHECK(!reresult->IsNull());
19019 ExpectString("str2.substring(2, 10);", "elspenda");
19021 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19023 ExpectString("str2.charAt(2);", "e");
19025 ExpectObject("str2.indexOf('els');", indexof);
19027 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19029 reresult = CompileRun("str2.charCodeAt(2);");
19030 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19034 TEST(ContainsOnlyOneByte) {
19035 v8::V8::Initialize();
19036 v8::Isolate* isolate = CcTest::isolate();
19037 v8::HandleScope scope(isolate);
19038 // Make a buffer long enough that it won't automatically be converted.
19039 const int length = 512;
19040 // Ensure word aligned assignment.
19041 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19042 i::SmartArrayPointer<uintptr_t>
19043 aligned_contents(new uintptr_t[aligned_length]);
19044 uint16_t* string_contents =
19045 reinterpret_cast<uint16_t*>(aligned_contents.get());
19046 // Set to contain only one byte.
19047 for (int i = 0; i < length-1; i++) {
19048 string_contents[i] = 0x41;
19050 string_contents[length-1] = 0;
19052 Handle<String> string =
19053 String::NewExternal(isolate,
19054 new TestResource(string_contents, NULL, false));
19055 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19056 // Counter example.
19057 string = String::NewFromTwoByte(isolate, string_contents);
19058 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19059 // Test left right and balanced cons strings.
19060 Handle<String> base = String::NewFromUtf8(isolate, "a");
19061 Handle<String> left = base;
19062 Handle<String> right = base;
19063 for (int i = 0; i < 1000; i++) {
19064 left = String::Concat(base, left);
19065 right = String::Concat(right, base);
19067 Handle<String> balanced = String::Concat(left, base);
19068 balanced = String::Concat(balanced, right);
19069 Handle<String> cons_strings[] = {left, balanced, right};
19070 Handle<String> two_byte =
19071 String::NewExternal(isolate,
19072 new TestResource(string_contents, NULL, false));
19073 USE(two_byte); USE(cons_strings);
19074 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19075 // Base assumptions.
19076 string = cons_strings[i];
19077 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19078 // Test left and right concatentation.
19079 string = String::Concat(two_byte, cons_strings[i]);
19080 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19081 string = String::Concat(cons_strings[i], two_byte);
19082 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19084 // Set bits in different positions
19085 // for strings of different lengths and alignments.
19086 for (int alignment = 0; alignment < 7; alignment++) {
19087 for (int size = 2; alignment + size < length; size *= 2) {
19088 int zero_offset = size + alignment;
19089 string_contents[zero_offset] = 0;
19090 for (int i = 0; i < size; i++) {
19091 int shift = 8 + (i % 7);
19092 string_contents[alignment + i] = 1 << shift;
19093 string = String::NewExternal(
19095 new TestResource(string_contents + alignment, NULL, false));
19096 CHECK_EQ(size, string->Length());
19097 CHECK(!string->ContainsOnlyOneByte());
19098 string_contents[alignment + i] = 0x41;
19100 string_contents[zero_offset] = 0x41;
19106 // Failed access check callback that performs a GC on each invocation.
19107 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19108 v8::AccessType type,
19109 Local<v8::Value> data) {
19110 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19114 TEST(GCInFailedAccessCheckCallback) {
19115 // Install a failed access check callback that performs a GC on each
19116 // invocation. Then force the callback to be called from va
19118 v8::V8::Initialize();
19119 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19121 v8::Isolate* isolate = CcTest::isolate();
19122 v8::HandleScope scope(isolate);
19124 // Create an ObjectTemplate for global objects and install access
19125 // check callbacks that will block access.
19126 v8::Handle<v8::ObjectTemplate> global_template =
19127 v8::ObjectTemplate::New(isolate);
19128 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19129 IndexedGetAccessBlocker,
19130 v8::Handle<v8::Value>(),
19133 // Create a context and set an x property on it's global object.
19134 LocalContext context0(NULL, global_template);
19135 context0->Global()->Set(v8_str("x"), v8_num(42));
19136 v8::Handle<v8::Object> global0 = context0->Global();
19138 // Create a context with a different security token so that the
19139 // failed access check callback will be called on each access.
19140 LocalContext context1(NULL, global_template);
19141 context1->Global()->Set(v8_str("other"), global0);
19143 // Get property with failed access check.
19144 ExpectUndefined("other.x");
19146 // Get element with failed access check.
19147 ExpectUndefined("other[0]");
19149 // Set property with failed access check.
19150 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19151 CHECK(result->IsObject());
19153 // Set element with failed access check.
19154 result = CompileRun("other[0] = new Object()");
19155 CHECK(result->IsObject());
19157 // Get property attribute with failed access check.
19158 ExpectFalse("\'x\' in other");
19160 // Get property attribute for element with failed access check.
19161 ExpectFalse("0 in other");
19163 // Delete property.
19164 ExpectFalse("delete other.x");
19167 CHECK_EQ(false, global0->Delete(0));
19171 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19173 // Define JavaScript accessor.
19174 ExpectUndefined("Object.prototype.__defineGetter__.call("
19175 " other, \'x\', function() { return 42; })");
19178 ExpectUndefined("Object.prototype.__lookupGetter__.call("
19182 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19184 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19185 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19186 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19188 // Reset the failed access check callback so it does not influence
19189 // the other tests.
19190 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19194 TEST(IsolateNewDispose) {
19195 v8::Isolate* current_isolate = CcTest::isolate();
19196 v8::Isolate* isolate = v8::Isolate::New();
19197 CHECK(isolate != NULL);
19198 CHECK(current_isolate != isolate);
19199 CHECK(current_isolate == CcTest::isolate());
19201 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19202 last_location = last_message = NULL;
19203 isolate->Dispose();
19204 CHECK_EQ(last_location, NULL);
19205 CHECK_EQ(last_message, NULL);
19209 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19210 v8::Isolate* isolate = v8::Isolate::New();
19212 v8::Isolate::Scope i_scope(isolate);
19213 v8::HandleScope scope(isolate);
19214 LocalContext context(isolate);
19215 // Run something in this isolate.
19216 ExpectTrue("true");
19217 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19218 last_location = last_message = NULL;
19219 // Still entered, should fail.
19220 isolate->Dispose();
19221 CHECK_NE(last_location, NULL);
19222 CHECK_NE(last_message, NULL);
19224 isolate->Dispose();
19228 TEST(RunTwoIsolatesOnSingleThread) {
19230 v8::Isolate* isolate1 = v8::Isolate::New();
19232 v8::Persistent<v8::Context> context1;
19234 v8::HandleScope scope(isolate1);
19235 context1.Reset(isolate1, Context::New(isolate1));
19239 v8::HandleScope scope(isolate1);
19240 v8::Local<v8::Context> context =
19241 v8::Local<v8::Context>::New(isolate1, context1);
19242 v8::Context::Scope context_scope(context);
19243 // Run something in new isolate.
19244 CompileRun("var foo = 'isolate 1';");
19245 ExpectString("function f() { return foo; }; f()", "isolate 1");
19249 v8::Isolate* isolate2 = v8::Isolate::New();
19250 v8::Persistent<v8::Context> context2;
19253 v8::Isolate::Scope iscope(isolate2);
19254 v8::HandleScope scope(isolate2);
19255 context2.Reset(isolate2, Context::New(isolate2));
19256 v8::Local<v8::Context> context =
19257 v8::Local<v8::Context>::New(isolate2, context2);
19258 v8::Context::Scope context_scope(context);
19260 // Run something in new isolate.
19261 CompileRun("var foo = 'isolate 2';");
19262 ExpectString("function f() { return foo; }; f()", "isolate 2");
19266 v8::HandleScope scope(isolate1);
19267 v8::Local<v8::Context> context =
19268 v8::Local<v8::Context>::New(isolate1, context1);
19269 v8::Context::Scope context_scope(context);
19270 // Now again in isolate 1
19271 ExpectString("function f() { return foo; }; f()", "isolate 1");
19276 // Run some stuff in default isolate.
19277 v8::Persistent<v8::Context> context_default;
19279 v8::Isolate* isolate = CcTest::isolate();
19280 v8::Isolate::Scope iscope(isolate);
19281 v8::HandleScope scope(isolate);
19282 context_default.Reset(isolate, Context::New(isolate));
19286 v8::HandleScope scope(CcTest::isolate());
19287 v8::Local<v8::Context> context =
19288 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19289 v8::Context::Scope context_scope(context);
19290 // Variables in other isolates should be not available, verify there
19291 // is an exception.
19292 ExpectTrue("function f() {"
19300 "var isDefaultIsolate = true;"
19307 v8::Isolate::Scope iscope(isolate2);
19308 v8::HandleScope scope(isolate2);
19309 v8::Local<v8::Context> context =
19310 v8::Local<v8::Context>::New(isolate2, context2);
19311 v8::Context::Scope context_scope(context);
19312 ExpectString("function f() { return foo; }; f()", "isolate 2");
19316 v8::HandleScope scope(v8::Isolate::GetCurrent());
19317 v8::Local<v8::Context> context =
19318 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19319 v8::Context::Scope context_scope(context);
19320 ExpectString("function f() { return foo; }; f()", "isolate 1");
19324 v8::Isolate::Scope iscope(isolate2);
19331 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19332 last_location = last_message = NULL;
19334 isolate1->Dispose();
19335 CHECK_EQ(last_location, NULL);
19336 CHECK_EQ(last_message, NULL);
19338 isolate2->Dispose();
19339 CHECK_EQ(last_location, NULL);
19340 CHECK_EQ(last_message, NULL);
19342 // Check that default isolate still runs.
19344 v8::HandleScope scope(CcTest::isolate());
19345 v8::Local<v8::Context> context =
19346 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19347 v8::Context::Scope context_scope(context);
19348 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19353 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19354 v8::Isolate::Scope isolate_scope(isolate);
19355 v8::HandleScope scope(isolate);
19356 LocalContext context(isolate);
19357 i::ScopedVector<char> code(1024);
19358 i::SNPrintF(code, "function fib(n) {"
19359 " if (n <= 2) return 1;"
19360 " return fib(n-1) + fib(n-2);"
19363 Local<Value> value = CompileRun(code.start());
19364 CHECK(value->IsNumber());
19365 return static_cast<int>(value->NumberValue());
19368 class IsolateThread : public v8::base::Thread {
19370 IsolateThread(v8::Isolate* isolate, int fib_limit)
19371 : Thread(Options("IsolateThread")),
19373 fib_limit_(fib_limit),
19377 result_ = CalcFibonacci(isolate_, fib_limit_);
19380 int result() { return result_; }
19383 v8::Isolate* isolate_;
19389 TEST(MultipleIsolatesOnIndividualThreads) {
19390 v8::Isolate* isolate1 = v8::Isolate::New();
19391 v8::Isolate* isolate2 = v8::Isolate::New();
19393 IsolateThread thread1(isolate1, 21);
19394 IsolateThread thread2(isolate2, 12);
19396 // Compute some fibonacci numbers on 3 threads in 3 isolates.
19400 int result1 = CalcFibonacci(CcTest::isolate(), 21);
19401 int result2 = CalcFibonacci(CcTest::isolate(), 12);
19406 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19407 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19408 CHECK_EQ(result1, 10946);
19409 CHECK_EQ(result2, 144);
19410 CHECK_EQ(result1, thread1.result());
19411 CHECK_EQ(result2, thread2.result());
19413 isolate1->Dispose();
19414 isolate2->Dispose();
19418 TEST(IsolateDifferentContexts) {
19419 v8::Isolate* isolate = v8::Isolate::New();
19420 Local<v8::Context> context;
19422 v8::Isolate::Scope isolate_scope(isolate);
19423 v8::HandleScope handle_scope(isolate);
19424 context = v8::Context::New(isolate);
19425 v8::Context::Scope context_scope(context);
19426 Local<Value> v = CompileRun("2");
19427 CHECK(v->IsNumber());
19428 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19431 v8::Isolate::Scope isolate_scope(isolate);
19432 v8::HandleScope handle_scope(isolate);
19433 context = v8::Context::New(isolate);
19434 v8::Context::Scope context_scope(context);
19435 Local<Value> v = CompileRun("22");
19436 CHECK(v->IsNumber());
19437 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19439 isolate->Dispose();
19442 class InitDefaultIsolateThread : public v8::base::Thread {
19445 SetResourceConstraints,
19447 SetCounterFunction,
19448 SetCreateHistogramFunction,
19449 SetAddHistogramSampleFunction
19452 explicit InitDefaultIsolateThread(TestCase testCase)
19453 : Thread(Options("InitDefaultIsolateThread")),
19454 testCase_(testCase),
19458 v8::Isolate* isolate = v8::Isolate::New();
19460 switch (testCase_) {
19461 case SetResourceConstraints: {
19462 v8::ResourceConstraints constraints;
19463 constraints.set_max_semi_space_size(1);
19464 constraints.set_max_old_space_size(4);
19465 v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19469 case SetFatalHandler:
19470 v8::V8::SetFatalErrorHandler(NULL);
19473 case SetCounterFunction:
19474 CcTest::isolate()->SetCounterFunction(NULL);
19477 case SetCreateHistogramFunction:
19478 CcTest::isolate()->SetCreateHistogramFunction(NULL);
19481 case SetAddHistogramSampleFunction:
19482 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19486 isolate->Dispose();
19490 bool result() { return result_; }
19493 TestCase testCase_;
19498 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19499 InitDefaultIsolateThread thread(testCase);
19502 CHECK_EQ(thread.result(), true);
19506 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19507 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19511 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19512 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19516 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19517 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19521 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19522 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19526 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19527 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19531 TEST(StringCheckMultipleContexts) {
19533 "(function() { return \"a\".charAt(0); })()";
19536 // Run the code twice in the first context to initialize the call IC.
19537 LocalContext context1;
19538 v8::HandleScope scope(context1->GetIsolate());
19539 ExpectString(code, "a");
19540 ExpectString(code, "a");
19544 // Change the String.prototype in the second context and check
19545 // that the right function gets called.
19546 LocalContext context2;
19547 v8::HandleScope scope(context2->GetIsolate());
19548 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19549 ExpectString(code, "not a");
19554 TEST(NumberCheckMultipleContexts) {
19556 "(function() { return (42).toString(); })()";
19559 // Run the code twice in the first context to initialize the call IC.
19560 LocalContext context1;
19561 v8::HandleScope scope(context1->GetIsolate());
19562 ExpectString(code, "42");
19563 ExpectString(code, "42");
19567 // Change the Number.prototype in the second context and check
19568 // that the right function gets called.
19569 LocalContext context2;
19570 v8::HandleScope scope(context2->GetIsolate());
19571 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19572 ExpectString(code, "not 42");
19577 TEST(BooleanCheckMultipleContexts) {
19579 "(function() { return true.toString(); })()";
19582 // Run the code twice in the first context to initialize the call IC.
19583 LocalContext context1;
19584 v8::HandleScope scope(context1->GetIsolate());
19585 ExpectString(code, "true");
19586 ExpectString(code, "true");
19590 // Change the Boolean.prototype in the second context and check
19591 // that the right function gets called.
19592 LocalContext context2;
19593 v8::HandleScope scope(context2->GetIsolate());
19594 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19595 ExpectString(code, "");
19600 TEST(DontDeleteCellLoadIC) {
19601 const char* function_code =
19602 "function readCell() { while (true) { return cell; } }";
19605 // Run the code twice in the first context to initialize the load
19606 // IC for a don't delete cell.
19607 LocalContext context1;
19608 v8::HandleScope scope(context1->GetIsolate());
19609 CompileRun("var cell = \"first\";");
19610 ExpectBoolean("delete cell", false);
19611 CompileRun(function_code);
19612 ExpectString("readCell()", "first");
19613 ExpectString("readCell()", "first");
19617 // Use a deletable cell in the second context.
19618 LocalContext context2;
19619 v8::HandleScope scope(context2->GetIsolate());
19620 CompileRun("cell = \"second\";");
19621 CompileRun(function_code);
19622 ExpectString("readCell()", "second");
19623 ExpectBoolean("delete cell", true);
19624 ExpectString("(function() {"
19626 " return readCell();"
19628 " return e.toString();"
19631 "ReferenceError: cell is not defined");
19632 CompileRun("cell = \"new_second\";");
19633 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19634 ExpectString("readCell()", "new_second");
19635 ExpectString("readCell()", "new_second");
19640 TEST(DontDeleteCellLoadICForceDelete) {
19641 const char* function_code =
19642 "function readCell() { while (true) { return cell; } }";
19644 // Run the code twice to initialize the load IC for a don't delete
19646 LocalContext context;
19647 v8::HandleScope scope(context->GetIsolate());
19648 CompileRun("var cell = \"value\";");
19649 ExpectBoolean("delete cell", false);
19650 CompileRun(function_code);
19651 ExpectString("readCell()", "value");
19652 ExpectString("readCell()", "value");
19654 // Delete the cell using the API and check the inlined code works
19656 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19657 ExpectString("(function() {"
19659 " return readCell();"
19661 " return e.toString();"
19664 "ReferenceError: cell is not defined");
19668 TEST(DontDeleteCellLoadICAPI) {
19669 const char* function_code =
19670 "function readCell() { while (true) { return cell; } }";
19672 // Run the code twice to initialize the load IC for a don't delete
19673 // cell created using the API.
19674 LocalContext context;
19675 v8::HandleScope scope(context->GetIsolate());
19676 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19677 ExpectBoolean("delete cell", false);
19678 CompileRun(function_code);
19679 ExpectString("readCell()", "value");
19680 ExpectString("readCell()", "value");
19682 // Delete the cell using the API and check the inlined code works
19684 CHECK(context->Global()->ForceDelete(v8_str("cell")));
19685 ExpectString("(function() {"
19687 " return readCell();"
19689 " return e.toString();"
19692 "ReferenceError: cell is not defined");
19696 class Visitor42 : public v8::PersistentHandleVisitor {
19698 explicit Visitor42(v8::Persistent<v8::Object>* object)
19699 : counter_(0), object_(object) { }
19701 virtual void VisitPersistentHandle(Persistent<Value>* value,
19702 uint16_t class_id) {
19703 if (class_id != 42) return;
19704 CHECK_EQ(42, value->WrapperClassId());
19705 v8::Isolate* isolate = CcTest::isolate();
19706 v8::HandleScope handle_scope(isolate);
19707 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19708 v8::Handle<v8::Value> object =
19709 v8::Local<v8::Object>::New(isolate, *object_);
19710 CHECK(handle->IsObject());
19711 CHECK_EQ(Handle<Object>::Cast(handle), object);
19716 v8::Persistent<v8::Object>* object_;
19720 TEST(PersistentHandleVisitor) {
19721 LocalContext context;
19722 v8::Isolate* isolate = context->GetIsolate();
19723 v8::HandleScope scope(isolate);
19724 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19725 CHECK_EQ(0, object.WrapperClassId());
19726 object.SetWrapperClassId(42);
19727 CHECK_EQ(42, object.WrapperClassId());
19729 Visitor42 visitor(&object);
19730 v8::V8::VisitHandlesWithClassIds(&visitor);
19731 CHECK_EQ(1, visitor.counter_);
19737 TEST(WrapperClassId) {
19738 LocalContext context;
19739 v8::Isolate* isolate = context->GetIsolate();
19740 v8::HandleScope scope(isolate);
19741 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19742 CHECK_EQ(0, object.WrapperClassId());
19743 object.SetWrapperClassId(65535);
19744 CHECK_EQ(65535, object.WrapperClassId());
19749 TEST(PersistentHandleInNewSpaceVisitor) {
19750 LocalContext context;
19751 v8::Isolate* isolate = context->GetIsolate();
19752 v8::HandleScope scope(isolate);
19753 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19754 CHECK_EQ(0, object1.WrapperClassId());
19755 object1.SetWrapperClassId(42);
19756 CHECK_EQ(42, object1.WrapperClassId());
19758 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19759 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19761 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19762 CHECK_EQ(0, object2.WrapperClassId());
19763 object2.SetWrapperClassId(42);
19764 CHECK_EQ(42, object2.WrapperClassId());
19766 Visitor42 visitor(&object2);
19767 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19768 CHECK_EQ(1, visitor.counter_);
19776 LocalContext context;
19777 v8::HandleScope scope(context->GetIsolate());
19779 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19780 CHECK(re->IsRegExp());
19781 CHECK(re->GetSource()->Equals(v8_str("foo")));
19782 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19784 re = v8::RegExp::New(v8_str("bar"),
19785 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19786 v8::RegExp::kGlobal));
19787 CHECK(re->IsRegExp());
19788 CHECK(re->GetSource()->Equals(v8_str("bar")));
19789 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19790 static_cast<int>(re->GetFlags()));
19792 re = v8::RegExp::New(v8_str("baz"),
19793 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19794 v8::RegExp::kMultiline));
19795 CHECK(re->IsRegExp());
19796 CHECK(re->GetSource()->Equals(v8_str("baz")));
19797 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19798 static_cast<int>(re->GetFlags()));
19800 re = CompileRun("/quux/").As<v8::RegExp>();
19801 CHECK(re->IsRegExp());
19802 CHECK(re->GetSource()->Equals(v8_str("quux")));
19803 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19805 re = CompileRun("/quux/gm").As<v8::RegExp>();
19806 CHECK(re->IsRegExp());
19807 CHECK(re->GetSource()->Equals(v8_str("quux")));
19808 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19809 static_cast<int>(re->GetFlags()));
19811 // Override the RegExp constructor and check the API constructor
19813 CompileRun("RegExp = function() {}");
19815 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19816 CHECK(re->IsRegExp());
19817 CHECK(re->GetSource()->Equals(v8_str("foobar")));
19818 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19820 re = v8::RegExp::New(v8_str("foobarbaz"),
19821 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19822 v8::RegExp::kMultiline));
19823 CHECK(re->IsRegExp());
19824 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19825 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19826 static_cast<int>(re->GetFlags()));
19828 context->Global()->Set(v8_str("re"), re);
19829 ExpectTrue("re.test('FoobarbaZ')");
19831 // RegExps are objects on which you can set properties.
19832 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19833 v8::Handle<v8::Value> value(CompileRun("re.property"));
19834 CHECK_EQ(32, value->Int32Value());
19836 v8::TryCatch try_catch;
19837 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19838 CHECK(re.IsEmpty());
19839 CHECK(try_catch.HasCaught());
19840 context->Global()->Set(v8_str("ex"), try_catch.Exception());
19841 ExpectTrue("ex instanceof SyntaxError");
19845 THREADED_TEST(Equals) {
19846 LocalContext localContext;
19847 v8::HandleScope handleScope(localContext->GetIsolate());
19849 v8::Handle<v8::Object> globalProxy = localContext->Global();
19850 v8::Handle<Value> global = globalProxy->GetPrototype();
19852 CHECK(global->StrictEquals(global));
19853 CHECK(!global->StrictEquals(globalProxy));
19854 CHECK(!globalProxy->StrictEquals(global));
19855 CHECK(globalProxy->StrictEquals(globalProxy));
19857 CHECK(global->Equals(global));
19858 CHECK(!global->Equals(globalProxy));
19859 CHECK(!globalProxy->Equals(global));
19860 CHECK(globalProxy->Equals(globalProxy));
19864 static void Getter(v8::Local<v8::String> property,
19865 const v8::PropertyCallbackInfo<v8::Value>& info ) {
19866 info.GetReturnValue().Set(v8_str("42!"));
19870 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19871 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19872 result->Set(0, v8_str("universalAnswer"));
19873 info.GetReturnValue().Set(result);
19877 TEST(NamedEnumeratorAndForIn) {
19878 LocalContext context;
19879 v8::Isolate* isolate = context->GetIsolate();
19880 v8::HandleScope handle_scope(isolate);
19881 v8::Context::Scope context_scope(context.local());
19883 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19884 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19885 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19886 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19887 "var result = []; for (var k in o) result.push(k); result"));
19888 CHECK_EQ(1, result->Length());
19889 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19893 TEST(DefinePropertyPostDetach) {
19894 LocalContext context;
19895 v8::HandleScope scope(context->GetIsolate());
19896 v8::Handle<v8::Object> proxy = context->Global();
19897 v8::Handle<v8::Function> define_property =
19898 CompileRun("(function() {"
19899 " Object.defineProperty("
19902 " { configurable: true, enumerable: true, value: 3 });"
19903 "})").As<Function>();
19904 context->DetachGlobal();
19905 define_property->Call(proxy, 0, NULL);
19909 static void InstallContextId(v8::Handle<Context> context, int id) {
19910 Context::Scope scope(context);
19911 CompileRun("Object.prototype").As<Object>()->
19912 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19916 static void CheckContextId(v8::Handle<Object> object, int expected) {
19917 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19921 THREADED_TEST(CreationContext) {
19922 v8::Isolate* isolate = CcTest::isolate();
19923 HandleScope handle_scope(isolate);
19924 Handle<Context> context1 = Context::New(isolate);
19925 InstallContextId(context1, 1);
19926 Handle<Context> context2 = Context::New(isolate);
19927 InstallContextId(context2, 2);
19928 Handle<Context> context3 = Context::New(isolate);
19929 InstallContextId(context3, 3);
19931 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19933 Local<Object> object1;
19934 Local<Function> func1;
19936 Context::Scope scope(context1);
19937 object1 = Object::New(isolate);
19938 func1 = tmpl->GetFunction();
19941 Local<Object> object2;
19942 Local<Function> func2;
19944 Context::Scope scope(context2);
19945 object2 = Object::New(isolate);
19946 func2 = tmpl->GetFunction();
19949 Local<Object> instance1;
19950 Local<Object> instance2;
19953 Context::Scope scope(context3);
19954 instance1 = func1->NewInstance();
19955 instance2 = func2->NewInstance();
19958 CHECK(object1->CreationContext() == context1);
19959 CheckContextId(object1, 1);
19960 CHECK(func1->CreationContext() == context1);
19961 CheckContextId(func1, 1);
19962 CHECK(instance1->CreationContext() == context1);
19963 CheckContextId(instance1, 1);
19964 CHECK(object2->CreationContext() == context2);
19965 CheckContextId(object2, 2);
19966 CHECK(func2->CreationContext() == context2);
19967 CheckContextId(func2, 2);
19968 CHECK(instance2->CreationContext() == context2);
19969 CheckContextId(instance2, 2);
19972 Context::Scope scope(context1);
19973 CHECK(object1->CreationContext() == context1);
19974 CheckContextId(object1, 1);
19975 CHECK(func1->CreationContext() == context1);
19976 CheckContextId(func1, 1);
19977 CHECK(instance1->CreationContext() == context1);
19978 CheckContextId(instance1, 1);
19979 CHECK(object2->CreationContext() == context2);
19980 CheckContextId(object2, 2);
19981 CHECK(func2->CreationContext() == context2);
19982 CheckContextId(func2, 2);
19983 CHECK(instance2->CreationContext() == context2);
19984 CheckContextId(instance2, 2);
19988 Context::Scope scope(context2);
19989 CHECK(object1->CreationContext() == context1);
19990 CheckContextId(object1, 1);
19991 CHECK(func1->CreationContext() == context1);
19992 CheckContextId(func1, 1);
19993 CHECK(instance1->CreationContext() == context1);
19994 CheckContextId(instance1, 1);
19995 CHECK(object2->CreationContext() == context2);
19996 CheckContextId(object2, 2);
19997 CHECK(func2->CreationContext() == context2);
19998 CheckContextId(func2, 2);
19999 CHECK(instance2->CreationContext() == context2);
20000 CheckContextId(instance2, 2);
20005 THREADED_TEST(CreationContextOfJsFunction) {
20006 HandleScope handle_scope(CcTest::isolate());
20007 Handle<Context> context = Context::New(CcTest::isolate());
20008 InstallContextId(context, 1);
20010 Local<Object> function;
20012 Context::Scope scope(context);
20013 function = CompileRun("function foo() {}; foo").As<Object>();
20016 CHECK(function->CreationContext() == context);
20017 CheckContextId(function, 1);
20021 void HasOwnPropertyIndexedPropertyGetter(
20023 const v8::PropertyCallbackInfo<v8::Value>& info) {
20024 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20028 void HasOwnPropertyNamedPropertyGetter(
20029 Local<String> property,
20030 const v8::PropertyCallbackInfo<v8::Value>& info) {
20031 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20035 void HasOwnPropertyIndexedPropertyQuery(
20036 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20037 if (index == 42) info.GetReturnValue().Set(1);
20041 void HasOwnPropertyNamedPropertyQuery(
20042 Local<String> property,
20043 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20044 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20048 void HasOwnPropertyNamedPropertyQuery2(
20049 Local<String> property,
20050 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20051 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20055 void HasOwnPropertyAccessorGetter(
20056 Local<String> property,
20057 const v8::PropertyCallbackInfo<v8::Value>& info) {
20058 info.GetReturnValue().Set(v8_str("yes"));
20062 TEST(HasOwnProperty) {
20064 v8::Isolate* isolate = env->GetIsolate();
20065 v8::HandleScope scope(isolate);
20066 { // Check normal properties and defined getters.
20067 Handle<Value> value = CompileRun(
20070 " this.__defineGetter__('baz', function() { return 1; });"
20072 "function Bar() { "
20074 " this.__defineGetter__('bla', function() { return 2; });"
20076 "Bar.prototype = new Foo();"
20078 CHECK(value->IsObject());
20079 Handle<Object> object = value->ToObject();
20080 CHECK(object->Has(v8_str("foo")));
20081 CHECK(!object->HasOwnProperty(v8_str("foo")));
20082 CHECK(object->HasOwnProperty(v8_str("bar")));
20083 CHECK(object->Has(v8_str("baz")));
20084 CHECK(!object->HasOwnProperty(v8_str("baz")));
20085 CHECK(object->HasOwnProperty(v8_str("bla")));
20087 { // Check named getter interceptors.
20088 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20089 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20090 Handle<Object> instance = templ->NewInstance();
20091 CHECK(!instance->HasOwnProperty(v8_str("42")));
20092 CHECK(instance->HasOwnProperty(v8_str("foo")));
20093 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20095 { // Check indexed getter interceptors.
20096 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20097 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20098 Handle<Object> instance = templ->NewInstance();
20099 CHECK(instance->HasOwnProperty(v8_str("42")));
20100 CHECK(!instance->HasOwnProperty(v8_str("43")));
20101 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20103 { // Check named query interceptors.
20104 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20105 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20106 Handle<Object> instance = templ->NewInstance();
20107 CHECK(instance->HasOwnProperty(v8_str("foo")));
20108 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20110 { // Check indexed query interceptors.
20111 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20112 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20113 Handle<Object> instance = templ->NewInstance();
20114 CHECK(instance->HasOwnProperty(v8_str("42")));
20115 CHECK(!instance->HasOwnProperty(v8_str("41")));
20117 { // Check callbacks.
20118 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20119 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20120 Handle<Object> instance = templ->NewInstance();
20121 CHECK(instance->HasOwnProperty(v8_str("foo")));
20122 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20124 { // Check that query wins on disagreement.
20125 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20126 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20128 HasOwnPropertyNamedPropertyQuery2);
20129 Handle<Object> instance = templ->NewInstance();
20130 CHECK(!instance->HasOwnProperty(v8_str("foo")));
20131 CHECK(instance->HasOwnProperty(v8_str("bar")));
20136 TEST(IndexedInterceptorWithStringProto) {
20137 v8::Isolate* isolate = CcTest::isolate();
20138 v8::HandleScope scope(isolate);
20139 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20140 templ->SetIndexedPropertyHandler(NULL,
20142 HasOwnPropertyIndexedPropertyQuery);
20143 LocalContext context;
20144 context->Global()->Set(v8_str("obj"), templ->NewInstance());
20145 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20146 // These should be intercepted.
20147 CHECK(CompileRun("42 in obj")->BooleanValue());
20148 CHECK(CompileRun("'42' in obj")->BooleanValue());
20149 // These should fall through to the String prototype.
20150 CHECK(CompileRun("0 in obj")->BooleanValue());
20151 CHECK(CompileRun("'0' in obj")->BooleanValue());
20152 // And these should both fail.
20153 CHECK(!CompileRun("32 in obj")->BooleanValue());
20154 CHECK(!CompileRun("'32' in obj")->BooleanValue());
20158 void CheckCodeGenerationAllowed() {
20159 Handle<Value> result = CompileRun("eval('42')");
20160 CHECK_EQ(42, result->Int32Value());
20161 result = CompileRun("(function(e) { return e('42'); })(eval)");
20162 CHECK_EQ(42, result->Int32Value());
20163 result = CompileRun("var f = new Function('return 42'); f()");
20164 CHECK_EQ(42, result->Int32Value());
20168 void CheckCodeGenerationDisallowed() {
20169 TryCatch try_catch;
20171 Handle<Value> result = CompileRun("eval('42')");
20172 CHECK(result.IsEmpty());
20173 CHECK(try_catch.HasCaught());
20176 result = CompileRun("(function(e) { return e('42'); })(eval)");
20177 CHECK(result.IsEmpty());
20178 CHECK(try_catch.HasCaught());
20181 result = CompileRun("var f = new Function('return 42'); f()");
20182 CHECK(result.IsEmpty());
20183 CHECK(try_catch.HasCaught());
20187 bool CodeGenerationAllowed(Local<Context> context) {
20188 ApiTestFuzzer::Fuzz();
20193 bool CodeGenerationDisallowed(Local<Context> context) {
20194 ApiTestFuzzer::Fuzz();
20199 THREADED_TEST(AllowCodeGenFromStrings) {
20200 LocalContext context;
20201 v8::HandleScope scope(context->GetIsolate());
20203 // eval and the Function constructor allowed by default.
20204 CHECK(context->IsCodeGenerationFromStringsAllowed());
20205 CheckCodeGenerationAllowed();
20207 // Disallow eval and the Function constructor.
20208 context->AllowCodeGenerationFromStrings(false);
20209 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20210 CheckCodeGenerationDisallowed();
20213 context->AllowCodeGenerationFromStrings(true);
20214 CheckCodeGenerationAllowed();
20216 // Disallow but setting a global callback that will allow the calls.
20217 context->AllowCodeGenerationFromStrings(false);
20218 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20219 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20220 CheckCodeGenerationAllowed();
20222 // Set a callback that disallows the code generation.
20223 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20224 CHECK(!context->IsCodeGenerationFromStringsAllowed());
20225 CheckCodeGenerationDisallowed();
20229 TEST(SetErrorMessageForCodeGenFromStrings) {
20230 LocalContext context;
20231 v8::HandleScope scope(context->GetIsolate());
20232 TryCatch try_catch;
20234 Handle<String> message = v8_str("Message") ;
20235 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20236 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20237 context->AllowCodeGenerationFromStrings(false);
20238 context->SetErrorMessageForCodeGenerationFromStrings(message);
20239 Handle<Value> result = CompileRun("eval('42')");
20240 CHECK(result.IsEmpty());
20241 CHECK(try_catch.HasCaught());
20242 Handle<String> actual_message = try_catch.Message()->Get();
20243 CHECK(expected_message->Equals(actual_message));
20247 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20251 THREADED_TEST(CallAPIFunctionOnNonObject) {
20252 LocalContext context;
20253 v8::Isolate* isolate = context->GetIsolate();
20254 v8::HandleScope scope(isolate);
20255 Handle<FunctionTemplate> templ =
20256 v8::FunctionTemplate::New(isolate, NonObjectThis);
20257 Handle<Function> function = templ->GetFunction();
20258 context->Global()->Set(v8_str("f"), function);
20259 TryCatch try_catch;
20260 CompileRun("f.call(2)");
20264 // Regression test for issue 1470.
20265 THREADED_TEST(ReadOnlyIndexedProperties) {
20266 v8::Isolate* isolate = CcTest::isolate();
20267 v8::HandleScope scope(isolate);
20268 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20270 LocalContext context;
20271 Local<v8::Object> obj = templ->NewInstance();
20272 context->Global()->Set(v8_str("obj"), obj);
20273 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20274 obj->Set(v8_str("1"), v8_str("foobar"));
20275 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20276 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20277 obj->Set(v8_num(2), v8_str("foobar"));
20278 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20280 // Test non-smi case.
20281 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20282 obj->Set(v8_str("2000000000"), v8_str("foobar"));
20283 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20287 THREADED_TEST(Regress1516) {
20288 LocalContext context;
20289 v8::HandleScope scope(context->GetIsolate());
20291 { v8::HandleScope temp_scope(context->GetIsolate());
20292 CompileRun("({'a': 0})");
20296 { i::MapCache* map_cache =
20297 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20298 elements = map_cache->NumberOfElements();
20299 CHECK_LE(1, elements);
20302 CcTest::heap()->CollectAllGarbage(
20303 i::Heap::kAbortIncrementalMarkingMask);
20304 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20305 if (raw_map_cache != CcTest::heap()->undefined_value()) {
20306 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20307 CHECK_GT(elements, map_cache->NumberOfElements());
20313 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20315 v8::AccessType type,
20316 Local<Value> data) {
20317 // Only block read access to __proto__.
20318 if (type == v8::ACCESS_GET &&
20319 name->IsString() &&
20320 name->ToString()->Length() == 9 &&
20321 name->ToString()->Utf8Length() == 9) {
20323 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20324 return strncmp(buffer, "__proto__", 9) != 0;
20331 THREADED_TEST(Regress93759) {
20332 v8::Isolate* isolate = CcTest::isolate();
20333 HandleScope scope(isolate);
20335 // Template for object with security check.
20336 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20337 // We don't do indexing, so any callback can be used for that.
20338 no_proto_template->SetAccessCheckCallbacks(
20339 BlockProtoNamedSecurityTestCallback,
20340 IndexedSecurityTestCallback);
20342 // Templates for objects with hidden prototypes and possibly security check.
20343 Local<FunctionTemplate> hidden_proto_template =
20344 v8::FunctionTemplate::New(isolate);
20345 hidden_proto_template->SetHiddenPrototype(true);
20347 Local<FunctionTemplate> protected_hidden_proto_template =
20348 v8::FunctionTemplate::New(isolate);
20349 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20350 BlockProtoNamedSecurityTestCallback,
20351 IndexedSecurityTestCallback);
20352 protected_hidden_proto_template->SetHiddenPrototype(true);
20354 // Context for "foreign" objects used in test.
20355 Local<Context> context = v8::Context::New(isolate);
20358 // Plain object, no security check.
20359 Local<Object> simple_object = Object::New(isolate);
20361 // Object with explicit security check.
20362 Local<Object> protected_object =
20363 no_proto_template->NewInstance();
20365 // JSGlobalProxy object, always have security check.
20366 Local<Object> proxy_object =
20369 // Global object, the prototype of proxy_object. No security checks.
20370 Local<Object> global_object =
20371 proxy_object->GetPrototype()->ToObject();
20373 // Hidden prototype without security check.
20374 Local<Object> hidden_prototype =
20375 hidden_proto_template->GetFunction()->NewInstance();
20376 Local<Object> object_with_hidden =
20377 Object::New(isolate);
20378 object_with_hidden->SetPrototype(hidden_prototype);
20380 // Hidden prototype with security check on the hidden prototype.
20381 Local<Object> protected_hidden_prototype =
20382 protected_hidden_proto_template->GetFunction()->NewInstance();
20383 Local<Object> object_with_protected_hidden =
20384 Object::New(isolate);
20385 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20389 // Template for object for second context. Values to test are put on it as
20391 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20392 global_template->Set(v8_str("simple"), simple_object);
20393 global_template->Set(v8_str("protected"), protected_object);
20394 global_template->Set(v8_str("global"), global_object);
20395 global_template->Set(v8_str("proxy"), proxy_object);
20396 global_template->Set(v8_str("hidden"), object_with_hidden);
20397 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20399 LocalContext context2(NULL, global_template);
20401 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20402 CHECK(result1->Equals(simple_object->GetPrototype()));
20404 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20405 CHECK(result2.IsEmpty());
20407 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20408 CHECK(result3->Equals(global_object->GetPrototype()));
20410 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20411 CHECK(result4.IsEmpty());
20413 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20414 CHECK(result5->Equals(
20415 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20417 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20418 CHECK(result6.IsEmpty());
20422 THREADED_TEST(Regress125988) {
20423 v8::HandleScope scope(CcTest::isolate());
20424 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20425 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20427 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20428 CompileRun("var a = new Object();"
20429 "var b = new Intercept();"
20430 "var c = new Object();"
20434 "for (var i = 0; i < 3; i++) c.x;");
20435 ExpectBoolean("c.hasOwnProperty('x')", false);
20436 ExpectInt32("c.x", 23);
20437 CompileRun("a.y = 42;"
20438 "for (var i = 0; i < 3; i++) c.x;");
20439 ExpectBoolean("c.hasOwnProperty('x')", false);
20440 ExpectInt32("c.x", 23);
20441 ExpectBoolean("c.hasOwnProperty('y')", false);
20442 ExpectInt32("c.y", 42);
20446 static void TestReceiver(Local<Value> expected_result,
20447 Local<Value> expected_receiver,
20448 const char* code) {
20449 Local<Value> result = CompileRun(code);
20450 CHECK(result->IsObject());
20451 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20452 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20456 THREADED_TEST(ForeignFunctionReceiver) {
20457 v8::Isolate* isolate = CcTest::isolate();
20458 HandleScope scope(isolate);
20460 // Create two contexts with different "id" properties ('i' and 'o').
20461 // Call a function both from its own context and from a the foreign
20462 // context, and see what "this" is bound to (returning both "this"
20463 // and "this.id" for comparison).
20465 Local<Context> foreign_context = v8::Context::New(isolate);
20466 foreign_context->Enter();
20467 Local<Value> foreign_function =
20468 CompileRun("function func() { return { 0: this.id, "
20470 " toString: function() { "
20477 CHECK(foreign_function->IsFunction());
20478 foreign_context->Exit();
20480 LocalContext context;
20482 Local<String> password = v8_str("Password");
20483 // Don't get hit by security checks when accessing foreign_context's
20484 // global receiver (aka. global proxy).
20485 context->SetSecurityToken(password);
20486 foreign_context->SetSecurityToken(password);
20488 Local<String> i = v8_str("i");
20489 Local<String> o = v8_str("o");
20490 Local<String> id = v8_str("id");
20492 CompileRun("function ownfunc() { return { 0: this.id, "
20494 " toString: function() { "
20501 context->Global()->Set(v8_str("func"), foreign_function);
20503 // Sanity check the contexts.
20504 CHECK(i->Equals(foreign_context->Global()->Get(id)));
20505 CHECK(o->Equals(context->Global()->Get(id)));
20507 // Checking local function's receiver.
20508 // Calling function using its call/apply methods.
20509 TestReceiver(o, context->Global(), "ownfunc.call()");
20510 TestReceiver(o, context->Global(), "ownfunc.apply()");
20511 // Making calls through built-in functions.
20512 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20513 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20514 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20515 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20516 // Calling with environment record as base.
20517 TestReceiver(o, context->Global(), "ownfunc()");
20518 // Calling with no base.
20519 TestReceiver(o, context->Global(), "(1,ownfunc)()");
20521 // Checking foreign function return value.
20522 // Calling function using its call/apply methods.
20523 TestReceiver(i, foreign_context->Global(), "func.call()");
20524 TestReceiver(i, foreign_context->Global(), "func.apply()");
20525 // Calling function using another context's call/apply methods.
20526 TestReceiver(i, foreign_context->Global(),
20527 "Function.prototype.call.call(func)");
20528 TestReceiver(i, foreign_context->Global(),
20529 "Function.prototype.call.apply(func)");
20530 TestReceiver(i, foreign_context->Global(),
20531 "Function.prototype.apply.call(func)");
20532 TestReceiver(i, foreign_context->Global(),
20533 "Function.prototype.apply.apply(func)");
20534 // Making calls through built-in functions.
20535 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20536 // ToString(func()) is func()[0], i.e., the returned this.id.
20537 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20538 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20539 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20541 // Calling with environment record as base.
20542 TestReceiver(i, foreign_context->Global(), "func()");
20543 // Calling with no base.
20544 TestReceiver(i, foreign_context->Global(), "(1,func)()");
20548 uint8_t callback_fired = 0;
20551 void CallCompletedCallback1() {
20552 v8::base::OS::Print("Firing callback 1.\n");
20553 callback_fired ^= 1; // Toggle first bit.
20557 void CallCompletedCallback2() {
20558 v8::base::OS::Print("Firing callback 2.\n");
20559 callback_fired ^= 2; // Toggle second bit.
20563 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20564 int32_t level = args[0]->Int32Value();
20567 v8::base::OS::Print("Entering recursion level %d.\n", level);
20569 i::Vector<char> script_vector(script, sizeof(script));
20570 i::SNPrintF(script_vector, "recursion(%d)", level);
20571 CompileRun(script_vector.start());
20572 v8::base::OS::Print("Leaving recursion level %d.\n", level);
20573 CHECK_EQ(0, callback_fired);
20575 v8::base::OS::Print("Recursion ends.\n");
20576 CHECK_EQ(0, callback_fired);
20581 TEST(CallCompletedCallback) {
20583 v8::HandleScope scope(env->GetIsolate());
20584 v8::Handle<v8::FunctionTemplate> recursive_runtime =
20585 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20586 env->Global()->Set(v8_str("recursion"),
20587 recursive_runtime->GetFunction());
20588 // Adding the same callback a second time has no effect.
20589 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20590 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20591 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20592 v8::base::OS::Print("--- Script (1) ---\n");
20593 Local<Script> script = v8::Script::Compile(
20594 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20596 CHECK_EQ(3, callback_fired);
20598 v8::base::OS::Print("\n--- Script (2) ---\n");
20599 callback_fired = 0;
20600 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20602 CHECK_EQ(2, callback_fired);
20604 v8::base::OS::Print("\n--- Function ---\n");
20605 callback_fired = 0;
20606 Local<Function> recursive_function =
20607 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20608 v8::Handle<Value> args[] = { v8_num(0) };
20609 recursive_function->Call(env->Global(), 1, args);
20610 CHECK_EQ(2, callback_fired);
20614 void CallCompletedCallbackNoException() {
20615 v8::HandleScope scope(CcTest::isolate());
20616 CompileRun("1+1;");
20620 void CallCompletedCallbackException() {
20621 v8::HandleScope scope(CcTest::isolate());
20622 CompileRun("throw 'second exception';");
20626 TEST(CallCompletedCallbackOneException) {
20628 v8::HandleScope scope(env->GetIsolate());
20629 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20630 CompileRun("throw 'exception';");
20634 TEST(CallCompletedCallbackTwoExceptions) {
20636 v8::HandleScope scope(env->GetIsolate());
20637 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20638 CompileRun("throw 'first exception';");
20642 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20643 v8::HandleScope scope(info.GetIsolate());
20644 CompileRun("ext1Calls++;");
20648 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20649 v8::HandleScope scope(info.GetIsolate());
20650 CompileRun("ext2Calls++;");
20654 void* g_passed_to_three = NULL;
20657 static void MicrotaskThree(void* data) {
20658 g_passed_to_three = data;
20662 TEST(EnqueueMicrotask) {
20664 v8::HandleScope scope(env->GetIsolate());
20666 "var ext1Calls = 0;"
20667 "var ext2Calls = 0;");
20668 CompileRun("1+1;");
20669 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20670 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20672 env->GetIsolate()->EnqueueMicrotask(
20673 Function::New(env->GetIsolate(), MicrotaskOne));
20674 CompileRun("1+1;");
20675 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20676 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20678 env->GetIsolate()->EnqueueMicrotask(
20679 Function::New(env->GetIsolate(), MicrotaskOne));
20680 env->GetIsolate()->EnqueueMicrotask(
20681 Function::New(env->GetIsolate(), MicrotaskTwo));
20682 CompileRun("1+1;");
20683 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20684 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20686 env->GetIsolate()->EnqueueMicrotask(
20687 Function::New(env->GetIsolate(), MicrotaskTwo));
20688 CompileRun("1+1;");
20689 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20690 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20692 CompileRun("1+1;");
20693 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20694 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20696 g_passed_to_three = NULL;
20697 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20698 CompileRun("1+1;");
20699 CHECK_EQ(NULL, g_passed_to_three);
20700 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20701 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20704 env->GetIsolate()->EnqueueMicrotask(
20705 Function::New(env->GetIsolate(), MicrotaskOne));
20706 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20707 env->GetIsolate()->EnqueueMicrotask(
20708 Function::New(env->GetIsolate(), MicrotaskTwo));
20709 CompileRun("1+1;");
20710 CHECK_EQ(&dummy, g_passed_to_three);
20711 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20712 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20713 g_passed_to_three = NULL;
20717 static void MicrotaskExceptionOne(
20718 const v8::FunctionCallbackInfo<Value>& info) {
20719 v8::HandleScope scope(info.GetIsolate());
20720 CompileRun("exception1Calls++;");
20721 info.GetIsolate()->ThrowException(
20722 v8::Exception::Error(v8_str("first")));
20726 static void MicrotaskExceptionTwo(
20727 const v8::FunctionCallbackInfo<Value>& info) {
20728 v8::HandleScope scope(info.GetIsolate());
20729 CompileRun("exception2Calls++;");
20730 info.GetIsolate()->ThrowException(
20731 v8::Exception::Error(v8_str("second")));
20735 TEST(RunMicrotasksIgnoresThrownExceptions) {
20737 v8::Isolate* isolate = env->GetIsolate();
20738 v8::HandleScope scope(isolate);
20740 "var exception1Calls = 0;"
20741 "var exception2Calls = 0;");
20742 isolate->EnqueueMicrotask(
20743 Function::New(isolate, MicrotaskExceptionOne));
20744 isolate->EnqueueMicrotask(
20745 Function::New(isolate, MicrotaskExceptionTwo));
20746 TryCatch try_catch;
20747 CompileRun("1+1;");
20748 CHECK(!try_catch.HasCaught());
20749 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20750 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20754 TEST(SetAutorunMicrotasks) {
20756 v8::HandleScope scope(env->GetIsolate());
20758 "var ext1Calls = 0;"
20759 "var ext2Calls = 0;");
20760 CompileRun("1+1;");
20761 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20762 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20764 env->GetIsolate()->EnqueueMicrotask(
20765 Function::New(env->GetIsolate(), MicrotaskOne));
20766 CompileRun("1+1;");
20767 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20768 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20770 env->GetIsolate()->SetAutorunMicrotasks(false);
20771 env->GetIsolate()->EnqueueMicrotask(
20772 Function::New(env->GetIsolate(), MicrotaskOne));
20773 env->GetIsolate()->EnqueueMicrotask(
20774 Function::New(env->GetIsolate(), MicrotaskTwo));
20775 CompileRun("1+1;");
20776 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20777 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20779 env->GetIsolate()->RunMicrotasks();
20780 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20781 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20783 env->GetIsolate()->EnqueueMicrotask(
20784 Function::New(env->GetIsolate(), MicrotaskTwo));
20785 CompileRun("1+1;");
20786 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20787 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20789 env->GetIsolate()->RunMicrotasks();
20790 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20791 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20793 env->GetIsolate()->SetAutorunMicrotasks(true);
20794 env->GetIsolate()->EnqueueMicrotask(
20795 Function::New(env->GetIsolate(), MicrotaskTwo));
20796 CompileRun("1+1;");
20797 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20800 env->GetIsolate()->EnqueueMicrotask(
20801 Function::New(env->GetIsolate(), MicrotaskTwo));
20803 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20804 CompileRun("1+1;");
20805 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20806 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20809 CompileRun("1+1;");
20810 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20811 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20815 TEST(RunMicrotasksWithoutEnteringContext) {
20816 v8::Isolate* isolate = CcTest::isolate();
20817 HandleScope handle_scope(isolate);
20818 isolate->SetAutorunMicrotasks(false);
20819 Handle<Context> context = Context::New(isolate);
20821 Context::Scope context_scope(context);
20822 CompileRun("var ext1Calls = 0;");
20823 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20825 isolate->RunMicrotasks();
20827 Context::Scope context_scope(context);
20828 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20830 isolate->SetAutorunMicrotasks(true);
20834 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
20835 v8::DebugEvent event = event_details.GetEvent();
20836 if (event != v8::Break) return;
20837 Handle<Object> exec_state = event_details.GetExecutionState();
20838 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
20839 CompileRun("function f(id) { new FrameDetails(id, 0); }");
20840 Handle<Function> fun = Handle<Function>::Cast(
20841 CcTest::global()->Get(v8_str("f"))->ToObject());
20842 fun->Call(CcTest::global(), 1, &break_id);
20846 TEST(Regress385349) {
20847 i::FLAG_allow_natives_syntax = true;
20848 v8::Isolate* isolate = CcTest::isolate();
20849 HandleScope handle_scope(isolate);
20850 isolate->SetAutorunMicrotasks(false);
20851 Handle<Context> context = Context::New(isolate);
20852 v8::Debug::SetDebugEventListener(DebugEventInObserver);
20854 Context::Scope context_scope(context);
20855 CompileRun("var obj = {};"
20856 "Object.observe(obj, function(changes) { debugger; });"
20859 isolate->RunMicrotasks();
20860 isolate->SetAutorunMicrotasks(true);
20861 v8::Debug::SetDebugEventListener(NULL);
20866 static int probes_counter = 0;
20867 static int misses_counter = 0;
20868 static int updates_counter = 0;
20871 static int* LookupCounter(const char* name) {
20872 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20873 return &probes_counter;
20874 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20875 return &misses_counter;
20876 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20877 return &updates_counter;
20883 static const char* kMegamorphicTestProgram =
20884 "function ClassA() { };"
20885 "function ClassB() { };"
20886 "ClassA.prototype.foo = function() { };"
20887 "ClassB.prototype.foo = function() { };"
20888 "function fooify(obj) { obj.foo(); };"
20889 "var a = new ClassA();"
20890 "var b = new ClassB();"
20891 "for (var i = 0; i < 10000; i++) {"
20898 static void StubCacheHelper(bool primary) {
20900 i::FLAG_native_code_counters = true;
20902 i::FLAG_test_primary_stub_cache = true;
20904 i::FLAG_test_secondary_stub_cache = true;
20906 i::FLAG_crankshaft = false;
20908 env->GetIsolate()->SetCounterFunction(LookupCounter);
20909 v8::HandleScope scope(env->GetIsolate());
20910 int initial_probes = probes_counter;
20911 int initial_misses = misses_counter;
20912 int initial_updates = updates_counter;
20913 CompileRun(kMegamorphicTestProgram);
20914 int probes = probes_counter - initial_probes;
20915 int misses = misses_counter - initial_misses;
20916 int updates = updates_counter - initial_updates;
20917 CHECK_LT(updates, 10);
20918 CHECK_LT(misses, 10);
20919 // TODO(verwaest): Update this test to overflow the degree of polymorphism
20920 // before megamorphism. The number of probes will only work once we teach the
20921 // serializer to embed references to counters in the stubs, given that the
20922 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20923 CHECK_GE(probes, 0);
20928 TEST(SecondaryStubCache) {
20929 StubCacheHelper(true);
20933 TEST(PrimaryStubCache) {
20934 StubCacheHelper(false);
20939 static int cow_arrays_created_runtime = 0;
20942 static int* LookupCounterCOWArrays(const char* name) {
20943 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20944 return &cow_arrays_created_runtime;
20951 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20953 i::FLAG_native_code_counters = true;
20955 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
20956 v8::HandleScope scope(env->GetIsolate());
20957 int initial_cow_arrays = cow_arrays_created_runtime;
20958 CompileRun("var o = [1, 2, 3];");
20959 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20960 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20961 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20962 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20963 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20968 TEST(StaticGetters) {
20969 LocalContext context;
20970 i::Factory* factory = CcTest::i_isolate()->factory();
20971 v8::Isolate* isolate = CcTest::isolate();
20972 v8::HandleScope scope(isolate);
20973 i::Handle<i::Object> undefined_value = factory->undefined_value();
20974 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20975 i::Handle<i::Object> null_value = factory->null_value();
20976 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20977 i::Handle<i::Object> true_value = factory->true_value();
20978 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20979 i::Handle<i::Object> false_value = factory->false_value();
20980 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20984 UNINITIALIZED_TEST(IsolateEmbedderData) {
20985 CcTest::DisableAutomaticDispose();
20986 v8::Isolate* isolate = v8::Isolate::New();
20988 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20989 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20990 CHECK_EQ(NULL, isolate->GetData(slot));
20991 CHECK_EQ(NULL, i_isolate->GetData(slot));
20993 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20994 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20995 isolate->SetData(slot, data);
20997 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20998 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20999 CHECK_EQ(data, isolate->GetData(slot));
21000 CHECK_EQ(data, i_isolate->GetData(slot));
21002 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21003 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21004 isolate->SetData(slot, data);
21006 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21007 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21008 CHECK_EQ(data, isolate->GetData(slot));
21009 CHECK_EQ(data, i_isolate->GetData(slot));
21012 isolate->Dispose();
21016 TEST(StringEmpty) {
21017 LocalContext context;
21018 i::Factory* factory = CcTest::i_isolate()->factory();
21019 v8::Isolate* isolate = CcTest::isolate();
21020 v8::HandleScope scope(isolate);
21021 i::Handle<i::Object> empty_string = factory->empty_string();
21022 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21026 static int instance_checked_getter_count = 0;
21027 static void InstanceCheckedGetter(
21028 Local<String> name,
21029 const v8::PropertyCallbackInfo<v8::Value>& info) {
21030 CHECK_EQ(name, v8_str("foo"));
21031 instance_checked_getter_count++;
21032 info.GetReturnValue().Set(v8_num(11));
21036 static int instance_checked_setter_count = 0;
21037 static void InstanceCheckedSetter(Local<String> name,
21038 Local<Value> value,
21039 const v8::PropertyCallbackInfo<void>& info) {
21040 CHECK_EQ(name, v8_str("foo"));
21041 CHECK_EQ(value, v8_num(23));
21042 instance_checked_setter_count++;
21046 static void CheckInstanceCheckedResult(int getters, int setters,
21047 bool expects_callbacks,
21048 TryCatch* try_catch) {
21049 if (expects_callbacks) {
21050 CHECK(!try_catch->HasCaught());
21051 CHECK_EQ(getters, instance_checked_getter_count);
21052 CHECK_EQ(setters, instance_checked_setter_count);
21054 CHECK(try_catch->HasCaught());
21055 CHECK_EQ(0, instance_checked_getter_count);
21056 CHECK_EQ(0, instance_checked_setter_count);
21058 try_catch->Reset();
21062 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21063 instance_checked_getter_count = 0;
21064 instance_checked_setter_count = 0;
21065 TryCatch try_catch;
21067 // Test path through generic runtime code.
21068 CompileRun("obj.foo");
21069 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21070 CompileRun("obj.foo = 23");
21071 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21073 // Test path through generated LoadIC and StoredIC.
21074 CompileRun("function test_get(o) { o.foo; }"
21076 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21077 CompileRun("test_get(obj);");
21078 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21079 CompileRun("test_get(obj);");
21080 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21081 CompileRun("function test_set(o) { o.foo = 23; }"
21083 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21084 CompileRun("test_set(obj);");
21085 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21086 CompileRun("test_set(obj);");
21087 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21089 // Test path through optimized code.
21090 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21092 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21093 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21095 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21097 // Cleanup so that closures start out fresh in next check.
21098 CompileRun("%DeoptimizeFunction(test_get);"
21099 "%ClearFunctionTypeFeedback(test_get);"
21100 "%DeoptimizeFunction(test_set);"
21101 "%ClearFunctionTypeFeedback(test_set);");
21105 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21106 v8::internal::FLAG_allow_natives_syntax = true;
21107 LocalContext context;
21108 v8::HandleScope scope(context->GetIsolate());
21110 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21111 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21112 inst->SetAccessor(v8_str("foo"),
21113 InstanceCheckedGetter, InstanceCheckedSetter,
21117 v8::AccessorSignature::New(context->GetIsolate(), templ));
21118 context->Global()->Set(v8_str("f"), templ->GetFunction());
21120 printf("Testing positive ...\n");
21121 CompileRun("var obj = new f();");
21122 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21123 CheckInstanceCheckedAccessors(true);
21125 printf("Testing negative ...\n");
21126 CompileRun("var obj = {};"
21127 "obj.__proto__ = new f();");
21128 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21129 CheckInstanceCheckedAccessors(false);
21133 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21134 v8::internal::FLAG_allow_natives_syntax = true;
21135 LocalContext context;
21136 v8::HandleScope scope(context->GetIsolate());
21138 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21139 Local<ObjectTemplate> inst = templ->InstanceTemplate();
21140 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21141 inst->SetAccessor(v8_str("foo"),
21142 InstanceCheckedGetter, InstanceCheckedSetter,
21146 v8::AccessorSignature::New(context->GetIsolate(), templ));
21147 context->Global()->Set(v8_str("f"), templ->GetFunction());
21149 printf("Testing positive ...\n");
21150 CompileRun("var obj = new f();");
21151 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21152 CheckInstanceCheckedAccessors(true);
21154 printf("Testing negative ...\n");
21155 CompileRun("var obj = {};"
21156 "obj.__proto__ = new f();");
21157 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21158 CheckInstanceCheckedAccessors(false);
21162 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21163 v8::internal::FLAG_allow_natives_syntax = true;
21164 LocalContext context;
21165 v8::HandleScope scope(context->GetIsolate());
21167 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21168 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21169 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21170 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21172 v8::AccessorSignature::New(context->GetIsolate(), templ));
21173 context->Global()->Set(v8_str("f"), templ->GetFunction());
21175 printf("Testing positive ...\n");
21176 CompileRun("var obj = new f();");
21177 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21178 CheckInstanceCheckedAccessors(true);
21180 printf("Testing negative ...\n");
21181 CompileRun("var obj = {};"
21182 "obj.__proto__ = new f();");
21183 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21184 CheckInstanceCheckedAccessors(false);
21186 printf("Testing positive with modified prototype chain ...\n");
21187 CompileRun("var obj = new f();"
21189 "pro.__proto__ = obj.__proto__;"
21190 "obj.__proto__ = pro;");
21191 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21192 CheckInstanceCheckedAccessors(true);
21196 TEST(TryFinallyMessage) {
21197 LocalContext context;
21198 v8::HandleScope scope(context->GetIsolate());
21200 // Test that the original error message is not lost if there is a
21201 // recursive call into Javascript is done in the finally block, e.g. to
21202 // initialize an IC. (crbug.com/129171)
21203 TryCatch try_catch;
21204 const char* trigger_ic =
21206 " throw new Error('test'); \n"
21209 " x++; \n" // Trigger an IC initialization here.
21211 CompileRun(trigger_ic);
21212 CHECK(try_catch.HasCaught());
21213 Local<Message> message = try_catch.Message();
21214 CHECK(!message.IsEmpty());
21215 CHECK_EQ(2, message->GetLineNumber());
21219 // Test that the original exception message is indeed overwritten if
21220 // a new error is thrown in the finally block.
21221 TryCatch try_catch;
21222 const char* throw_again =
21224 " throw new Error('test'); \n"
21228 " throw new Error('again'); \n" // This is the new uncaught error.
21230 CompileRun(throw_again);
21231 CHECK(try_catch.HasCaught());
21232 Local<Message> message = try_catch.Message();
21233 CHECK(!message.IsEmpty());
21234 CHECK_EQ(6, message->GetLineNumber());
21239 static void Helper137002(bool do_store,
21241 bool remove_accessor,
21242 bool interceptor) {
21243 LocalContext context;
21244 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21246 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21248 templ->SetAccessor(v8_str("foo"),
21249 GetterWhichReturns42,
21250 SetterWhichSetsYOnThisTo23);
21252 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21254 // Turn monomorphic on slow object with native accessor, then turn
21255 // polymorphic, finally optimize to create negative lookup and fail.
21256 CompileRun(do_store ?
21257 "function f(x) { x.foo = void 0; }" :
21258 "function f(x) { return x.foo; }");
21259 CompileRun("obj.y = void 0;");
21260 if (!interceptor) {
21261 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21263 CompileRun("obj.__proto__ = null;"
21264 "f(obj); f(obj); f(obj);");
21266 CompileRun("f({});");
21268 CompileRun("obj.y = void 0;"
21269 "%OptimizeFunctionOnNextCall(f);");
21270 if (remove_accessor) {
21271 CompileRun("delete obj.foo;");
21273 CompileRun("var result = f(obj);");
21275 CompileRun("result = obj.y;");
21277 if (remove_accessor && !interceptor) {
21278 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21280 CHECK_EQ(do_store ? 23 : 42,
21281 context->Global()->Get(v8_str("result"))->Int32Value());
21286 THREADED_TEST(Regress137002a) {
21287 i::FLAG_allow_natives_syntax = true;
21288 i::FLAG_compilation_cache = false;
21289 v8::HandleScope scope(CcTest::isolate());
21290 for (int i = 0; i < 16; i++) {
21291 Helper137002(i & 8, i & 4, i & 2, i & 1);
21296 THREADED_TEST(Regress137002b) {
21297 i::FLAG_allow_natives_syntax = true;
21298 LocalContext context;
21299 v8::Isolate* isolate = context->GetIsolate();
21300 v8::HandleScope scope(isolate);
21301 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21302 templ->SetAccessor(v8_str("foo"),
21303 GetterWhichReturns42,
21304 SetterWhichSetsYOnThisTo23);
21305 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21307 // Turn monomorphic on slow object with native accessor, then just
21308 // delete the property and fail.
21309 CompileRun("function load(x) { return x.foo; }"
21310 "function store(x) { x.foo = void 0; }"
21311 "function keyed_load(x, key) { return x[key]; }"
21312 // Second version of function has a different source (add void 0)
21313 // so that it does not share code with the first version. This
21314 // ensures that the ICs are monomorphic.
21315 "function load2(x) { void 0; return x.foo; }"
21316 "function store2(x) { void 0; x.foo = void 0; }"
21317 "function keyed_load2(x, key) { void 0; return x[key]; }"
21320 "obj.__proto__ = null;"
21322 "subobj.y = void 0;"
21323 "subobj.__proto__ = obj;"
21324 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21326 // Make the ICs monomorphic.
21327 "load(obj); load(obj);"
21328 "load2(subobj); load2(subobj);"
21329 "store(obj); store(obj);"
21330 "store2(subobj); store2(subobj);"
21331 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21332 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21334 // Actually test the shiny new ICs and better not crash. This
21335 // serves as a regression test for issue 142088 as well.
21340 "keyed_load(obj, 'foo');"
21341 "keyed_load2(subobj, 'foo');"
21343 // Delete the accessor. It better not be called any more now.
21346 "subobj.y = void 0;"
21348 "var load_result = load(obj);"
21349 "var load_result2 = load2(subobj);"
21350 "var keyed_load_result = keyed_load(obj, 'foo');"
21351 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21354 "var y_from_obj = obj.y;"
21355 "var y_from_subobj = subobj.y;");
21356 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21357 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21358 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21359 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21360 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21361 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21365 THREADED_TEST(Regress142088) {
21366 i::FLAG_allow_natives_syntax = true;
21367 LocalContext context;
21368 v8::Isolate* isolate = context->GetIsolate();
21369 v8::HandleScope scope(isolate);
21370 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21371 templ->SetAccessor(v8_str("foo"),
21372 GetterWhichReturns42,
21373 SetterWhichSetsYOnThisTo23);
21374 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21376 CompileRun("function load(x) { return x.foo; }"
21377 "var o = Object.create(obj);"
21378 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21379 "load(o); load(o); load(o); load(o);");
21383 THREADED_TEST(Regress3337) {
21384 LocalContext context;
21385 v8::Isolate* isolate = context->GetIsolate();
21386 v8::HandleScope scope(isolate);
21387 Local<v8::Object> o1 = Object::New(isolate);
21388 Local<v8::Object> o2 = Object::New(isolate);
21389 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21390 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21391 CHECK(io1->map() == io2->map());
21392 o1->SetIndexedPropertiesToExternalArrayData(
21393 NULL, v8::kExternalUint32Array, 0);
21394 o2->SetIndexedPropertiesToExternalArrayData(
21395 NULL, v8::kExternalUint32Array, 0);
21396 CHECK(io1->map() == io2->map());
21400 THREADED_TEST(Regress137496) {
21401 i::FLAG_expose_gc = true;
21402 LocalContext context;
21403 v8::HandleScope scope(context->GetIsolate());
21405 // Compile a try-finally clause where the finally block causes a GC
21406 // while there still is a message pending for external reporting.
21407 TryCatch try_catch;
21408 try_catch.SetVerbose(true);
21409 CompileRun("try { throw new Error(); } finally { gc(); }");
21410 CHECK(try_catch.HasCaught());
21414 THREADED_TEST(Regress149912) {
21415 LocalContext context;
21416 v8::HandleScope scope(context->GetIsolate());
21417 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21418 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21419 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21420 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21424 THREADED_TEST(Regress157124) {
21425 LocalContext context;
21426 v8::Isolate* isolate = context->GetIsolate();
21427 v8::HandleScope scope(isolate);
21428 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21429 Local<Object> obj = templ->NewInstance();
21430 obj->GetIdentityHash();
21431 obj->DeleteHiddenValue(v8_str("Bug"));
21435 THREADED_TEST(Regress2535) {
21436 LocalContext context;
21437 v8::HandleScope scope(context->GetIsolate());
21438 Local<Value> set_value = CompileRun("new Set();");
21439 Local<Object> set_object(Local<Object>::Cast(set_value));
21440 CHECK_EQ(0, set_object->InternalFieldCount());
21441 Local<Value> map_value = CompileRun("new Map();");
21442 Local<Object> map_object(Local<Object>::Cast(map_value));
21443 CHECK_EQ(0, map_object->InternalFieldCount());
21447 THREADED_TEST(Regress2746) {
21448 LocalContext context;
21449 v8::Isolate* isolate = context->GetIsolate();
21450 v8::HandleScope scope(isolate);
21451 Local<Object> obj = Object::New(isolate);
21452 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21453 obj->SetHiddenValue(key, v8::Undefined(isolate));
21454 Local<Value> value = obj->GetHiddenValue(key);
21455 CHECK(!value.IsEmpty());
21456 CHECK(value->IsUndefined());
21460 THREADED_TEST(Regress260106) {
21461 LocalContext context;
21462 v8::Isolate* isolate = context->GetIsolate();
21463 v8::HandleScope scope(isolate);
21464 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21466 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21467 Local<Function> function = templ->GetFunction();
21468 CHECK(!function.IsEmpty());
21469 CHECK(function->IsFunction());
21473 THREADED_TEST(JSONParseObject) {
21474 LocalContext context;
21475 HandleScope scope(context->GetIsolate());
21476 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21477 Handle<Object> global = context->Global();
21478 global->Set(v8_str("obj"), obj);
21479 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21483 THREADED_TEST(JSONParseNumber) {
21484 LocalContext context;
21485 HandleScope scope(context->GetIsolate());
21486 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21487 Handle<Object> global = context->Global();
21488 global->Set(v8_str("obj"), obj);
21489 ExpectString("JSON.stringify(obj)", "42");
21494 class ThreadInterruptTest {
21496 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21497 ~ThreadInterruptTest() {}
21500 InterruptThread i_thread(this);
21504 CHECK_EQ(kExpectedValue, sem_value_);
21508 static const int kExpectedValue = 1;
21510 class InterruptThread : public v8::base::Thread {
21512 explicit InterruptThread(ThreadInterruptTest* test)
21513 : Thread(Options("InterruptThread")), test_(test) {}
21515 virtual void Run() {
21516 struct sigaction action;
21518 // Ensure that we'll enter waiting condition
21519 v8::base::OS::Sleep(100);
21521 // Setup signal handler
21522 memset(&action, 0, sizeof(action));
21523 action.sa_handler = SignalHandler;
21524 sigaction(SIGCHLD, &action, NULL);
21527 kill(getpid(), SIGCHLD);
21529 // Ensure that if wait has returned because of error
21530 v8::base::OS::Sleep(100);
21532 // Set value and signal semaphore
21533 test_->sem_value_ = 1;
21534 test_->sem_.Signal();
21537 static void SignalHandler(int signal) {
21541 ThreadInterruptTest* test_;
21544 v8::base::Semaphore sem_;
21545 volatile int sem_value_;
21549 THREADED_TEST(SemaphoreInterruption) {
21550 ThreadInterruptTest().RunTest();
21554 #endif // V8_OS_POSIX
21557 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21559 v8::AccessType type,
21560 Local<Value> data) {
21561 i::PrintF("Named access blocked.\n");
21566 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21568 v8::AccessType type,
21569 Local<Value> data) {
21570 i::PrintF("Indexed access blocked.\n");
21575 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21580 TEST(JSONStringifyAccessCheck) {
21581 v8::V8::Initialize();
21582 v8::Isolate* isolate = CcTest::isolate();
21583 v8::HandleScope scope(isolate);
21585 // Create an ObjectTemplate for global objects and install access
21586 // check callbacks that will block access.
21587 v8::Handle<v8::ObjectTemplate> global_template =
21588 v8::ObjectTemplate::New(isolate);
21589 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21590 IndexAccessAlwaysBlocked);
21592 // Create a context and set an x property on it's global object.
21593 LocalContext context0(NULL, global_template);
21594 v8::Handle<v8::Object> global0 = context0->Global();
21595 global0->Set(v8_str("x"), v8_num(42));
21596 ExpectString("JSON.stringify(this)", "{\"x\":42}");
21598 for (int i = 0; i < 2; i++) {
21600 // Install a toJSON function on the second run.
21601 v8::Handle<v8::FunctionTemplate> toJSON =
21602 v8::FunctionTemplate::New(isolate, UnreachableCallback);
21604 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21606 // Create a context with a different security token so that the
21607 // failed access check callback will be called on each access.
21608 LocalContext context1(NULL, global_template);
21609 context1->Global()->Set(v8_str("other"), global0);
21611 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21612 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21613 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21615 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21616 array->Set(0, v8_str("a"));
21617 array->Set(1, v8_str("b"));
21618 context1->Global()->Set(v8_str("array"), array);
21619 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21620 array->TurnOnAccessCheck();
21621 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21622 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21623 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21628 bool access_check_fail_thrown = false;
21629 bool catch_callback_called = false;
21632 // Failed access check callback that performs a GC on each invocation.
21633 void FailedAccessCheckThrows(Local<v8::Object> target,
21634 v8::AccessType type,
21635 Local<v8::Value> data) {
21636 access_check_fail_thrown = true;
21637 i::PrintF("Access check failed. Error thrown.\n");
21638 CcTest::isolate()->ThrowException(
21639 v8::Exception::Error(v8_str("cross context")));
21643 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21644 for (int i = 0; i < args.Length(); i++) {
21645 i::PrintF("%s\n", *String::Utf8Value(args[i]));
21647 catch_callback_called = true;
21651 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21652 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21656 void CheckCorrectThrow(const char* script) {
21657 // Test that the script, when wrapped into a try-catch, triggers the catch
21658 // clause due to failed access check throwing an exception.
21659 // The subsequent try-catch should run without any exception.
21660 access_check_fail_thrown = false;
21661 catch_callback_called = false;
21662 i::ScopedVector<char> source(1024);
21663 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21664 CompileRun(source.start());
21665 CHECK(access_check_fail_thrown);
21666 CHECK(catch_callback_called);
21668 access_check_fail_thrown = false;
21669 catch_callback_called = false;
21670 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21671 CHECK(!access_check_fail_thrown);
21672 CHECK(!catch_callback_called);
21676 TEST(AccessCheckThrows) {
21677 i::FLAG_allow_natives_syntax = true;
21678 v8::V8::Initialize();
21679 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21680 v8::Isolate* isolate = CcTest::isolate();
21681 v8::HandleScope scope(isolate);
21683 // Create an ObjectTemplate for global objects and install access
21684 // check callbacks that will block access.
21685 v8::Handle<v8::ObjectTemplate> global_template =
21686 v8::ObjectTemplate::New(isolate);
21687 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21688 IndexAccessAlwaysBlocked);
21690 // Create a context and set an x property on it's global object.
21691 LocalContext context0(NULL, global_template);
21692 context0->Global()->Set(v8_str("x"), v8_num(42));
21693 v8::Handle<v8::Object> global0 = context0->Global();
21695 // Create a context with a different security token so that the
21696 // failed access check callback will be called on each access.
21697 LocalContext context1(NULL, global_template);
21698 context1->Global()->Set(v8_str("other"), global0);
21700 v8::Handle<v8::FunctionTemplate> catcher_fun =
21701 v8::FunctionTemplate::New(isolate, CatcherCallback);
21702 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21704 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21705 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21706 context1->Global()->Set(v8_str("has_own_property"),
21707 has_own_property_fun->GetFunction());
21709 { v8::TryCatch try_catch;
21710 access_check_fail_thrown = false;
21711 CompileRun("other.x;");
21712 CHECK(access_check_fail_thrown);
21713 CHECK(try_catch.HasCaught());
21716 CheckCorrectThrow("other.x");
21717 CheckCorrectThrow("other[1]");
21718 CheckCorrectThrow("JSON.stringify(other)");
21719 CheckCorrectThrow("has_own_property(other, 'x')");
21720 CheckCorrectThrow("%GetProperty(other, 'x')");
21721 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21722 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21723 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21724 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21725 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21726 CheckCorrectThrow("%HasProperty(other, 'x')");
21727 CheckCorrectThrow("%HasElement(other, 1)");
21728 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21729 CheckCorrectThrow("%GetPropertyNames(other)");
21730 // PROPERTY_ATTRIBUTES_NONE = 0
21731 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21732 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21733 "other, 'x', null, null, 1)");
21735 // Reset the failed access check callback so it does not influence
21736 // the other tests.
21737 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21741 THREADED_TEST(Regress256330) {
21742 i::FLAG_allow_natives_syntax = true;
21743 LocalContext context;
21744 v8::HandleScope scope(context->GetIsolate());
21745 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21746 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21747 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21748 CompileRun("\"use strict\"; var o = new Bug;"
21749 "function f(o) { o.x = 10; };"
21750 "f(o); f(o); f(o);"
21751 "%OptimizeFunctionOnNextCall(f);"
21753 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21757 THREADED_TEST(CrankshaftInterceptorSetter) {
21758 i::FLAG_allow_natives_syntax = true;
21759 v8::HandleScope scope(CcTest::isolate());
21760 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21761 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21763 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21764 CompileRun("var obj = new Obj;"
21765 // Initialize fields to avoid transitions later.
21767 "obj.accessor_age = 42;"
21768 "function setter(i) { this.accessor_age = i; };"
21769 "function getter() { return this.accessor_age; };"
21770 "function setAge(i) { obj.age = i; };"
21771 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21775 "%OptimizeFunctionOnNextCall(setAge);"
21777 // All stores went through the interceptor.
21778 ExpectInt32("obj.interceptor_age", 4);
21779 ExpectInt32("obj.accessor_age", 42);
21783 THREADED_TEST(CrankshaftInterceptorGetter) {
21784 i::FLAG_allow_natives_syntax = true;
21785 v8::HandleScope scope(CcTest::isolate());
21786 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21787 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21789 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21790 CompileRun("var obj = new Obj;"
21791 // Initialize fields to avoid transitions later.
21793 "obj.accessor_age = 42;"
21794 "function getter() { return this.accessor_age; };"
21795 "function getAge() { return obj.interceptor_age; };"
21796 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21800 "%OptimizeFunctionOnNextCall(getAge);");
21801 // Access through interceptor.
21802 ExpectInt32("getAge()", 1);
21806 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21807 i::FLAG_allow_natives_syntax = true;
21808 v8::HandleScope scope(CcTest::isolate());
21809 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21810 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21812 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21813 CompileRun("var obj = new Obj;"
21814 "obj.__proto__.interceptor_age = 42;"
21816 "function getAge() { return obj.interceptor_age; };");
21817 ExpectInt32("getAge();", 100);
21818 ExpectInt32("getAge();", 100);
21819 ExpectInt32("getAge();", 100);
21820 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21821 // Access through interceptor.
21822 ExpectInt32("getAge();", 100);
21826 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21827 i::FLAG_allow_natives_syntax = true;
21828 v8::HandleScope scope(CcTest::isolate());
21829 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21830 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21832 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21833 CompileRun("var obj = new Obj;"
21834 "obj.age = 100000;"
21835 "function setAge(i) { obj.age = i };"
21839 "%OptimizeFunctionOnNextCall(setAge);"
21841 ExpectInt32("obj.age", 100000);
21842 ExpectInt32("obj.interceptor_age", 103);
21846 class RequestInterruptTestBase {
21848 RequestInterruptTestBase()
21850 isolate_(env_->GetIsolate()),
21853 should_continue_(true) {
21856 virtual ~RequestInterruptTestBase() { }
21858 virtual void StartInterruptThread() = 0;
21860 virtual void TestBody() = 0;
21863 StartInterruptThread();
21865 v8::HandleScope handle_scope(isolate_);
21869 isolate_->ClearInterrupt();
21871 // Verify we arrived here because interruptor was called
21872 // not due to a bug causing us to exit the loop too early.
21873 CHECK(!should_continue());
21876 void WakeUpInterruptor() {
21880 bool should_continue() const { return should_continue_; }
21882 bool ShouldContinue() {
21884 if (--warmup_ == 0) {
21885 WakeUpInterruptor();
21889 return should_continue_;
21892 static void ShouldContinueCallback(
21893 const v8::FunctionCallbackInfo<Value>& info) {
21894 RequestInterruptTestBase* test =
21895 reinterpret_cast<RequestInterruptTestBase*>(
21896 info.Data().As<v8::External>()->Value());
21897 info.GetReturnValue().Set(test->ShouldContinue());
21901 v8::Isolate* isolate_;
21902 v8::base::Semaphore sem_;
21904 bool should_continue_;
21908 class RequestInterruptTestBaseWithSimpleInterrupt
21909 : public RequestInterruptTestBase {
21911 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
21913 virtual void StartInterruptThread() {
21918 class InterruptThread : public v8::base::Thread {
21920 explicit InterruptThread(RequestInterruptTestBase* test)
21921 : Thread(Options("RequestInterruptTest")), test_(test) {}
21923 virtual void Run() {
21924 test_->sem_.Wait();
21925 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21928 static void OnInterrupt(v8::Isolate* isolate, void* data) {
21929 reinterpret_cast<RequestInterruptTestBase*>(data)->
21930 should_continue_ = false;
21934 RequestInterruptTestBase* test_;
21937 InterruptThread i_thread;
21941 class RequestInterruptTestWithFunctionCall
21942 : public RequestInterruptTestBaseWithSimpleInterrupt {
21944 virtual void TestBody() {
21945 Local<Function> func = Function::New(
21946 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21947 env_->Global()->Set(v8_str("ShouldContinue"), func);
21949 CompileRun("while (ShouldContinue()) { }");
21954 class RequestInterruptTestWithMethodCall
21955 : public RequestInterruptTestBaseWithSimpleInterrupt {
21957 virtual void TestBody() {
21958 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21959 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21960 proto->Set(v8_str("shouldContinue"), Function::New(
21961 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21962 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21964 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21969 class RequestInterruptTestWithAccessor
21970 : public RequestInterruptTestBaseWithSimpleInterrupt {
21972 virtual void TestBody() {
21973 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21974 v8::Local<v8::Template> proto = t->PrototypeTemplate();
21975 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21976 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21977 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21979 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21984 class RequestInterruptTestWithNativeAccessor
21985 : public RequestInterruptTestBaseWithSimpleInterrupt {
21987 virtual void TestBody() {
21988 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21989 t->InstanceTemplate()->SetNativeDataProperty(
21990 v8_str("shouldContinue"),
21991 &ShouldContinueNativeGetter,
21993 v8::External::New(isolate_, this));
21994 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21996 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22000 static void ShouldContinueNativeGetter(
22001 Local<String> property,
22002 const v8::PropertyCallbackInfo<v8::Value>& info) {
22003 RequestInterruptTestBase* test =
22004 reinterpret_cast<RequestInterruptTestBase*>(
22005 info.Data().As<v8::External>()->Value());
22006 info.GetReturnValue().Set(test->ShouldContinue());
22011 class RequestInterruptTestWithMethodCallAndInterceptor
22012 : public RequestInterruptTestBaseWithSimpleInterrupt {
22014 virtual void TestBody() {
22015 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22016 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22017 proto->Set(v8_str("shouldContinue"), Function::New(
22018 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22019 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22020 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22022 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22024 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22028 static void EmptyInterceptor(
22029 Local<String> property,
22030 const v8::PropertyCallbackInfo<v8::Value>& info) {
22035 class RequestInterruptTestWithMathAbs
22036 : public RequestInterruptTestBaseWithSimpleInterrupt {
22038 virtual void TestBody() {
22039 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22041 WakeUpInterruptorCallback,
22042 v8::External::New(isolate_, this)));
22044 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22046 ShouldContinueCallback,
22047 v8::External::New(isolate_, this)));
22049 i::FLAG_allow_natives_syntax = true;
22050 CompileRun("function loopish(o) {"
22052 " while (o.abs(1) > 0) {"
22053 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22055 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22060 "var obj = {abs: function () { return i-- }, x: null};"
22063 "%OptimizeFunctionOnNextCall(loopish);"
22066 i::FLAG_allow_natives_syntax = false;
22070 static void WakeUpInterruptorCallback(
22071 const v8::FunctionCallbackInfo<Value>& info) {
22072 if (!info[0]->BooleanValue()) return;
22074 RequestInterruptTestBase* test =
22075 reinterpret_cast<RequestInterruptTestBase*>(
22076 info.Data().As<v8::External>()->Value());
22077 test->WakeUpInterruptor();
22080 static void ShouldContinueCallback(
22081 const v8::FunctionCallbackInfo<Value>& info) {
22082 RequestInterruptTestBase* test =
22083 reinterpret_cast<RequestInterruptTestBase*>(
22084 info.Data().As<v8::External>()->Value());
22085 info.GetReturnValue().Set(test->should_continue());
22090 TEST(RequestInterruptTestWithFunctionCall) {
22091 RequestInterruptTestWithFunctionCall().RunTest();
22095 TEST(RequestInterruptTestWithMethodCall) {
22096 RequestInterruptTestWithMethodCall().RunTest();
22100 TEST(RequestInterruptTestWithAccessor) {
22101 RequestInterruptTestWithAccessor().RunTest();
22105 TEST(RequestInterruptTestWithNativeAccessor) {
22106 RequestInterruptTestWithNativeAccessor().RunTest();
22110 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22111 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22115 TEST(RequestInterruptTestWithMathAbs) {
22116 RequestInterruptTestWithMathAbs().RunTest();
22120 class ClearInterruptFromAnotherThread
22121 : public RequestInterruptTestBase {
22123 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22125 virtual void StartInterruptThread() {
22129 virtual void TestBody() {
22130 Local<Function> func = Function::New(
22131 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22132 env_->Global()->Set(v8_str("ShouldContinue"), func);
22134 CompileRun("while (ShouldContinue()) { }");
22138 class InterruptThread : public v8::base::Thread {
22140 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22141 : Thread(Options("RequestInterruptTest")), test_(test) {}
22143 virtual void Run() {
22144 test_->sem_.Wait();
22145 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22146 test_->sem_.Wait();
22147 test_->isolate_->ClearInterrupt();
22148 test_->sem2_.Signal();
22151 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22152 ClearInterruptFromAnotherThread* test =
22153 reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22154 test->sem_.Signal();
22155 bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22156 // Crash instead of timeout to make this failure more prominent.
22158 test->should_continue_ = false;
22162 ClearInterruptFromAnotherThread* test_;
22165 InterruptThread i_thread;
22166 v8::base::Semaphore sem2_;
22170 TEST(ClearInterruptFromAnotherThread) {
22171 ClearInterruptFromAnotherThread().RunTest();
22175 static Local<Value> function_new_expected_env;
22176 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22177 CHECK_EQ(function_new_expected_env, info.Data());
22178 info.GetReturnValue().Set(17);
22182 THREADED_TEST(FunctionNew) {
22184 v8::Isolate* isolate = env->GetIsolate();
22185 v8::HandleScope scope(isolate);
22186 Local<Object> data = v8::Object::New(isolate);
22187 function_new_expected_env = data;
22188 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22189 env->Global()->Set(v8_str("func"), func);
22190 Local<Value> result = CompileRun("func();");
22191 CHECK_EQ(v8::Integer::New(isolate, 17), result);
22192 // Verify function not cached
22193 int serial_number =
22194 i::Smi::cast(v8::Utils::OpenHandle(*func)
22195 ->shared()->get_api_func_data()->serial_number())->value();
22196 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22197 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22198 i::Handle<i::Object> elm =
22199 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22200 CHECK(elm->IsUndefined());
22201 // Verify that each Function::New creates a new function instance
22202 Local<Object> data2 = v8::Object::New(isolate);
22203 function_new_expected_env = data2;
22204 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22205 CHECK(!func2->IsNull());
22206 CHECK_NE(func, func2);
22207 env->Global()->Set(v8_str("func2"), func2);
22208 Local<Value> result2 = CompileRun("func2();");
22209 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22213 TEST(EscapeableHandleScope) {
22214 HandleScope outer_scope(CcTest::isolate());
22215 LocalContext context;
22216 const int runs = 10;
22217 Local<String> values[runs];
22218 for (int i = 0; i < runs; i++) {
22219 v8::EscapableHandleScope inner_scope(CcTest::isolate());
22220 Local<String> value;
22221 if (i != 0) value = v8_str("escape value");
22222 values[i] = inner_scope.Escape(value);
22224 for (int i = 0; i < runs; i++) {
22225 Local<String> expected;
22227 CHECK_EQ(v8_str("escape value"), values[i]);
22229 CHECK(values[i].IsEmpty());
22235 static void SetterWhichExpectsThisAndHolderToDiffer(
22236 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22237 CHECK(info.Holder() != info.This());
22241 TEST(Regress239669) {
22242 LocalContext context;
22243 v8::Isolate* isolate = context->GetIsolate();
22244 v8::HandleScope scope(isolate);
22245 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22246 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22247 context->Global()->Set(v8_str("P"), templ->NewInstance());
22252 "C1.prototype = P;"
22253 "for (var i = 0; i < 4; i++ ) {"
22259 class ApiCallOptimizationChecker {
22261 static Local<Object> data;
22262 static Local<Object> receiver;
22263 static Local<Object> holder;
22264 static Local<Object> callee;
22267 static void OptimizationCallback(
22268 const v8::FunctionCallbackInfo<v8::Value>& info) {
22269 CHECK(callee == info.Callee());
22270 CHECK(data == info.Data());
22271 CHECK(receiver == info.This());
22272 if (info.Length() == 1) {
22273 CHECK_EQ(v8_num(1), info[0]);
22275 CHECK(holder == info.Holder());
22277 info.GetReturnValue().Set(v8_str("returned"));
22281 enum SignatureType {
22283 kSignatureOnReceiver,
22284 kSignatureOnPrototype
22288 SignatureType signature_types[] =
22289 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22290 for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22291 SignatureType signature_type = signature_types[i];
22292 for (int j = 0; j < 2; j++) {
22293 bool global = j == 0;
22294 int key = signature_type +
22295 ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22296 Run(signature_type, global, key);
22301 void Run(SignatureType signature_type, bool global, int key) {
22302 v8::Isolate* isolate = CcTest::isolate();
22303 v8::HandleScope scope(isolate);
22304 // Build a template for signature checks.
22305 Local<v8::ObjectTemplate> signature_template;
22306 Local<v8::Signature> signature;
22308 Local<v8::FunctionTemplate> parent_template =
22309 FunctionTemplate::New(isolate);
22310 parent_template->SetHiddenPrototype(true);
22311 Local<v8::FunctionTemplate> function_template
22312 = FunctionTemplate::New(isolate);
22313 function_template->Inherit(parent_template);
22314 switch (signature_type) {
22317 case kSignatureOnReceiver:
22318 signature = v8::Signature::New(isolate, function_template);
22320 case kSignatureOnPrototype:
22321 signature = v8::Signature::New(isolate, parent_template);
22324 signature_template = function_template->InstanceTemplate();
22326 // Global object must pass checks.
22327 Local<v8::Context> context =
22328 v8::Context::New(isolate, NULL, signature_template);
22329 v8::Context::Scope context_scope(context);
22330 // Install regular object that can pass signature checks.
22331 Local<Object> function_receiver = signature_template->NewInstance();
22332 context->Global()->Set(v8_str("function_receiver"), function_receiver);
22333 // Get the holder objects.
22334 Local<Object> inner_global =
22335 Local<Object>::Cast(context->Global()->GetPrototype());
22336 // Install functions on hidden prototype object if there is one.
22337 data = Object::New(isolate);
22338 Local<FunctionTemplate> function_template = FunctionTemplate::New(
22339 isolate, OptimizationCallback, data, signature);
22340 Local<Function> function = function_template->GetFunction();
22341 Local<Object> global_holder = inner_global;
22342 Local<Object> function_holder = function_receiver;
22343 if (signature_type == kSignatureOnPrototype) {
22344 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22345 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22347 global_holder->Set(v8_str("g_f"), function);
22348 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22349 function_holder->Set(v8_str("f"), function);
22350 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22351 // Initialize expected values.
22355 receiver = context->Global();
22356 holder = inner_global;
22358 holder = function_receiver;
22359 // If not using a signature, add something else to the prototype chain
22360 // to test the case that holder != receiver
22361 if (signature_type == kNoSignature) {
22362 receiver = Local<Object>::Cast(CompileRun(
22363 "var receiver_subclass = {};\n"
22364 "receiver_subclass.__proto__ = function_receiver;\n"
22365 "receiver_subclass"));
22367 receiver = Local<Object>::Cast(CompileRun(
22368 "var receiver_subclass = function_receiver;\n"
22369 "receiver_subclass"));
22372 // With no signature, the holder is not set.
22373 if (signature_type == kNoSignature) holder = receiver;
22374 // build wrap_function
22375 i::ScopedVector<char> wrap_function(200);
22379 "function wrap_f_%d() { var f = g_f; return f(); }\n"
22380 "function wrap_get_%d() { return this.g_acc; }\n"
22381 "function wrap_set_%d() { return this.g_acc = 1; }\n",
22386 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22387 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22388 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22391 // build source string
22392 i::ScopedVector<char> source(1000);
22395 "%s\n" // wrap functions
22396 "function wrap_f() { return wrap_f_%d(); }\n"
22397 "function wrap_get() { return wrap_get_%d(); }\n"
22398 "function wrap_set() { return wrap_set_%d(); }\n"
22399 "check = function(returned) {\n"
22400 " if (returned !== 'returned') { throw returned; }\n"
22403 "check(wrap_f());\n"
22404 "check(wrap_f());\n"
22405 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22406 "check(wrap_f());\n"
22408 "check(wrap_get());\n"
22409 "check(wrap_get());\n"
22410 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22411 "check(wrap_get());\n"
22413 "check = function(returned) {\n"
22414 " if (returned !== 1) { throw returned; }\n"
22416 "check(wrap_set());\n"
22417 "check(wrap_set());\n"
22418 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22419 "check(wrap_set());\n",
22420 wrap_function.start(), key, key, key, key, key, key);
22421 v8::TryCatch try_catch;
22422 CompileRun(source.start());
22423 DCHECK(!try_catch.HasCaught());
22424 CHECK_EQ(9, count);
22429 Local<Object> ApiCallOptimizationChecker::data;
22430 Local<Object> ApiCallOptimizationChecker::receiver;
22431 Local<Object> ApiCallOptimizationChecker::holder;
22432 Local<Object> ApiCallOptimizationChecker::callee;
22433 int ApiCallOptimizationChecker::count = 0;
22436 TEST(TestFunctionCallOptimization) {
22437 i::FLAG_allow_natives_syntax = true;
22438 ApiCallOptimizationChecker checker;
22443 static const char* last_event_message;
22444 static int last_event_status;
22445 void StoringEventLoggerCallback(const char* message, int status) {
22446 last_event_message = message;
22447 last_event_status = status;
22451 TEST(EventLogging) {
22452 v8::Isolate* isolate = CcTest::isolate();
22453 isolate->SetEventLogger(StoringEventLoggerCallback);
22454 v8::internal::HistogramTimer histogramTimer(
22455 "V8.Test", 0, 10000, 50,
22456 reinterpret_cast<v8::internal::Isolate*>(isolate));
22457 histogramTimer.Start();
22458 CHECK_EQ("V8.Test", last_event_message);
22459 CHECK_EQ(0, last_event_status);
22460 histogramTimer.Stop();
22461 CHECK_EQ("V8.Test", last_event_message);
22462 CHECK_EQ(1, last_event_status);
22467 LocalContext context;
22468 v8::Isolate* isolate = context->GetIsolate();
22469 v8::HandleScope scope(isolate);
22470 Handle<Object> global = context->Global();
22473 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22474 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22475 Handle<v8::Promise> p = pr->GetPromise();
22476 Handle<v8::Promise> r = rr->GetPromise();
22478 // IsPromise predicate.
22479 CHECK(p->IsPromise());
22480 CHECK(r->IsPromise());
22481 Handle<Value> o = v8::Object::New(isolate);
22482 CHECK(!o->IsPromise());
22484 // Resolution and rejection.
22485 pr->Resolve(v8::Integer::New(isolate, 1));
22486 CHECK(p->IsPromise());
22487 rr->Reject(v8::Integer::New(isolate, 2));
22488 CHECK(r->IsPromise());
22490 // Chaining non-pending promises.
22494 "function f1(x) { x1 = x; return x+1 };\n"
22495 "function f2(x) { x2 = x; return x+1 };\n");
22496 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22497 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22500 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22501 isolate->RunMicrotasks();
22502 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22505 isolate->RunMicrotasks();
22506 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22509 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22510 isolate->RunMicrotasks();
22511 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22514 isolate->RunMicrotasks();
22515 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22517 // Chaining pending promises.
22518 CompileRun("x1 = x2 = 0;");
22519 pr = v8::Promise::Resolver::New(isolate);
22520 rr = v8::Promise::Resolver::New(isolate);
22522 pr->GetPromise()->Chain(f1);
22523 rr->GetPromise()->Catch(f2);
22524 isolate->RunMicrotasks();
22525 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22526 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22528 pr->Resolve(v8::Integer::New(isolate, 1));
22529 rr->Reject(v8::Integer::New(isolate, 2));
22530 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22531 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22533 isolate->RunMicrotasks();
22534 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22535 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22538 CompileRun("x1 = x2 = 0;");
22539 pr = v8::Promise::Resolver::New(isolate);
22540 pr->GetPromise()->Chain(f1)->Chain(f2);
22541 pr->Resolve(v8::Integer::New(isolate, 3));
22542 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22543 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22544 isolate->RunMicrotasks();
22545 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22546 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22548 CompileRun("x1 = x2 = 0;");
22549 rr = v8::Promise::Resolver::New(isolate);
22550 rr->GetPromise()->Catch(f1)->Chain(f2);
22551 rr->Reject(v8::Integer::New(isolate, 3));
22552 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22553 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22554 isolate->RunMicrotasks();
22555 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22556 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22560 TEST(PromiseThen) {
22561 LocalContext context;
22562 v8::Isolate* isolate = context->GetIsolate();
22563 v8::HandleScope scope(isolate);
22564 Handle<Object> global = context->Global();
22567 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22568 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22569 Handle<v8::Promise> p = pr->GetPromise();
22570 Handle<v8::Promise> q = qr->GetPromise();
22572 CHECK(p->IsPromise());
22573 CHECK(q->IsPromise());
22575 pr->Resolve(v8::Integer::New(isolate, 1));
22578 // Chaining non-pending promises.
22582 "function f1(x) { x1 = x; return x+1 };\n"
22583 "function f2(x) { x2 = x; return x+1 };\n");
22584 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22585 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22589 CHECK(global->Get(v8_str("x1"))->IsNumber());
22590 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22591 isolate->RunMicrotasks();
22592 CHECK(!global->Get(v8_str("x1"))->IsNumber());
22593 CHECK_EQ(p, global->Get(v8_str("x1")));
22596 CompileRun("x1 = x2 = 0;");
22598 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22599 isolate->RunMicrotasks();
22600 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22603 CompileRun("x1 = x2 = 0;");
22604 pr = v8::Promise::Resolver::New(isolate);
22605 qr = v8::Promise::Resolver::New(isolate);
22608 qr->GetPromise()->Then(f1)->Then(f2);
22610 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22611 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22612 isolate->RunMicrotasks();
22613 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22614 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22616 pr->Resolve(v8::Integer::New(isolate, 3));
22618 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22619 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22620 isolate->RunMicrotasks();
22621 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22622 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22626 TEST(DisallowJavascriptExecutionScope) {
22627 LocalContext context;
22628 v8::Isolate* isolate = context->GetIsolate();
22629 v8::HandleScope scope(isolate);
22630 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22631 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22636 TEST(AllowJavascriptExecutionScope) {
22637 LocalContext context;
22638 v8::Isolate* isolate = context->GetIsolate();
22639 v8::HandleScope scope(isolate);
22640 v8::Isolate::DisallowJavascriptExecutionScope no_js(
22641 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22642 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22643 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22644 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22650 TEST(ThrowOnJavascriptExecution) {
22651 LocalContext context;
22652 v8::Isolate* isolate = context->GetIsolate();
22653 v8::HandleScope scope(isolate);
22654 v8::TryCatch try_catch;
22655 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22656 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22658 CHECK(try_catch.HasCaught());
22662 TEST(Regress354123) {
22663 LocalContext current;
22664 v8::Isolate* isolate = current->GetIsolate();
22665 v8::HandleScope scope(isolate);
22667 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22668 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22669 current->Global()->Set(v8_str("friend"), templ->NewInstance());
22671 // Test access using __proto__ from the prototype chain.
22672 named_access_count = 0;
22673 CompileRun("friend.__proto__ = {};");
22674 CHECK_EQ(2, named_access_count);
22675 CompileRun("friend.__proto__;");
22676 CHECK_EQ(4, named_access_count);
22678 // Test access using __proto__ as a hijacked function (A).
22679 named_access_count = 0;
22680 CompileRun("var p = Object.prototype;"
22681 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22682 "f.call(friend, {});");
22683 CHECK_EQ(1, named_access_count);
22684 CompileRun("var p = Object.prototype;"
22685 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22686 "f.call(friend);");
22687 CHECK_EQ(2, named_access_count);
22689 // Test access using __proto__ as a hijacked function (B).
22690 named_access_count = 0;
22691 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22692 "f.call(friend, {});");
22693 CHECK_EQ(1, named_access_count);
22694 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22695 "f.call(friend);");
22696 CHECK_EQ(2, named_access_count);
22698 // Test access using Object.setPrototypeOf reflective method.
22699 named_access_count = 0;
22700 CompileRun("Object.setPrototypeOf(friend, {});");
22701 CHECK_EQ(1, named_access_count);
22702 CompileRun("Object.getPrototypeOf(friend);");
22703 CHECK_EQ(2, named_access_count);
22707 TEST(CaptureStackTraceForStackOverflow) {
22708 v8::internal::FLAG_stack_size = 150;
22709 LocalContext current;
22710 v8::Isolate* isolate = current->GetIsolate();
22711 v8::HandleScope scope(isolate);
22712 V8::SetCaptureStackTraceForUncaughtExceptions(
22713 true, 10, v8::StackTrace::kDetailed);
22714 v8::TryCatch try_catch;
22715 CompileRun("(function f(x) { f(x+1); })(0)");
22716 CHECK(try_catch.HasCaught());
22720 TEST(ScriptNameAndLineNumber) {
22722 v8::Isolate* isolate = env->GetIsolate();
22723 v8::HandleScope scope(isolate);
22724 const char* url = "http://www.foo.com/foo.js";
22725 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22726 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22727 Local<Script> script = v8::ScriptCompiler::Compile(
22728 isolate, &script_source);
22729 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22730 CHECK(!script_name.IsEmpty());
22731 CHECK(script_name->IsString());
22732 String::Utf8Value utf8_name(script_name);
22733 CHECK_EQ(url, *utf8_name);
22734 int line_number = script->GetUnboundScript()->GetLineNumber(0);
22735 CHECK_EQ(13, line_number);
22739 void SourceURLHelper(const char* source, const char* expected_source_url,
22740 const char* expected_source_mapping_url) {
22741 Local<Script> script = v8_compile(source);
22742 if (expected_source_url != NULL) {
22743 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22744 CHECK_EQ(expected_source_url, *url);
22746 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22748 if (expected_source_mapping_url != NULL) {
22749 v8::String::Utf8Value url(
22750 script->GetUnboundScript()->GetSourceMappingURL());
22751 CHECK_EQ(expected_source_mapping_url, *url);
22753 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22758 TEST(ScriptSourceURLAndSourceMappingURL) {
22760 v8::Isolate* isolate = env->GetIsolate();
22761 v8::HandleScope scope(isolate);
22762 SourceURLHelper("function foo() {}\n"
22763 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22764 SourceURLHelper("function foo() {}\n"
22765 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22767 // Both sourceURL and sourceMappingURL.
22768 SourceURLHelper("function foo() {}\n"
22769 "//# sourceURL=bar3.js\n"
22770 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
22772 // Two source URLs; the first one is ignored.
22773 SourceURLHelper("function foo() {}\n"
22774 "//# sourceURL=ignoreme.js\n"
22775 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
22776 SourceURLHelper("function foo() {}\n"
22777 "//# sourceMappingURL=ignoreme.js\n"
22778 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
22780 // SourceURL or sourceMappingURL in the middle of the script.
22781 SourceURLHelper("function foo() {}\n"
22782 "//# sourceURL=bar7.js\n"
22783 "function baz() {}\n", "bar7.js", NULL);
22784 SourceURLHelper("function foo() {}\n"
22785 "//# sourceMappingURL=bar8.js\n"
22786 "function baz() {}\n", NULL, "bar8.js");
22788 // Too much whitespace.
22789 SourceURLHelper("function foo() {}\n"
22790 "//# sourceURL=bar9.js\n"
22791 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
22792 SourceURLHelper("function foo() {}\n"
22793 "//# sourceURL =bar11.js\n"
22794 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
22796 // Disallowed characters in value.
22797 SourceURLHelper("function foo() {}\n"
22798 "//# sourceURL=bar13 .js \n"
22799 "//# sourceMappingURL=bar14 .js \n",
22801 SourceURLHelper("function foo() {}\n"
22802 "//# sourceURL=bar15\t.js \n"
22803 "//# sourceMappingURL=bar16\t.js \n",
22805 SourceURLHelper("function foo() {}\n"
22806 "//# sourceURL=bar17'.js \n"
22807 "//# sourceMappingURL=bar18'.js \n",
22809 SourceURLHelper("function foo() {}\n"
22810 "//# sourceURL=bar19\".js \n"
22811 "//# sourceMappingURL=bar20\".js \n",
22814 // Not too much whitespace.
22815 SourceURLHelper("function foo() {}\n"
22816 "//# sourceURL= bar21.js \n"
22817 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
22821 TEST(GetOwnPropertyDescriptor) {
22823 v8::Isolate* isolate = env->GetIsolate();
22824 v8::HandleScope scope(isolate);
22826 "var x = { value : 13};"
22827 "Object.defineProperty(x, 'p0', {value : 12});"
22828 "Object.defineProperty(x, 'p1', {"
22829 " set : function(value) { this.value = value; },"
22830 " get : function() { return this.value; },"
22832 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
22833 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
22834 CHECK(desc->IsUndefined());
22835 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
22836 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
22837 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
22838 Local<Function> set =
22839 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
22840 Local<Function> get =
22841 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
22842 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
22843 Handle<Value> args[] = { v8_num(14) };
22844 set->Call(x, 1, args);
22845 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));