blob: 800cc8be690fa0f49a67a7c936945e42037740a9 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2007-2008 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
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.
15//
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.
27
28#include <map>
29#include <string>
30
31#include "v8.h"
32
33#include "api.h"
34#include "snapshot.h"
35#include "platform.h"
36#include "top.h"
37#include "cctest.h"
38
39static bool IsNaN(double x) {
40#ifdef WIN32
41 return _isnan(x);
42#else
43 return isnan(x);
44#endif
45}
46
47using ::v8::ObjectTemplate;
48using ::v8::Value;
49using ::v8::Context;
50using ::v8::Local;
51using ::v8::String;
52using ::v8::Script;
53using ::v8::Function;
54using ::v8::AccessorInfo;
55using ::v8::Extension;
56
57namespace i = ::v8::internal;
58
59static Local<Value> v8_num(double x) {
60 return v8::Number::New(x);
61}
62
63
64static Local<String> v8_str(const char* x) {
65 return String::New(x);
66}
67
68
69static Local<Script> v8_compile(const char* x) {
70 return Script::Compile(v8_str(x));
71}
72
73
74// A LocalContext holds a reference to a v8::Context.
75class LocalContext {
76 public:
77 LocalContext(v8::ExtensionConfiguration* extensions = 0,
78 v8::Handle<ObjectTemplate> global_template =
79 v8::Handle<ObjectTemplate>(),
80 v8::Handle<Value> global_object = v8::Handle<Value>())
81 : context_(Context::New(extensions, global_template, global_object)) {
82 context_->Enter();
83 }
84
85 virtual ~LocalContext() {
86 context_->Exit();
87 context_.Dispose();
88 }
89
90 Context* operator->() { return *context_; }
91 Context* operator*() { return *context_; }
92 Local<Context> local() { return Local<Context>::New(context_); }
93 bool IsReady() { return !context_.IsEmpty(); }
94
95 private:
96 v8::Persistent<Context> context_;
97};
98
99
100// Switches between all the Api tests using the threading support.
101// In order to get a surprising but repeatable pattern of thread
102// switching it has extra semaphores to control the order in which
103// the tests alternate, not relying solely on the big V8 lock.
104//
105// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
106// callbacks. This will have no effect when we are not running the
107// thread fuzzing test. In the thread fuzzing test it will
108// pseudorandomly select a successor thread and switch execution
109// to that thread, suspending the current test.
110class ApiTestFuzzer: public v8::internal::Thread {
111 public:
112 void CallTest();
113 explicit ApiTestFuzzer(int num)
114 : test_number_(num),
115 gate_(v8::internal::OS::CreateSemaphore(0)),
116 active_(true) {
117 }
118
119 // The ApiTestFuzzer is also a Thread, so it has a Run method.
120 virtual void Run();
121
122 enum PartOfTest { FIRST_PART, SECOND_PART };
123
124 static void Setup(PartOfTest part);
125 static void RunAllTests();
126 static void TearDown();
127 // This method switches threads if we are running the Threading test.
128 // Otherwise it does nothing.
129 static void Fuzz();
130 private:
131 static bool fuzzing_;
132 static int tests_being_run_;
133 static int current_;
134 static int active_tests_;
135 static bool NextThread();
136 int test_number_;
137 v8::internal::Semaphore* gate_;
138 bool active_;
139 void ContextSwitch();
140 static int GetNextTestNumber();
141 static v8::internal::Semaphore* all_tests_done_;
142};
143
144
145#define THREADED_TEST(Name) \
146 static void Test##Name(); \
147 RegisterThreadedTest register_##Name(Test##Name); \
148 /* */ TEST(Name)
149
150
151class RegisterThreadedTest {
152 public:
153 explicit RegisterThreadedTest(CcTest::TestFunction* callback)
154 : callback_(callback) {
155 prev_ = first_;
156 first_ = this;
157 count_++;
158 }
159 static int count() { return count_; }
160 static RegisterThreadedTest* nth(int i) {
161 ASSERT(i < count());
162 RegisterThreadedTest* current = first_;
163 while (i > 0) {
164 i--;
165 current = current->prev_;
166 }
167 return current;
168 }
169 CcTest::TestFunction* callback() { return callback_; }
170 ApiTestFuzzer* fuzzer_;
171
172 private:
173 static RegisterThreadedTest* first_;
174 static int count_;
175 CcTest::TestFunction* callback_;
176 RegisterThreadedTest* prev_;
177};
178
179
180RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
181int RegisterThreadedTest::count_ = 0;
182
183
184static int signature_callback_count;
185static v8::Handle<Value> IncrementingSignatureCallback(
186 const v8::Arguments& args) {
187 ApiTestFuzzer::Fuzz();
188 signature_callback_count++;
189 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
190 for (int i = 0; i < args.Length(); i++)
191 result->Set(v8::Integer::New(i), args[i]);
192 return result;
193}
194
195
196static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
197 ApiTestFuzzer::Fuzz();
198 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
199 for (int i = 0; i < args.Length(); i++) {
200 result->Set(v8::Integer::New(i), args[i]);
201 }
202 return result;
203}
204
205
206THREADED_TEST(Handles) {
207 v8::HandleScope scope;
208 Local<Context> local_env;
209 {
210 LocalContext env;
211 local_env = env.local();
212 }
213
214 // Local context should still be live.
215 CHECK(!local_env.IsEmpty());
216 local_env->Enter();
217
218 v8::Handle<v8::Primitive> undef = v8::Undefined();
219 CHECK(!undef.IsEmpty());
220 CHECK(undef->IsUndefined());
221
222 const char* c_source = "1 + 2 + 3";
223 Local<String> source = String::New(c_source);
224 Local<Script> script = Script::Compile(source);
225 CHECK_EQ(6, script->Run()->Int32Value());
226
227 local_env->Exit();
228}
229
230
231// Helper function that compiles and runs the source.
232static Local<Value> CompileRun(const char* source) {
233 return Script::Compile(String::New(source))->Run();
234}
235
236THREADED_TEST(ReceiverSignature) {
237 v8::HandleScope scope;
238 LocalContext env;
239 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
240 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
241 fun->PrototypeTemplate()->Set(
242 v8_str("m"),
243 v8::FunctionTemplate::New(IncrementingSignatureCallback,
244 v8::Handle<Value>(),
245 sig));
246 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
247 signature_callback_count = 0;
248 CompileRun(
249 "var o = new Fun();"
250 "o.m();");
251 CHECK_EQ(1, signature_callback_count);
252 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
253 sub_fun->Inherit(fun);
254 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
255 CompileRun(
256 "var o = new SubFun();"
257 "o.m();");
258 CHECK_EQ(2, signature_callback_count);
259
260 v8::TryCatch try_catch;
261 CompileRun(
262 "var o = { };"
263 "o.m = Fun.prototype.m;"
264 "o.m();");
265 CHECK_EQ(2, signature_callback_count);
266 CHECK(try_catch.HasCaught());
267 try_catch.Reset();
268 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
269 sub_fun->Inherit(fun);
270 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
271 CompileRun(
272 "var o = new UnrelFun();"
273 "o.m = Fun.prototype.m;"
274 "o.m();");
275 CHECK_EQ(2, signature_callback_count);
276 CHECK(try_catch.HasCaught());
277}
278
279
280
281
282THREADED_TEST(ArgumentSignature) {
283 v8::HandleScope scope;
284 LocalContext env;
285 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
286 cons->SetClassName(v8_str("Cons"));
287 v8::Handle<v8::Signature> sig =
288 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
289 v8::Handle<v8::FunctionTemplate> fun =
290 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
291 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
292 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
293
294 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
295 ASSERT(value1->IsTrue());
296
297 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
298 ASSERT(value2->IsTrue());
299
300 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
301 ASSERT(value3->IsTrue());
302
303 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
304 cons1->SetClassName(v8_str("Cons1"));
305 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
306 cons2->SetClassName(v8_str("Cons2"));
307 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
308 cons3->SetClassName(v8_str("Cons3"));
309
310 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
311 v8::Handle<v8::Signature> wsig =
312 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
313 v8::Handle<v8::FunctionTemplate> fun2 =
314 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
315
316 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
317 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
318 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
319 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
320 v8::Handle<Value> value4 = CompileRun(
321 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
322 "'[object Cons1],[object Cons2],[object Cons3]'");
323 ASSERT(value4->IsTrue());
324
325 v8::Handle<Value> value5 = CompileRun(
326 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
327 ASSERT(value5->IsTrue());
328
329 v8::Handle<Value> value6 = CompileRun(
330 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
331 ASSERT(value6->IsTrue());
332
333 v8::Handle<Value> value7 = CompileRun(
334 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
335 "'[object Cons1],[object Cons2],[object Cons3],d';");
336 ASSERT(value7->IsTrue());
337
338 v8::Handle<Value> value8 = CompileRun(
339 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
340 ASSERT(value8->IsTrue());
341}
342
343
344THREADED_TEST(HulIgennem) {
345 v8::HandleScope scope;
346 LocalContext env;
347 v8::Handle<v8::Primitive> undef = v8::Undefined();
348 Local<String> undef_str = undef->ToString();
349 char* value = i::NewArray<char>(undef_str->Length() + 1);
350 undef_str->WriteAscii(value);
351 CHECK_EQ(0, strcmp(value, "undefined"));
352 i::DeleteArray(value);
353}
354
355
356THREADED_TEST(Access) {
357 v8::HandleScope scope;
358 LocalContext env;
359 Local<v8::Object> obj = v8::Object::New();
360 Local<Value> foo_before = obj->Get(v8_str("foo"));
361 CHECK(foo_before->IsUndefined());
362 Local<String> bar_str = v8_str("bar");
363 obj->Set(v8_str("foo"), bar_str);
364 Local<Value> foo_after = obj->Get(v8_str("foo"));
365 CHECK(!foo_after->IsUndefined());
366 CHECK(foo_after->IsString());
367 CHECK_EQ(bar_str, foo_after);
368}
369
370
371THREADED_TEST(Script) {
372 v8::HandleScope scope;
373 LocalContext env;
374 const char* c_source = "1 + 2 + 3";
375 Local<String> source = String::New(c_source);
376 Local<Script> script = Script::Compile(source);
377 CHECK_EQ(6, script->Run()->Int32Value());
378}
379
380
381static uint16_t* AsciiToTwoByteString(const char* source) {
382 size_t array_length = strlen(source) + 1;
383 uint16_t* converted = i::NewArray<uint16_t>(array_length);
384 for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
385 return converted;
386}
387
388
389class TestResource: public String::ExternalStringResource {
390 public:
391 static int dispose_count;
392
393 explicit TestResource(uint16_t* data)
394 : data_(data), length_(0) {
395 while (data[length_]) ++length_;
396 }
397
398 ~TestResource() {
399 i::DeleteArray(data_);
400 ++dispose_count;
401 }
402
403 const uint16_t* data() const {
404 return data_;
405 }
406
407 size_t length() const {
408 return length_;
409 }
410 private:
411 uint16_t* data_;
412 size_t length_;
413};
414
415
416int TestResource::dispose_count = 0;
417
418
419class TestAsciiResource: public String::ExternalAsciiStringResource {
420 public:
421 static int dispose_count;
422
423 explicit TestAsciiResource(char* data)
424 : data_(data),
425 length_(strlen(data)) { }
426
427 ~TestAsciiResource() {
428 i::DeleteArray(data_);
429 ++dispose_count;
430 }
431
432 const char* data() const {
433 return data_;
434 }
435
436 size_t length() const {
437 return length_;
438 }
439 private:
440 char* data_;
441 size_t length_;
442};
443
444
445int TestAsciiResource::dispose_count = 0;
446
447
448THREADED_TEST(ScriptUsingStringResource) {
449 TestResource::dispose_count = 0;
450 const char* c_source = "1 + 2 * 3";
451 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
452 {
453 v8::HandleScope scope;
454 LocalContext env;
455 TestResource* resource = new TestResource(two_byte_source);
456 Local<String> source = String::NewExternal(resource);
457 Local<Script> script = Script::Compile(source);
458 Local<Value> value = script->Run();
459 CHECK(value->IsNumber());
460 CHECK_EQ(7, value->Int32Value());
461 CHECK(source->IsExternal());
462 CHECK_EQ(resource,
463 static_cast<TestResource*>(source->GetExternalStringResource()));
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000464 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000465 CHECK_EQ(0, TestResource::dispose_count);
466 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000467 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000468 CHECK_EQ(1, TestResource::dispose_count);
469}
470
471
472THREADED_TEST(ScriptUsingAsciiStringResource) {
473 TestAsciiResource::dispose_count = 0;
474 const char* c_source = "1 + 2 * 3";
475 {
476 v8::HandleScope scope;
477 LocalContext env;
478 Local<String> source =
479 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
480 Local<Script> script = Script::Compile(source);
481 Local<Value> value = script->Run();
482 CHECK(value->IsNumber());
483 CHECK_EQ(7, value->Int32Value());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000484 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000485 CHECK_EQ(0, TestAsciiResource::dispose_count);
486 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000487 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000488 CHECK_EQ(1, TestAsciiResource::dispose_count);
489}
490
491
492THREADED_TEST(GlobalProperties) {
493 v8::HandleScope scope;
494 LocalContext env;
495 v8::Handle<v8::Object> global = env->Global();
496 global->Set(v8_str("pi"), v8_num(3.1415926));
497 Local<Value> pi = global->Get(v8_str("pi"));
498 CHECK_EQ(3.1415926, pi->NumberValue());
499}
500
501
502static v8::Handle<Value> handle_call(const v8::Arguments& args) {
503 ApiTestFuzzer::Fuzz();
504 return v8_num(102);
505}
506
507
508static v8::Handle<Value> construct_call(const v8::Arguments& args) {
509 ApiTestFuzzer::Fuzz();
510 args.This()->Set(v8_str("x"), v8_num(1));
511 args.This()->Set(v8_str("y"), v8_num(2));
512 return args.This();
513}
514
515THREADED_TEST(FunctionTemplate) {
516 v8::HandleScope scope;
517 LocalContext env;
518 {
519 Local<v8::FunctionTemplate> fun_templ =
520 v8::FunctionTemplate::New(handle_call);
521 Local<Function> fun = fun_templ->GetFunction();
522 env->Global()->Set(v8_str("obj"), fun);
523 Local<Script> script = v8_compile("obj()");
524 CHECK_EQ(102, script->Run()->Int32Value());
525 }
526 // Use SetCallHandler to initialize a function template, should work like the
527 // previous one.
528 {
529 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
530 fun_templ->SetCallHandler(handle_call);
531 Local<Function> fun = fun_templ->GetFunction();
532 env->Global()->Set(v8_str("obj"), fun);
533 Local<Script> script = v8_compile("obj()");
534 CHECK_EQ(102, script->Run()->Int32Value());
535 }
536 // Test constructor calls.
537 {
538 Local<v8::FunctionTemplate> fun_templ =
539 v8::FunctionTemplate::New(construct_call);
540 fun_templ->SetClassName(v8_str("funky"));
541 Local<Function> fun = fun_templ->GetFunction();
542 env->Global()->Set(v8_str("obj"), fun);
543 Local<Script> script = v8_compile("var s = new obj(); s.x");
544 CHECK_EQ(1, script->Run()->Int32Value());
545
546 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
547 CHECK_EQ(v8_str("[object funky]"), result);
548 }
549}
550
551
552static v8::Handle<Value> handle_property(Local<String> name,
553 const AccessorInfo&) {
554 ApiTestFuzzer::Fuzz();
555 return v8_num(900);
556}
557
558
559THREADED_TEST(PropertyHandler) {
560 v8::HandleScope scope;
561 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
562 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
563 LocalContext env;
564 Local<Function> fun = fun_templ->GetFunction();
565 env->Global()->Set(v8_str("Fun"), fun);
566 Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
567 CHECK_EQ(900, getter->Run()->Int32Value());
568 Local<Script> setter = v8_compile("obj.foo = 901;");
569 CHECK_EQ(901, setter->Run()->Int32Value());
570}
571
572
573THREADED_TEST(Number) {
574 v8::HandleScope scope;
575 LocalContext env;
576 double PI = 3.1415926;
577 Local<v8::Number> pi_obj = v8::Number::New(PI);
578 CHECK_EQ(PI, pi_obj->NumberValue());
579}
580
581
582THREADED_TEST(ToNumber) {
583 v8::HandleScope scope;
584 LocalContext env;
585 Local<String> str = v8_str("3.1415926");
586 CHECK_EQ(3.1415926, str->NumberValue());
587 v8::Handle<v8::Boolean> t = v8::True();
588 CHECK_EQ(1.0, t->NumberValue());
589 v8::Handle<v8::Boolean> f = v8::False();
590 CHECK_EQ(0.0, f->NumberValue());
591}
592
593
594THREADED_TEST(Date) {
595 v8::HandleScope scope;
596 LocalContext env;
597 double PI = 3.1415926;
598 Local<Value> date_obj = v8::Date::New(PI);
599 CHECK_EQ(3.0, date_obj->NumberValue());
600}
601
602
603THREADED_TEST(Boolean) {
604 v8::HandleScope scope;
605 LocalContext env;
606 v8::Handle<v8::Boolean> t = v8::True();
607 CHECK(t->Value());
608 v8::Handle<v8::Boolean> f = v8::False();
609 CHECK(!f->Value());
610 v8::Handle<v8::Primitive> u = v8::Undefined();
611 CHECK(!u->BooleanValue());
612 v8::Handle<v8::Primitive> n = v8::Null();
613 CHECK(!n->BooleanValue());
614 v8::Handle<String> str1 = v8_str("");
615 CHECK(!str1->BooleanValue());
616 v8::Handle<String> str2 = v8_str("x");
617 CHECK(str2->BooleanValue());
618 CHECK(!v8::Number::New(0)->BooleanValue());
619 CHECK(v8::Number::New(-1)->BooleanValue());
620 CHECK(v8::Number::New(1)->BooleanValue());
621 CHECK(v8::Number::New(42)->BooleanValue());
622 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
623}
624
625
626static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
627 ApiTestFuzzer::Fuzz();
628 return v8_num(13.4);
629}
630
631
632static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
633 ApiTestFuzzer::Fuzz();
634 return v8_num(876);
635}
636
637
638THREADED_TEST(GlobalPrototype) {
639 v8::HandleScope scope;
640 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
641 func_templ->PrototypeTemplate()->Set(
642 "dummy",
643 v8::FunctionTemplate::New(DummyCallHandler));
644 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
645 templ->Set("x", v8_num(200));
646 templ->SetAccessor(v8_str("m"), GetM);
647 LocalContext env(0, templ);
648 v8::Handle<v8::Object> obj = env->Global();
649 v8::Handle<Script> script = v8_compile("dummy()");
650 v8::Handle<Value> result = script->Run();
651 CHECK_EQ(13.4, result->NumberValue());
652 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
653 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
654}
655
656
657static v8::Handle<Value> GetIntValue(Local<String> property,
658 const AccessorInfo& info) {
659 ApiTestFuzzer::Fuzz();
660 int* value =
661 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
662 return v8_num(*value);
663}
664
665static void SetIntValue(Local<String> property,
666 Local<Value> value,
667 const AccessorInfo& info) {
668 int* field =
669 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
670 *field = value->Int32Value();
671}
672
673int foo, bar, baz;
674
675THREADED_TEST(GlobalVariableAccess) {
676 foo = 0;
677 bar = -4;
678 baz = 10;
679 v8::HandleScope scope;
680 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
681 templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
682 GetIntValue,
683 SetIntValue,
684 v8::External::New(&foo));
685 templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
686 GetIntValue,
687 SetIntValue,
688 v8::External::New(&bar));
689 templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
690 GetIntValue,
691 SetIntValue,
692 v8::External::New(&baz));
693 LocalContext env(0, templ->InstanceTemplate());
694 v8_compile("foo = (++bar) + baz")->Run();
695 CHECK_EQ(bar, -3);
696 CHECK_EQ(foo, 7);
697}
698
699
700THREADED_TEST(ObjectTemplate) {
701 v8::HandleScope scope;
702 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
703 templ1->Set("x", v8_num(10));
704 templ1->Set("y", v8_num(13));
705 LocalContext env;
706 Local<v8::Object> instance1 = templ1->NewInstance();
707 env->Global()->Set(v8_str("p"), instance1);
708 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
709 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
710 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
711 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
712 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
713 templ2->Set("a", v8_num(12));
714 templ2->Set("b", templ1);
715 Local<v8::Object> instance2 = templ2->NewInstance();
716 env->Global()->Set(v8_str("q"), instance2);
717 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
718 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
719 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
720 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
721}
722
723
724static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
725 ApiTestFuzzer::Fuzz();
726 return v8_num(17.2);
727}
728
729
730static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
731 ApiTestFuzzer::Fuzz();
732 return v8_num(15.2);
733}
734
735
736THREADED_TEST(DescriptorInheritance) {
737 v8::HandleScope scope;
738 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
739 super->PrototypeTemplate()->Set("flabby",
740 v8::FunctionTemplate::New(GetFlabby));
741 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
742
743 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
744
745 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
746 base1->Inherit(super);
747 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
748
749 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
750 base2->Inherit(super);
751 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
752
753 LocalContext env;
754
755 env->Global()->Set(v8_str("s"), super->GetFunction());
756 env->Global()->Set(v8_str("base1"), base1->GetFunction());
757 env->Global()->Set(v8_str("base2"), base2->GetFunction());
758
759 // Checks right __proto__ chain.
760 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
761 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
762
763 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
764
765 // Instance accessor should not be visible on function object or its prototype
766 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
767 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
768 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
769
770 env->Global()->Set(v8_str("obj"),
771 base1->GetFunction()->NewInstance());
772 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
773 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
774 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
775 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
776 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
777
778 env->Global()->Set(v8_str("obj2"),
779 base2->GetFunction()->NewInstance());
780 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
781 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
782 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
783 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
784 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
785
786 // base1 and base2 cannot cross reference to each's prototype
787 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
788 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
789}
790
791
792int echo_named_call_count;
793
794
795static v8::Handle<Value> EchoNamedProperty(Local<String> name,
796 const AccessorInfo& info) {
797 ApiTestFuzzer::Fuzz();
798 CHECK_EQ(v8_str("data"), info.Data());
799 echo_named_call_count++;
800 return name;
801}
802
803
804THREADED_TEST(NamedPropertyHandlerGetter) {
805 echo_named_call_count = 0;
806 v8::HandleScope scope;
807 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
808 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
809 0, 0, 0, 0,
810 v8_str("data"));
811 LocalContext env;
812 env->Global()->Set(v8_str("obj"),
813 templ->GetFunction()->NewInstance());
814 CHECK_EQ(echo_named_call_count, 0);
815 v8_compile("obj.x")->Run();
816 CHECK_EQ(echo_named_call_count, 1);
817 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
818 v8::Handle<Value> str = CompileRun(code);
819 String::AsciiValue value(str);
820 CHECK_EQ(*value, "oddlepoddle");
821 // Check default behavior
822 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
823 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
824 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
825}
826
827
828int echo_indexed_call_count = 0;
829
830
831static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
832 const AccessorInfo& info) {
833 ApiTestFuzzer::Fuzz();
834 CHECK_EQ(v8_num(637), info.Data());
835 echo_indexed_call_count++;
836 return v8_num(index);
837}
838
839
840THREADED_TEST(IndexedPropertyHandlerGetter) {
841 v8::HandleScope scope;
842 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
843 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
844 0, 0, 0, 0,
845 v8_num(637));
846 LocalContext env;
847 env->Global()->Set(v8_str("obj"),
848 templ->GetFunction()->NewInstance());
849 Local<Script> script = v8_compile("obj[900]");
850 CHECK_EQ(script->Run()->Int32Value(), 900);
851}
852
853
854v8::Handle<v8::Object> bottom;
855
856static v8::Handle<Value> CheckThisIndexedPropertyHandler(
857 uint32_t index,
858 const AccessorInfo& info) {
859 ApiTestFuzzer::Fuzz();
860 CHECK(info.This()->Equals(bottom));
861 return v8::Handle<Value>();
862}
863
864static v8::Handle<Value> CheckThisNamedPropertyHandler(
865 Local<String> name,
866 const AccessorInfo& info) {
867 ApiTestFuzzer::Fuzz();
868 CHECK(info.This()->Equals(bottom));
869 return v8::Handle<Value>();
870}
871
872
873v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
874 Local<Value> value,
875 const AccessorInfo& info) {
876 ApiTestFuzzer::Fuzz();
877 CHECK(info.This()->Equals(bottom));
878 return v8::Handle<Value>();
879}
880
881
882v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
883 Local<Value> value,
884 const AccessorInfo& info) {
885 ApiTestFuzzer::Fuzz();
886 CHECK(info.This()->Equals(bottom));
887 return v8::Handle<Value>();
888}
889
890v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
891 uint32_t index,
892 const AccessorInfo& info) {
893 ApiTestFuzzer::Fuzz();
894 CHECK(info.This()->Equals(bottom));
895 return v8::Handle<v8::Boolean>();
896}
897
898
899v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
900 const AccessorInfo& info) {
901 ApiTestFuzzer::Fuzz();
902 CHECK(info.This()->Equals(bottom));
903 return v8::Handle<v8::Boolean>();
904}
905
906
907v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
908 uint32_t index,
909 const AccessorInfo& info) {
910 ApiTestFuzzer::Fuzz();
911 CHECK(info.This()->Equals(bottom));
912 return v8::Handle<v8::Boolean>();
913}
914
915
916v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
917 Local<String> property,
918 const AccessorInfo& info) {
919 ApiTestFuzzer::Fuzz();
920 CHECK(info.This()->Equals(bottom));
921 return v8::Handle<v8::Boolean>();
922}
923
924
925v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
926 const AccessorInfo& info) {
927 ApiTestFuzzer::Fuzz();
928 CHECK(info.This()->Equals(bottom));
929 return v8::Handle<v8::Array>();
930}
931
932
933v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
934 const AccessorInfo& info) {
935 ApiTestFuzzer::Fuzz();
936 CHECK(info.This()->Equals(bottom));
937 return v8::Handle<v8::Array>();
938}
939
940
941THREADED_TEST(PropertyHandlerInPrototype) {
942 v8::HandleScope scope;
943 LocalContext env;
944
945 // Set up a prototype chain with three interceptors.
946 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
947 templ->InstanceTemplate()->SetIndexedPropertyHandler(
948 CheckThisIndexedPropertyHandler,
949 CheckThisIndexedPropertySetter,
950 CheckThisIndexedPropertyQuery,
951 CheckThisIndexedPropertyDeleter,
952 CheckThisIndexedPropertyEnumerator);
953
954 templ->InstanceTemplate()->SetNamedPropertyHandler(
955 CheckThisNamedPropertyHandler,
956 CheckThisNamedPropertySetter,
957 CheckThisNamedPropertyQuery,
958 CheckThisNamedPropertyDeleter,
959 CheckThisNamedPropertyEnumerator);
960
961 bottom = templ->GetFunction()->NewInstance();
962 Local<v8::Object> top = templ->GetFunction()->NewInstance();
963 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
964
965 bottom->Set(v8_str("__proto__"), middle);
966 middle->Set(v8_str("__proto__"), top);
967 env->Global()->Set(v8_str("obj"), bottom);
968
969 // Indexed and named get.
970 Script::Compile(v8_str("obj[0]"))->Run();
971 Script::Compile(v8_str("obj.x"))->Run();
972
973 // Indexed and named set.
974 Script::Compile(v8_str("obj[1] = 42"))->Run();
975 Script::Compile(v8_str("obj.y = 42"))->Run();
976
977 // Indexed and named query.
978 Script::Compile(v8_str("0 in obj"))->Run();
979 Script::Compile(v8_str("'x' in obj"))->Run();
980
981 // Indexed and named deleter.
982 Script::Compile(v8_str("delete obj[0]"))->Run();
983 Script::Compile(v8_str("delete obj.x"))->Run();
984
985 // Enumerators.
986 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
987}
988
989
990v8::Handle<Value> pre_post_global;
991
992static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
993 const AccessorInfo& info) {
994 ApiTestFuzzer::Fuzz();
995 CHECK(info.This()->Equals(pre_post_global));
996 CHECK(info.Holder()->Equals(pre_post_global));
997 if (v8_str("pre")->Equals(key)) {
998 return v8_str("PrePropertyHandler: pre");
999 }
1000 return v8::Handle<String>();
1001}
1002
1003
1004static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1005 const AccessorInfo&) {
1006 if (v8_str("pre")->Equals(key)) {
1007 return v8::True();
1008 }
1009
1010 return v8::Handle<v8::Boolean>(); // do not intercept the call
1011}
1012
1013
1014THREADED_TEST(PrePropertyHandler) {
1015 v8::HandleScope scope;
1016 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1017 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1018 0,
1019 PrePropertyHandlerHas);
1020 LocalContext env(NULL, desc->InstanceTemplate());
1021 pre_post_global = env->Global();
1022 Script::Compile(v8_str(
1023 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1024 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1025 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1026 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1027 CHECK_EQ(v8_str("Object: on"), result_on);
1028 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1029 CHECK(result_post.IsEmpty());
1030}
1031
1032
1033v8::Handle<Script> call_recursively_script;
1034static const int kTargetRecursionDepth = 300; // near maximum
1035
1036
1037static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1038 ApiTestFuzzer::Fuzz();
1039 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1040 if (depth == kTargetRecursionDepth) return v8::Undefined();
1041 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1042 return call_recursively_script->Run();
1043}
1044
1045
1046static v8::Handle<Value> CallFunctionRecursivelyCall(
1047 const v8::Arguments& args) {
1048 ApiTestFuzzer::Fuzz();
1049 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1050 if (depth == kTargetRecursionDepth) {
1051 printf("[depth = %d]\n", depth);
1052 return v8::Undefined();
1053 }
1054 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1055 v8::Handle<Value> function =
1056 args.This()->Get(v8_str("callFunctionRecursively"));
1057 return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1058}
1059
1060
1061THREADED_TEST(DeepCrossLanguageRecursion) {
1062 v8::HandleScope scope;
1063 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1064 global->Set(v8_str("callScriptRecursively"),
1065 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1066 global->Set(v8_str("callFunctionRecursively"),
1067 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1068 LocalContext env(NULL, global);
1069
1070 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1071 call_recursively_script = v8_compile("callScriptRecursively()");
1072 v8::Handle<Value> result = call_recursively_script->Run();
1073 call_recursively_script = v8::Handle<Script>();
1074
1075 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1076 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1077}
1078
1079
1080static v8::Handle<Value>
1081 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1082 ApiTestFuzzer::Fuzz();
1083 return v8::ThrowException(key);
1084}
1085
1086
1087static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1088 Local<Value>,
1089 const AccessorInfo&) {
1090 v8::ThrowException(key);
1091 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1092}
1093
1094
1095THREADED_TEST(CallbackExceptionRegression) {
1096 v8::HandleScope scope;
1097 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1098 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1099 ThrowingPropertyHandlerSet);
1100 LocalContext env;
1101 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1102 v8::Handle<Value> otto = Script::Compile(v8_str(
1103 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1104 CHECK_EQ(v8_str("otto"), otto);
1105 v8::Handle<Value> netto = Script::Compile(v8_str(
1106 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1107 CHECK_EQ(v8_str("netto"), netto);
1108}
1109
1110
1111static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
1112 const AccessorInfo& info) {
1113 ApiTestFuzzer::Fuzz();
1114 return v8::ThrowException(v8_str("g"));
1115}
1116
1117
1118static void ThrowingSetAccessor(Local<String> name,
1119 Local<Value> value,
1120 const AccessorInfo& info) {
1121 v8::ThrowException(value);
1122}
1123
1124
1125THREADED_TEST(Regress1054726) {
1126 v8::HandleScope scope;
1127 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1128 obj->SetAccessor(v8_str("x"),
1129 ThrowingGetAccessor,
1130 ThrowingSetAccessor,
1131 Local<Value>());
1132
1133 LocalContext env;
1134 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1135
1136 // Use the throwing property setter/getter in a loop to force
1137 // the accessor ICs to be initialized.
1138 v8::Handle<Value> result;
1139 result = Script::Compile(v8_str(
1140 "var result = '';"
1141 "for (var i = 0; i < 5; i++) {"
1142 " try { obj.x; } catch (e) { result += e; }"
1143 "}; result"))->Run();
1144 CHECK_EQ(v8_str("ggggg"), result);
1145
1146 result = Script::Compile(String::New(
1147 "var result = '';"
1148 "for (var i = 0; i < 5; i++) {"
1149 " try { obj.x = i; } catch (e) { result += e; }"
1150 "}; result"))->Run();
1151 CHECK_EQ(v8_str("01234"), result);
1152}
1153
1154
1155THREADED_TEST(FunctionPrototype) {
1156 v8::HandleScope scope;
1157 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1158 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1159 LocalContext env;
1160 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1161 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1162 CHECK_EQ(script->Run()->Int32Value(), 321);
1163}
1164
1165
1166THREADED_TEST(InternalFields) {
1167 v8::HandleScope scope;
1168 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1169 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1170 instance_templ->SetInternalFieldCount(1);
1171 LocalContext env(0, instance_templ);
1172 CHECK_EQ(1, env->Global()->InternalFieldCount());
1173
1174 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1175 CHECK_EQ(1, obj->InternalFieldCount());
1176 CHECK(obj->GetInternalField(0)->IsUndefined());
1177 obj->SetInternalField(0, v8_num(17));
1178 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1179}
1180
1181
1182THREADED_TEST(External) {
1183 v8::HandleScope scope;
1184 int x = 3;
1185 Local<v8::External> ext = v8::External::New(&x);
1186 LocalContext env;
1187 env->Global()->Set(v8_str("ext"), ext);
1188 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1189 v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1190 int* ptr = static_cast<int*>(reext->Value());
1191 CHECK_EQ(x, 3);
1192 *ptr = 10;
1193 CHECK_EQ(x, 10);
1194}
1195
1196
1197THREADED_TEST(GlobalHandle) {
1198 v8::Persistent<String> global;
1199 {
1200 v8::HandleScope scope;
1201 Local<String> str = v8_str("str");
1202 global = v8::Persistent<String>::New(str);
1203 }
1204 CHECK_EQ(global->Length(), 3);
1205 global.Dispose();
1206}
1207
1208
1209THREADED_TEST(ScriptException) {
1210 v8::HandleScope scope;
1211 LocalContext env;
1212 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1213 v8::TryCatch try_catch;
1214 Local<Value> result = script->Run();
1215 CHECK(result.IsEmpty());
1216 CHECK(try_catch.HasCaught());
1217 String::AsciiValue exception_value(try_catch.Exception());
1218 CHECK_EQ(*exception_value, "panama!");
1219}
1220
1221
1222bool message_received;
1223
1224
1225static void check_message(v8::Handle<v8::Message> message,
1226 v8::Handle<Value> data) {
1227 CHECK_EQ(5.76, data->NumberValue());
1228 CHECK_EQ(6.75, message->GetSourceData()->NumberValue());
1229 message_received = true;
1230}
1231
1232
1233THREADED_TEST(MessageHandlerData) {
1234 message_received = false;
1235 v8::HandleScope scope;
1236 CHECK(!message_received);
1237 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1238 LocalContext context;
1239 v8::ScriptOrigin origin =
1240 v8::ScriptOrigin(v8_str("6.75"));
1241 Script::Compile(v8_str("throw 'error'"), &origin)->Run();
1242 CHECK(message_received);
1243 // clear out the message listener
1244 v8::V8::RemoveMessageListeners(check_message);
1245}
1246
1247
1248THREADED_TEST(GetSetProperty) {
1249 v8::HandleScope scope;
1250 LocalContext context;
1251 context->Global()->Set(v8_str("foo"), v8_num(14));
1252 context->Global()->Set(v8_str("12"), v8_num(92));
1253 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1254 context->Global()->Set(v8_num(13), v8_num(56));
1255 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1256 CHECK_EQ(14, foo->Int32Value());
1257 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1258 CHECK_EQ(92, twelve->Int32Value());
1259 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1260 CHECK_EQ(32, sixteen->Int32Value());
1261 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1262 CHECK_EQ(56, thirteen->Int32Value());
1263 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1264 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1265 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1266 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1267 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1268 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1269 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1270 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1271 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1272}
1273
1274
1275THREADED_TEST(PropertyAttributes) {
1276 v8::HandleScope scope;
1277 LocalContext context;
1278 // read-only
1279 Local<String> prop = v8_str("read_only");
1280 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1281 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1282 Script::Compile(v8_str("read_only = 9"))->Run();
1283 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1284 context->Global()->Set(prop, v8_num(10));
1285 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1286 // dont-delete
1287 prop = v8_str("dont_delete");
1288 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1289 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1290 Script::Compile(v8_str("delete dont_delete"))->Run();
1291 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1292}
1293
1294
1295THREADED_TEST(Array) {
1296 v8::HandleScope scope;
1297 LocalContext context;
1298 Local<v8::Array> array = v8::Array::New();
1299 CHECK_EQ(0, array->Length());
1300 CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1301 CHECK(!array->Has(0));
1302 CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1303 CHECK(!array->Has(100));
1304 array->Set(v8::Integer::New(2), v8_num(7));
1305 CHECK_EQ(3, array->Length());
1306 CHECK(!array->Has(0));
1307 CHECK(!array->Has(1));
1308 CHECK(array->Has(2));
1309 CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1310 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1311 Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1312 CHECK_EQ(3, arr->Length());
1313 CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1314 CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1315 CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1316}
1317
1318
1319v8::Handle<Value> HandleF(const v8::Arguments& args) {
1320 v8::HandleScope scope;
1321 ApiTestFuzzer::Fuzz();
1322 Local<v8::Array> result = v8::Array::New(args.Length());
1323 for (int i = 0; i < args.Length(); i++)
1324 result->Set(v8::Integer::New(i), args[i]);
1325 return scope.Close(result);
1326}
1327
1328
1329THREADED_TEST(Vector) {
1330 v8::HandleScope scope;
1331 Local<ObjectTemplate> global = ObjectTemplate::New();
1332 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1333 LocalContext context(0, global);
1334
1335 const char* fun = "f()";
1336 Local<v8::Array> a0 =
1337 Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1338 CHECK_EQ(0, a0->Length());
1339
1340 const char* fun2 = "f(11)";
1341 Local<v8::Array> a1 =
1342 Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1343 CHECK_EQ(1, a1->Length());
1344 CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1345
1346 const char* fun3 = "f(12, 13)";
1347 Local<v8::Array> a2 =
1348 Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1349 CHECK_EQ(2, a2->Length());
1350 CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1351 CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1352
1353 const char* fun4 = "f(14, 15, 16)";
1354 Local<v8::Array> a3 =
1355 Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1356 CHECK_EQ(3, a3->Length());
1357 CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1358 CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1359 CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1360
1361 const char* fun5 = "f(17, 18, 19, 20)";
1362 Local<v8::Array> a4 =
1363 Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1364 CHECK_EQ(4, a4->Length());
1365 CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1366 CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1367 CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1368 CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1369}
1370
1371
1372THREADED_TEST(FunctionCall) {
1373 v8::HandleScope scope;
1374 LocalContext context;
1375 CompileRun(
1376 "function Foo() {"
1377 " var result = [];"
1378 " for (var i = 0; i < arguments.length; i++) {"
1379 " result.push(arguments[i]);"
1380 " }"
1381 " return result;"
1382 "}");
1383 Local<Function> Foo =
1384 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1385
1386 v8::Handle<Value>* args0 = NULL;
1387 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1388 CHECK_EQ(0, a0->Length());
1389
1390 v8::Handle<Value> args1[] = { v8_num(1.1) };
1391 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1392 CHECK_EQ(1, a1->Length());
1393 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1394
1395 v8::Handle<Value> args2[] = { v8_num(2.2),
1396 v8_num(3.3) };
1397 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1398 CHECK_EQ(2, a2->Length());
1399 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1400 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1401
1402 v8::Handle<Value> args3[] = { v8_num(4.4),
1403 v8_num(5.5),
1404 v8_num(6.6) };
1405 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1406 CHECK_EQ(3, a3->Length());
1407 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1408 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1409 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1410
1411 v8::Handle<Value> args4[] = { v8_num(7.7),
1412 v8_num(8.8),
1413 v8_num(9.9),
1414 v8_num(10.11) };
1415 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1416 CHECK_EQ(4, a4->Length());
1417 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1418 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1419 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1420 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1421}
1422
1423
1424static const char* js_code_causing_out_of_memory =
1425 "var a = new Array(); while(true) a.push(a);";
1426
1427
1428// These tests run for a long time and prevent us from running tests
1429// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001430TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001431 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001432 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001433 // Set heap limits.
1434 static const int K = 1024;
1435 v8::ResourceConstraints constraints;
1436 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001437 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001438 v8::SetResourceConstraints(&constraints);
1439
1440 // Execute a script that causes out of memory.
1441 v8::HandleScope scope;
1442 LocalContext context;
1443 v8::V8::IgnoreOutOfMemoryException();
1444 Local<Script> script =
1445 Script::Compile(String::New(js_code_causing_out_of_memory));
1446 Local<Value> result = script->Run();
1447
1448 // Check for out of memory state.
1449 CHECK(result.IsEmpty());
1450 CHECK(context->HasOutOfMemoryException());
1451}
1452
1453
1454v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1455 ApiTestFuzzer::Fuzz();
1456
1457 v8::HandleScope scope;
1458 LocalContext context;
1459 Local<Script> script =
1460 Script::Compile(String::New(js_code_causing_out_of_memory));
1461 Local<Value> result = script->Run();
1462
1463 // Check for out of memory state.
1464 CHECK(result.IsEmpty());
1465 CHECK(context->HasOutOfMemoryException());
1466
1467 return result;
1468}
1469
1470
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001471TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001472 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001473 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001474 // Set heap limits.
1475 static const int K = 1024;
1476 v8::ResourceConstraints constraints;
1477 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001478 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001479 v8::SetResourceConstraints(&constraints);
1480
1481 v8::HandleScope scope;
1482 Local<ObjectTemplate> templ = ObjectTemplate::New();
1483 templ->Set(v8_str("ProvokeOutOfMemory"),
1484 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1485 LocalContext context(0, templ);
1486 v8::V8::IgnoreOutOfMemoryException();
1487 Local<Value> result = CompileRun(
1488 "var thrown = false;"
1489 "try {"
1490 " ProvokeOutOfMemory();"
1491 "} catch (e) {"
1492 " thrown = true;"
1493 "}");
1494 // Check for out of memory state.
1495 CHECK(result.IsEmpty());
1496 CHECK(context->HasOutOfMemoryException());
1497}
1498
1499
1500TEST(HugeConsStringOutOfMemory) {
1501 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001502 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001503 v8::HandleScope scope;
1504 LocalContext context;
1505 // Set heap limits.
1506 static const int K = 1024;
1507 v8::ResourceConstraints constraints;
1508 constraints.set_max_young_space_size(256 * K);
1509 constraints.set_max_old_space_size(2 * K * K);
1510 v8::SetResourceConstraints(&constraints);
1511
1512 // Execute a script that causes out of memory.
1513 v8::V8::IgnoreOutOfMemoryException();
1514
1515 // Build huge string. This should fail with out of memory exception.
1516 Local<Value> result = CompileRun(
1517 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1518 "for (var i = 0; i < 21; i++) { str = str + str; }");
1519
1520 // Check for out of memory state.
1521 CHECK(result.IsEmpty());
1522 CHECK(context->HasOutOfMemoryException());
1523}
1524
1525
1526THREADED_TEST(ConstructCall) {
1527 v8::HandleScope scope;
1528 LocalContext context;
1529 CompileRun(
1530 "function Foo() {"
1531 " var result = [];"
1532 " for (var i = 0; i < arguments.length; i++) {"
1533 " result.push(arguments[i]);"
1534 " }"
1535 " return result;"
1536 "}");
1537 Local<Function> Foo =
1538 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1539
1540 v8::Handle<Value>* args0 = NULL;
1541 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1542 CHECK_EQ(0, a0->Length());
1543
1544 v8::Handle<Value> args1[] = { v8_num(1.1) };
1545 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1546 CHECK_EQ(1, a1->Length());
1547 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1548
1549 v8::Handle<Value> args2[] = { v8_num(2.2),
1550 v8_num(3.3) };
1551 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1552 CHECK_EQ(2, a2->Length());
1553 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1554 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1555
1556 v8::Handle<Value> args3[] = { v8_num(4.4),
1557 v8_num(5.5),
1558 v8_num(6.6) };
1559 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1560 CHECK_EQ(3, a3->Length());
1561 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1562 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1563 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1564
1565 v8::Handle<Value> args4[] = { v8_num(7.7),
1566 v8_num(8.8),
1567 v8_num(9.9),
1568 v8_num(10.11) };
1569 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1570 CHECK_EQ(4, a4->Length());
1571 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1572 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1573 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1574 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1575}
1576
1577
1578static void CheckUncle(v8::TryCatch* try_catch) {
1579 CHECK(try_catch->HasCaught());
1580 String::AsciiValue str_value(try_catch->Exception());
1581 CHECK_EQ(*str_value, "uncle?");
1582 try_catch->Reset();
1583}
1584
1585
1586THREADED_TEST(ConversionException) {
1587 v8::HandleScope scope;
1588 LocalContext env;
1589 CompileRun(
1590 "function TestClass() { };"
1591 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1592 "var obj = new TestClass();");
1593 Local<Value> obj = env->Global()->Get(v8_str("obj"));
1594
1595 v8::TryCatch try_catch;
1596
1597 Local<Value> to_string_result = obj->ToString();
1598 CHECK(to_string_result.IsEmpty());
1599 CheckUncle(&try_catch);
1600
1601 Local<Value> to_number_result = obj->ToNumber();
1602 CHECK(to_number_result.IsEmpty());
1603 CheckUncle(&try_catch);
1604
1605 Local<Value> to_integer_result = obj->ToInteger();
1606 CHECK(to_integer_result.IsEmpty());
1607 CheckUncle(&try_catch);
1608
1609 Local<Value> to_uint32_result = obj->ToUint32();
1610 CHECK(to_uint32_result.IsEmpty());
1611 CheckUncle(&try_catch);
1612
1613 Local<Value> to_int32_result = obj->ToInt32();
1614 CHECK(to_int32_result.IsEmpty());
1615 CheckUncle(&try_catch);
1616
1617 Local<Value> to_object_result = v8::Undefined()->ToObject();
1618 CHECK(to_object_result.IsEmpty());
1619 CHECK(try_catch.HasCaught());
1620 try_catch.Reset();
1621
1622 int32_t int32_value = obj->Int32Value();
1623 CHECK_EQ(0, int32_value);
1624 CheckUncle(&try_catch);
1625
1626 uint32_t uint32_value = obj->Uint32Value();
1627 CHECK_EQ(0, uint32_value);
1628 CheckUncle(&try_catch);
1629
1630 double number_value = obj->NumberValue();
1631 CHECK_NE(0, IsNaN(number_value));
1632 CheckUncle(&try_catch);
1633
1634 int64_t integer_value = obj->IntegerValue();
1635 CHECK_EQ(0.0, static_cast<double>(integer_value));
1636 CheckUncle(&try_catch);
1637}
1638
1639
1640v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1641 ApiTestFuzzer::Fuzz();
1642 return v8::ThrowException(v8_str("konto"));
1643}
1644
1645
1646THREADED_TEST(APICatch) {
1647 v8::HandleScope scope;
1648 Local<ObjectTemplate> templ = ObjectTemplate::New();
1649 templ->Set(v8_str("ThrowFromC"),
1650 v8::FunctionTemplate::New(ThrowFromC));
1651 LocalContext context(0, templ);
1652 CompileRun(
1653 "var thrown = false;"
1654 "try {"
1655 " ThrowFromC();"
1656 "} catch (e) {"
1657 " thrown = true;"
1658 "}");
1659 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
1660 CHECK(thrown->BooleanValue());
1661}
1662
1663
1664THREADED_TEST(ExternalScriptException) {
1665 v8::HandleScope scope;
1666 Local<ObjectTemplate> templ = ObjectTemplate::New();
1667 templ->Set(v8_str("ThrowFromC"),
1668 v8::FunctionTemplate::New(ThrowFromC));
1669 LocalContext context(0, templ);
1670
1671 v8::TryCatch try_catch;
1672 Local<Script> script
1673 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
1674 Local<Value> result = script->Run();
1675 CHECK(result.IsEmpty());
1676 CHECK(try_catch.HasCaught());
1677 String::AsciiValue exception_value(try_catch.Exception());
1678 CHECK_EQ("konto", *exception_value);
1679}
1680
1681
1682
1683v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
1684 ApiTestFuzzer::Fuzz();
1685 CHECK_EQ(4, args.Length());
1686 int count = args[0]->Int32Value();
1687 int cInterval = args[2]->Int32Value();
1688 if (count == 0) {
1689 return v8::ThrowException(v8_str("FromC"));
1690 } else {
1691 Local<v8::Object> global = Context::GetCurrent()->Global();
1692 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
1693 v8::Handle<Value> argv[] = { v8_num(count - 1),
1694 args[1],
1695 args[2],
1696 args[3] };
1697 if (count % cInterval == 0) {
1698 v8::TryCatch try_catch;
1699 Local<Value> result =
1700 v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
1701 int expected = args[3]->Int32Value();
1702 if (try_catch.HasCaught()) {
1703 CHECK_EQ(expected, count);
1704 CHECK(!i::Top::has_scheduled_exception());
1705 } else {
1706 CHECK_NE(expected, count);
1707 }
1708 return result;
1709 } else {
1710 return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
1711 }
1712 }
1713}
1714
1715
1716v8::Handle<Value> JSCheck(const v8::Arguments& args) {
1717 ApiTestFuzzer::Fuzz();
1718 CHECK_EQ(3, args.Length());
1719 bool equality = args[0]->BooleanValue();
1720 int count = args[1]->Int32Value();
1721 int expected = args[2]->Int32Value();
1722 if (equality) {
1723 CHECK_EQ(count, expected);
1724 } else {
1725 CHECK_NE(count, expected);
1726 }
1727 return v8::Undefined();
1728}
1729
1730
1731// This test works by making a stack of alternating JavaScript and C
1732// activations. These activations set up exception handlers with regular
1733// intervals, one interval for C activations and another for JavaScript
1734// activations. When enough activations have been created an exception is
1735// thrown and we check that the right activation catches the exception and that
1736// no other activations do. The right activation is always the topmost one with
1737// a handler, regardless of whether it is in JavaScript or C.
1738//
1739// The notation used to describe a test case looks like this:
1740//
1741// *JS[4] *C[3] @JS[2] C[1] JS[0]
1742//
1743// Each entry is an activation, either JS or C. The index is the count at that
1744// level. Stars identify activations with exception handlers, the @ identifies
1745// the exception handler that should catch the exception.
1746THREADED_TEST(ExceptionOrder) {
1747 v8::HandleScope scope;
1748 Local<ObjectTemplate> templ = ObjectTemplate::New();
1749 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
1750 templ->Set(v8_str("CThrowCountDown"),
1751 v8::FunctionTemplate::New(CThrowCountDown));
1752 LocalContext context(0, templ);
1753 CompileRun(
1754 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
1755 " if (count == 0) throw 'FromJS';"
1756 " if (count % jsInterval == 0) {"
1757 " try {"
1758 " var value = CThrowCountDown(count - 1,"
1759 " jsInterval,"
1760 " cInterval,"
1761 " expected);"
1762 " check(false, count, expected);"
1763 " return value;"
1764 " } catch (e) {"
1765 " check(true, count, expected);"
1766 " }"
1767 " } else {"
1768 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
1769 " }"
1770 "}");
1771 Local<Function> fun =
1772 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
1773
1774 const int argc = 4;
1775 // count jsInterval cInterval expected
1776
1777 // *JS[4] *C[3] @JS[2] C[1] JS[0]
1778 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
1779 fun->Call(fun, argc, a0);
1780
1781 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
1782 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
1783 fun->Call(fun, argc, a1);
1784
1785 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
1786 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
1787 fun->Call(fun, argc, a2);
1788
1789 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
1790 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
1791 fun->Call(fun, argc, a3);
1792
1793 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
1794 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
1795 fun->Call(fun, argc, a4);
1796
1797 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
1798 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
1799 fun->Call(fun, argc, a5);
1800}
1801
1802
1803v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
1804 ApiTestFuzzer::Fuzz();
1805 CHECK_EQ(1, args.Length());
1806 return v8::ThrowException(args[0]);
1807}
1808
1809
1810THREADED_TEST(ThrowValues) {
1811 v8::HandleScope scope;
1812 Local<ObjectTemplate> templ = ObjectTemplate::New();
1813 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
1814 LocalContext context(0, templ);
1815 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
1816 "function Run(obj) {"
1817 " try {"
1818 " Throw(obj);"
1819 " } catch (e) {"
1820 " return e;"
1821 " }"
1822 " return 'no exception';"
1823 "}"
1824 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
1825 CHECK_EQ(5, result->Length());
1826 CHECK(result->Get(v8::Integer::New(0))->IsString());
1827 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
1828 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
1829 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
1830 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
1831 CHECK(result->Get(v8::Integer::New(3))->IsNull());
1832 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
1833}
1834
1835
1836THREADED_TEST(CatchZero) {
1837 v8::HandleScope scope;
1838 LocalContext context;
1839 v8::TryCatch try_catch;
1840 CHECK(!try_catch.HasCaught());
1841 Script::Compile(v8_str("throw 10"))->Run();
1842 CHECK(try_catch.HasCaught());
1843 CHECK_EQ(10, try_catch.Exception()->Int32Value());
1844 try_catch.Reset();
1845 CHECK(!try_catch.HasCaught());
1846 Script::Compile(v8_str("throw 0"))->Run();
1847 CHECK(try_catch.HasCaught());
1848 CHECK_EQ(0, try_catch.Exception()->Int32Value());
1849}
1850
1851
1852THREADED_TEST(CatchExceptionFromWith) {
1853 v8::HandleScope scope;
1854 LocalContext context;
1855 v8::TryCatch try_catch;
1856 CHECK(!try_catch.HasCaught());
1857 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
1858 CHECK(try_catch.HasCaught());
1859}
1860
1861
1862THREADED_TEST(Equality) {
1863 v8::HandleScope scope;
1864 LocalContext context;
1865 // Check that equality works at all before relying on CHECK_EQ
1866 CHECK(v8_str("a")->Equals(v8_str("a")));
1867 CHECK(!v8_str("a")->Equals(v8_str("b")));
1868
1869 CHECK_EQ(v8_str("a"), v8_str("a"));
1870 CHECK_NE(v8_str("a"), v8_str("b"));
1871 CHECK_EQ(v8_num(1), v8_num(1));
1872 CHECK_EQ(v8_num(1.00), v8_num(1));
1873 CHECK_NE(v8_num(1), v8_num(2));
1874
1875 // Assume String is not symbol.
1876 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
1877 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
1878 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
1879 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
1880 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
1881 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
1882 Local<Value> not_a_number = v8_num(i::OS::nan_value());
1883 CHECK(!not_a_number->StrictEquals(not_a_number));
1884 CHECK(v8::False()->StrictEquals(v8::False()));
1885 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
1886
1887 v8::Handle<v8::Object> obj = v8::Object::New();
1888 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
1889 CHECK(alias->StrictEquals(obj));
1890 alias.Dispose();
1891}
1892
1893
1894THREADED_TEST(MultiRun) {
1895 v8::HandleScope scope;
1896 LocalContext context;
1897 Local<Script> script = Script::Compile(v8_str("x"));
1898 for (int i = 0; i < 10; i++)
1899 script->Run();
1900}
1901
1902
1903static v8::Handle<Value> GetXValue(Local<String> name,
1904 const AccessorInfo& info) {
1905 ApiTestFuzzer::Fuzz();
1906 CHECK_EQ(info.Data(), v8_str("donut"));
1907 CHECK_EQ(name, v8_str("x"));
1908 return name;
1909}
1910
1911
1912THREADED_TEST(SimplePropertyRead) {
1913 v8::HandleScope scope;
1914 Local<ObjectTemplate> templ = ObjectTemplate::New();
1915 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
1916 LocalContext context;
1917 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1918 Local<Script> script = Script::Compile(v8_str("obj.x"));
1919 for (int i = 0; i < 10; i++) {
1920 Local<Value> result = script->Run();
1921 CHECK_EQ(result, v8_str("x"));
1922 }
1923}
1924
1925
1926v8::Persistent<Value> xValue;
1927
1928
1929static void SetXValue(Local<String> name,
1930 Local<Value> value,
1931 const AccessorInfo& info) {
1932 CHECK_EQ(value, v8_num(4));
1933 CHECK_EQ(info.Data(), v8_str("donut"));
1934 CHECK_EQ(name, v8_str("x"));
1935 CHECK(xValue.IsEmpty());
1936 xValue = v8::Persistent<Value>::New(value);
1937}
1938
1939
1940THREADED_TEST(SimplePropertyWrite) {
1941 v8::HandleScope scope;
1942 Local<ObjectTemplate> templ = ObjectTemplate::New();
1943 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
1944 LocalContext context;
1945 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1946 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
1947 for (int i = 0; i < 10; i++) {
1948 CHECK(xValue.IsEmpty());
1949 script->Run();
1950 CHECK_EQ(v8_num(4), xValue);
1951 xValue.Dispose();
1952 xValue = v8::Persistent<Value>();
1953 }
1954}
1955
1956
1957static v8::Handle<Value> XPropertyGetter(Local<String> property,
1958 const AccessorInfo& info) {
1959 ApiTestFuzzer::Fuzz();
1960 CHECK(info.Data()->IsUndefined());
1961 return property;
1962}
1963
1964
1965THREADED_TEST(NamedInterceporPropertyRead) {
1966 v8::HandleScope scope;
1967 Local<ObjectTemplate> templ = ObjectTemplate::New();
1968 templ->SetNamedPropertyHandler(XPropertyGetter);
1969 LocalContext context;
1970 context->Global()->Set(v8_str("obj"), templ->NewInstance());
1971 Local<Script> script = Script::Compile(v8_str("obj.x"));
1972 for (int i = 0; i < 10; i++) {
1973 Local<Value> result = script->Run();
1974 CHECK_EQ(result, v8_str("x"));
1975 }
1976}
1977
1978THREADED_TEST(MultiContexts) {
1979 v8::HandleScope scope;
1980 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
1981 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
1982
1983 Local<String> password = v8_str("Password");
1984
1985 // Create an environment
1986 LocalContext context0(0, templ);
1987 context0->SetSecurityToken(password);
1988 v8::Handle<v8::Object> global0 = context0->Global();
1989 global0->Set(v8_str("custom"), v8_num(1234));
1990 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
1991
1992 // Create an independent environment
1993 LocalContext context1(0, templ);
1994 context1->SetSecurityToken(password);
1995 v8::Handle<v8::Object> global1 = context1->Global();
1996 global1->Set(v8_str("custom"), v8_num(1234));
1997 CHECK_NE(global0, global1);
1998 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
1999 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2000
2001 // Now create a new context with the old global
2002 LocalContext context2(0, templ, global1);
2003 context2->SetSecurityToken(password);
2004 v8::Handle<v8::Object> global2 = context2->Global();
2005 CHECK_EQ(global1, global2);
2006 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2007 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2008}
2009
2010
2011THREADED_TEST(FunctionPrototypeAcrossContexts) {
2012 // Make sure that functions created by cloning boilerplates cannot
2013 // communicate through their __proto__ field.
2014
2015 v8::HandleScope scope;
2016
2017 LocalContext env0;
2018 v8::Handle<v8::Object> global0 =
2019 env0->Global();
2020 v8::Handle<v8::Object> object0 =
2021 v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2022 v8::Handle<v8::Object> tostring0 =
2023 v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2024 v8::Handle<v8::Object> proto0 =
2025 v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2026 proto0->Set(v8_str("custom"), v8_num(1234));
2027
2028 LocalContext env1;
2029 v8::Handle<v8::Object> global1 =
2030 env1->Global();
2031 v8::Handle<v8::Object> object1 =
2032 v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2033 v8::Handle<v8::Object> tostring1 =
2034 v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2035 v8::Handle<v8::Object> proto1 =
2036 v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2037 CHECK(!proto1->Has(v8_str("custom")));
2038}
2039
2040
2041THREADED_TEST(Regress892105) {
2042 // Make sure that object and array literals created by cloning
2043 // boilerplates cannot communicate through their __proto__
2044 // field. This is rather difficult to check, but we try to add stuff
2045 // to Object.prototype and Array.prototype and create a new
2046 // environment. This should succeed.
2047
2048 v8::HandleScope scope;
2049
2050 Local<String> source = v8_str("Object.prototype.obj = 1234;"
2051 "Array.prototype.arr = 4567;"
2052 "8901");
2053
2054 LocalContext env0;
2055 Local<Script> script0 = Script::Compile(source);
2056 CHECK_EQ(8901.0, script0->Run()->NumberValue());
2057
2058 LocalContext env1;
2059 Local<Script> script1 = Script::Compile(source);
2060 CHECK_EQ(8901.0, script1->Run()->NumberValue());
2061}
2062
2063
2064static void ExpectString(const char* code, const char* expected) {
2065 Local<Value> result = CompileRun(code);
2066 CHECK(result->IsString());
2067 String::AsciiValue ascii(result);
2068 CHECK_EQ(0, strcmp(*ascii, expected));
2069}
2070
2071
2072static void ExpectBoolean(const char* code, bool expected) {
2073 Local<Value> result = CompileRun(code);
2074 CHECK(result->IsBoolean());
2075 CHECK_EQ(expected, result->BooleanValue());
2076}
2077
2078
2079static void ExpectObject(const char* code, Local<Value> expected) {
2080 Local<Value> result = CompileRun(code);
2081 CHECK(result->Equals(expected));
2082}
2083
2084
2085THREADED_TEST(UndetectableObject) {
2086 v8::HandleScope scope;
2087 LocalContext env;
2088
2089 Local<v8::FunctionTemplate> desc =
2090 v8::FunctionTemplate::New(0, v8::Handle<Value>());
2091 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
2092
2093 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2094 env->Global()->Set(v8_str("undetectable"), obj);
2095
2096 ExpectString("undetectable.toString()", "[object Object]");
2097 ExpectString("typeof undetectable", "undefined");
2098 ExpectString("typeof(undetectable)", "undefined");
2099 ExpectBoolean("typeof undetectable == 'undefined'", true);
2100 ExpectBoolean("typeof undetectable == 'object'", false);
2101 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2102 ExpectBoolean("!undetectable", true);
2103
2104 ExpectObject("true&&undetectable", obj);
2105 ExpectBoolean("false&&undetectable", false);
2106 ExpectBoolean("true||undetectable", true);
2107 ExpectObject("false||undetectable", obj);
2108
2109 ExpectObject("undetectable&&true", obj);
2110 ExpectObject("undetectable&&false", obj);
2111 ExpectBoolean("undetectable||true", true);
2112 ExpectBoolean("undetectable||false", false);
2113
2114 ExpectBoolean("undetectable==null", true);
2115 ExpectBoolean("undetectable==undefined", true);
2116 ExpectBoolean("undetectable==undetectable", true);
2117
2118 ExpectBoolean("undetectable===null", false);
2119 ExpectBoolean("undetectable===undefined", true);
2120 ExpectBoolean("undetectable===undetectable", true);
2121}
2122
2123
2124THREADED_TEST(UndetectableString) {
2125 v8::HandleScope scope;
2126 LocalContext env;
2127
2128 Local<String> obj = String::NewUndetectable("foo");
2129 env->Global()->Set(v8_str("undetectable"), obj);
2130
2131 ExpectString("undetectable", "foo");
2132 ExpectString("typeof undetectable", "undefined");
2133 ExpectString("typeof(undetectable)", "undefined");
2134 ExpectBoolean("typeof undetectable == 'undefined'", true);
2135 ExpectBoolean("typeof undetectable == 'string'", false);
2136 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2137 ExpectBoolean("!undetectable", true);
2138
2139 ExpectObject("true&&undetectable", obj);
2140 ExpectBoolean("false&&undetectable", false);
2141 ExpectBoolean("true||undetectable", true);
2142 ExpectObject("false||undetectable", obj);
2143
2144 ExpectObject("undetectable&&true", obj);
2145 ExpectObject("undetectable&&false", obj);
2146 ExpectBoolean("undetectable||true", true);
2147 ExpectBoolean("undetectable||false", false);
2148
2149 ExpectBoolean("undetectable==null", true);
2150 ExpectBoolean("undetectable==undefined", true);
2151 ExpectBoolean("undetectable==undetectable", true);
2152
2153 ExpectBoolean("undetectable===null", false);
2154 ExpectBoolean("undetectable===undefined", true);
2155 ExpectBoolean("undetectable===undetectable", true);
2156}
2157
2158
2159template <typename T> static void USE(T) { }
2160
2161
2162// This test is not intended to be run, just type checked.
2163static void PersistentHandles() {
2164 USE(PersistentHandles);
2165 Local<String> str = v8_str("foo");
2166 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
2167 USE(p_str);
2168 Local<Script> scr = Script::Compile(v8_str(""));
2169 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
2170 USE(p_scr);
2171 Local<ObjectTemplate> templ = ObjectTemplate::New();
2172 v8::Persistent<ObjectTemplate> p_templ =
2173 v8::Persistent<ObjectTemplate>::New(templ);
2174 USE(p_templ);
2175}
2176
2177
2178static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
2179 ApiTestFuzzer::Fuzz();
2180 return v8::Undefined();
2181}
2182
2183
2184THREADED_TEST(GlobalObjectTemplate) {
2185 v8::HandleScope handle_scope;
2186 Local<ObjectTemplate> global_template = ObjectTemplate::New();
2187 global_template->Set(v8_str("JSNI_Log"),
2188 v8::FunctionTemplate::New(HandleLogDelegator));
2189 v8::Persistent<Context> context = Context::New(0, global_template);
2190 Context::Scope context_scope(context);
2191 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
2192 context.Dispose();
2193}
2194
2195
2196static const char* kSimpleExtensionSource =
2197 "function Foo() {"
2198 " return 4;"
2199 "}";
2200
2201
2202THREADED_TEST(SimpleExtensions) {
2203 v8::HandleScope handle_scope;
2204 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
2205 const char* extension_names[] = { "simpletest" };
2206 v8::ExtensionConfiguration extensions(1, extension_names);
2207 v8::Handle<Context> context = Context::New(&extensions);
2208 Context::Scope lock(context);
2209 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2210 CHECK_EQ(result, v8::Integer::New(4));
2211}
2212
2213
2214THREADED_TEST(AutoExtensions) {
2215 v8::HandleScope handle_scope;
2216 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
2217 extension->set_auto_enable(true);
2218 v8::RegisterExtension(extension);
2219 v8::Handle<Context> context = Context::New();
2220 Context::Scope lock(context);
2221 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2222 CHECK_EQ(result, v8::Integer::New(4));
2223}
2224
2225
2226static void CheckDependencies(const char* name, const char* expected) {
2227 v8::HandleScope handle_scope;
2228 v8::ExtensionConfiguration config(1, &name);
2229 LocalContext context(&config);
2230 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
2231}
2232
2233
2234/*
2235 * Configuration:
2236 *
2237 * /-- B <--\
2238 * A <- -- D <-- E
2239 * \-- C <--/
2240 */
2241THREADED_TEST(ExtensionDependency) {
2242 static const char* kEDeps[] = { "D" };
2243 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
2244 static const char* kDDeps[] = { "B", "C" };
2245 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
2246 static const char* kBCDeps[] = { "A" };
2247 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
2248 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
2249 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
2250 CheckDependencies("A", "undefinedA");
2251 CheckDependencies("B", "undefinedAB");
2252 CheckDependencies("C", "undefinedAC");
2253 CheckDependencies("D", "undefinedABCD");
2254 CheckDependencies("E", "undefinedABCDE");
2255 v8::HandleScope handle_scope;
2256 static const char* exts[2] = { "C", "E" };
2257 v8::ExtensionConfiguration config(2, exts);
2258 LocalContext context(&config);
2259 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
2260}
2261
2262
2263static const char* kExtensionTestScript =
2264 "native function A();"
2265 "native function B();"
2266 "native function C();"
2267 "function Foo(i) {"
2268 " if (i == 0) return A();"
2269 " if (i == 1) return B();"
2270 " if (i == 2) return C();"
2271 "}";
2272
2273
2274static v8::Handle<Value> CallFun(const v8::Arguments& args) {
2275 ApiTestFuzzer::Fuzz();
2276 return args.Data();
2277}
2278
2279
2280class FunctionExtension : public Extension {
2281 public:
2282 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
2283 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
2284 v8::Handle<String> name);
2285};
2286
2287
2288static int lookup_count = 0;
2289v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
2290 v8::Handle<String> name) {
2291 lookup_count++;
2292 if (name->Equals(v8_str("A"))) {
2293 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
2294 } else if (name->Equals(v8_str("B"))) {
2295 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
2296 } else if (name->Equals(v8_str("C"))) {
2297 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
2298 } else {
2299 return v8::Handle<v8::FunctionTemplate>();
2300 }
2301}
2302
2303
2304THREADED_TEST(FunctionLookup) {
2305 v8::RegisterExtension(new FunctionExtension());
2306 v8::HandleScope handle_scope;
2307 static const char* exts[1] = { "functiontest" };
2308 v8::ExtensionConfiguration config(1, exts);
2309 LocalContext context(&config);
2310 CHECK_EQ(3, lookup_count);
2311 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
2312 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
2313 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
2314}
2315
2316
2317static const char* last_location;
2318static const char* last_message;
2319void StoringErrorCallback(const char* location, const char* message) {
2320 if (last_location == NULL) {
2321 last_location = location;
2322 last_message = message;
2323 }
2324}
2325
2326
2327// ErrorReporting creates a circular extensions configuration and
2328// tests that the fatal error handler gets called. This renders V8
2329// unusable and therefore this test cannot be run in parallel.
2330TEST(ErrorReporting) {
2331 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
2332 static const char* aDeps[] = { "B" };
2333 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
2334 static const char* bDeps[] = { "A" };
2335 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
2336 last_location = NULL;
2337 v8::ExtensionConfiguration config(1, bDeps);
2338 v8::Handle<Context> context = Context::New(&config);
2339 CHECK(context.IsEmpty());
2340 CHECK_NE(last_location, NULL);
2341}
2342
2343
2344static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
2345 v8::Handle<Value> data) {
2346 CHECK_EQ(v8::Undefined(), data);
2347 CHECK(message->GetScriptResourceName().IsEmpty());
2348 CHECK_EQ(v8::Undefined(), message->GetSourceData());
2349 message->GetLineNumber();
2350 message->GetSourceLine();
2351}
2352
2353
2354THREADED_TEST(ErrorWithMissingScriptInfo) {
2355 v8::HandleScope scope;
2356 LocalContext context;
2357 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
2358 Script::Compile(v8_str("throw Error()"))->Run();
2359 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
2360}
2361
2362
2363int global_index = 0;
2364
2365class Snorkel {
2366 public:
2367 Snorkel() { index_ = global_index++; }
2368 int index_;
2369};
2370
2371class Whammy {
2372 public:
2373 Whammy() {
2374 cursor_ = 0;
2375 }
2376 ~Whammy() {
2377 script_.Dispose();
2378 }
2379 v8::Handle<Script> getScript() {
2380 if (script_.IsEmpty())
2381 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
2382 return Local<Script>(*script_);
2383 }
2384
2385 public:
2386 static const int kObjectCount = 256;
2387 int cursor_;
2388 v8::Persistent<v8::Object> objects_[kObjectCount];
2389 v8::Persistent<Script> script_;
2390};
2391
2392static void HandleWeakReference(v8::Persistent<v8::Object> obj, void* data) {
2393 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
2394 delete snorkel;
2395 obj.ClearWeak();
2396}
2397
2398v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
2399 const AccessorInfo& info) {
2400 Whammy* whammy =
2401 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
2402
2403 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
2404
2405 v8::Handle<v8::Object> obj = v8::Object::New();
2406 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
2407 if (!prev.IsEmpty()) {
2408 prev->Set(v8_str("next"), obj);
2409 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
2410 whammy->objects_[whammy->cursor_].Clear();
2411 }
2412 whammy->objects_[whammy->cursor_] = global;
2413 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
2414 return whammy->getScript()->Run();
2415}
2416
2417THREADED_TEST(WeakReference) {
2418 v8::HandleScope handle_scope;
2419 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
2420 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
2421 0, 0, 0, 0,
2422 v8::External::New(new Whammy()));
2423 const char* extension_list[] = { "v8/gc" };
2424 v8::ExtensionConfiguration extensions(1, extension_list);
2425 v8::Persistent<Context> context = Context::New(&extensions);
2426 Context::Scope context_scope(context);
2427
2428 v8::Handle<v8::Object> interceptor = templ->NewInstance();
2429 context->Global()->Set(v8_str("whammy"), interceptor);
2430 const char* code =
2431 "var last;"
2432 "for (var i = 0; i < 10000; i++) {"
2433 " var obj = whammy.length;"
2434 " if (last) last.next = obj;"
2435 " last = obj;"
2436 "}"
2437 "gc();"
2438 "4";
2439 v8::Handle<Value> result = CompileRun(code);
2440 CHECK_EQ(4.0, result->NumberValue());
2441
2442 context.Dispose();
2443}
2444
2445
2446v8::Handle<Function> args_fun;
2447
2448
2449static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
2450 ApiTestFuzzer::Fuzz();
2451 CHECK_EQ(args_fun, args.Callee());
2452 CHECK_EQ(3, args.Length());
2453 CHECK_EQ(v8::Integer::New(1), args[0]);
2454 CHECK_EQ(v8::Integer::New(2), args[1]);
2455 CHECK_EQ(v8::Integer::New(3), args[2]);
2456 CHECK_EQ(v8::Undefined(), args[3]);
2457 v8::HandleScope scope;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002458 i::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002459 return v8::Undefined();
2460}
2461
2462
2463THREADED_TEST(Arguments) {
2464 v8::HandleScope scope;
2465 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2466 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
2467 LocalContext context(NULL, global);
2468 args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
2469 v8_compile("f(1, 2, 3)")->Run();
2470}
2471
2472
2473static int x_register = 0;
2474static v8::Handle<v8::Object> x_receiver;
2475static v8::Handle<v8::Object> x_holder;
2476
2477
2478static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
2479 ApiTestFuzzer::Fuzz();
2480 CHECK_EQ(x_receiver, info.This());
2481 CHECK_EQ(x_holder, info.Holder());
2482 return v8_num(x_register);
2483}
2484
2485
2486static void XSetter(Local<String> name,
2487 Local<Value> value,
2488 const AccessorInfo& info) {
2489 CHECK_EQ(x_holder, info.This());
2490 CHECK_EQ(x_holder, info.Holder());
2491 x_register = value->Int32Value();
2492}
2493
2494
2495THREADED_TEST(AccessorIC) {
2496 v8::HandleScope scope;
2497 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2498 obj->SetAccessor(v8_str("x"), XGetter, XSetter);
2499 LocalContext context;
2500 x_holder = obj->NewInstance();
2501 context->Global()->Set(v8_str("holder"), x_holder);
2502 x_receiver = v8::Object::New();
2503 context->Global()->Set(v8_str("obj"), x_receiver);
2504 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
2505 "obj.__proto__ = holder;"
2506 "var result = [];"
2507 "for (var i = 0; i < 10; i++) {"
2508 " holder.x = i;"
2509 " result.push(obj.x);"
2510 "}"
2511 "result"));
2512 CHECK_EQ(10, array->Length());
2513 for (int i = 0; i < 10; i++) {
2514 v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
2515 CHECK_EQ(v8::Integer::New(i), entry);
2516 }
2517}
2518
2519
2520static v8::Handle<Value> NoBlockGetterX(Local<String> name,
2521 const AccessorInfo&) {
2522 return v8::Handle<Value>();
2523}
2524
2525
2526static v8::Handle<Value> NoBlockGetterI(uint32_t index,
2527 const AccessorInfo&) {
2528 return v8::Handle<Value>();
2529}
2530
2531
2532static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
2533 const AccessorInfo&) {
2534 if (!name->Equals(v8_str("foo"))) {
2535 return v8::Handle<v8::Boolean>(); // not intercepted
2536 }
2537
2538 return v8::False(); // intercepted, and don't delete the property
2539}
2540
2541
2542static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
2543 if (index != 2) {
2544 return v8::Handle<v8::Boolean>(); // not intercepted
2545 }
2546
2547 return v8::False(); // intercepted, and don't delete the property
2548}
2549
2550
2551THREADED_TEST(Deleter) {
2552 v8::HandleScope scope;
2553 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2554 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
2555 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
2556 LocalContext context;
2557 context->Global()->Set(v8_str("k"), obj->NewInstance());
2558 CompileRun(
2559 "k.foo = 'foo';"
2560 "k.bar = 'bar';"
2561 "k[2] = 2;"
2562 "k[4] = 4;");
2563 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
2564 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
2565
2566 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
2567 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
2568
2569 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
2570 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
2571
2572 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
2573 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
2574}
2575
2576
2577static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
2578 ApiTestFuzzer::Fuzz();
2579 return v8::Undefined();
2580}
2581
2582
2583static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
2584 ApiTestFuzzer::Fuzz();
2585 v8::Handle<v8::Array> result = v8::Array::New(3);
2586 result->Set(v8::Integer::New(0), v8_str("foo"));
2587 result->Set(v8::Integer::New(1), v8_str("bar"));
2588 result->Set(v8::Integer::New(2), v8_str("baz"));
2589 return result;
2590}
2591
2592
2593static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
2594 ApiTestFuzzer::Fuzz();
2595 v8::Handle<v8::Array> result = v8::Array::New(2);
2596 result->Set(v8::Integer::New(0), v8_str("hat"));
2597 result->Set(v8::Integer::New(1), v8_str("gyt"));
2598 return result;
2599}
2600
2601
2602THREADED_TEST(Enumerators) {
2603 v8::HandleScope scope;
2604 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2605 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
2606 obj->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, IndexedEnum);
2607 LocalContext context;
2608 context->Global()->Set(v8_str("k"), obj->NewInstance());
2609 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2610 "var result = [];"
2611 "for (var prop in k) {"
2612 " result.push(prop);"
2613 "}"
2614 "result"));
2615 CHECK_EQ(5, result->Length());
2616 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(0)));
2617 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(1)));
2618 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(2)));
2619 CHECK_EQ(v8_str("hat"), result->Get(v8::Integer::New(3)));
2620 CHECK_EQ(v8_str("gyt"), result->Get(v8::Integer::New(4)));
2621}
2622
2623
2624int p_getter_count;
2625int p_getter_count2;
2626
2627
2628static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
2629 ApiTestFuzzer::Fuzz();
2630 p_getter_count++;
2631 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
2632 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
2633 if (name->Equals(v8_str("p1"))) {
2634 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
2635 } else if (name->Equals(v8_str("p2"))) {
2636 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
2637 } else if (name->Equals(v8_str("p3"))) {
2638 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
2639 } else if (name->Equals(v8_str("p4"))) {
2640 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
2641 }
2642 return v8::Undefined();
2643}
2644
2645
2646static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
2647 ApiTestFuzzer::Fuzz();
2648 LocalContext context;
2649 context->Global()->Set(v8_str("o1"), obj->NewInstance());
2650 CompileRun(
2651 "o1.__proto__ = { };"
2652 "var o2 = { __proto__: o1 };"
2653 "var o3 = { __proto__: o2 };"
2654 "var o4 = { __proto__: o3 };"
2655 "for (var i = 0; i < 10; i++) o4.p4;"
2656 "for (var i = 0; i < 10; i++) o3.p3;"
2657 "for (var i = 0; i < 10; i++) o2.p2;"
2658 "for (var i = 0; i < 10; i++) o1.p1;");
2659}
2660
2661
2662static v8::Handle<Value> PGetter2(Local<String> name,
2663 const AccessorInfo& info) {
2664 ApiTestFuzzer::Fuzz();
2665 p_getter_count2++;
2666 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
2667 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
2668 if (name->Equals(v8_str("p1"))) {
2669 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
2670 } else if (name->Equals(v8_str("p2"))) {
2671 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
2672 } else if (name->Equals(v8_str("p3"))) {
2673 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
2674 } else if (name->Equals(v8_str("p4"))) {
2675 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
2676 }
2677 return v8::Undefined();
2678}
2679
2680
2681THREADED_TEST(GetterHolders) {
2682 v8::HandleScope scope;
2683 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2684 obj->SetAccessor(v8_str("p1"), PGetter);
2685 obj->SetAccessor(v8_str("p2"), PGetter);
2686 obj->SetAccessor(v8_str("p3"), PGetter);
2687 obj->SetAccessor(v8_str("p4"), PGetter);
2688 p_getter_count = 0;
2689 RunHolderTest(obj);
2690 CHECK_EQ(40, p_getter_count);
2691}
2692
2693
2694THREADED_TEST(PreInterceptorHolders) {
2695 v8::HandleScope scope;
2696 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2697 obj->SetNamedPropertyHandler(PGetter2);
2698 p_getter_count2 = 0;
2699 RunHolderTest(obj);
2700 CHECK_EQ(40, p_getter_count2);
2701}
2702
2703
2704THREADED_TEST(ObjectInstantiation) {
2705 v8::HandleScope scope;
2706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
2707 templ->SetAccessor(v8_str("t"), PGetter2);
2708 LocalContext context;
2709 context->Global()->Set(v8_str("o"), templ->NewInstance());
2710 for (int i = 0; i < 100; i++) {
2711 v8::HandleScope inner_scope;
2712 v8::Handle<v8::Object> obj = templ->NewInstance();
2713 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
2714 context->Global()->Set(v8_str("o2"), obj);
2715 v8::Handle<Value> value =
2716 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
2717 CHECK_EQ(v8::True(), value);
2718 context->Global()->Set(v8_str("o"), obj);
2719 }
2720}
2721
2722
2723THREADED_TEST(StringWrite) {
2724 v8::HandleScope scope;
2725 v8::Handle<String> str = v8_str("abcde");
2726
2727 char buf[100];
2728 int len;
2729
2730 memset(buf, 0x1, sizeof(buf));
2731 len = str->WriteAscii(buf);
2732 CHECK_EQ(len, 5);
2733 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
2734
2735 memset(buf, 0x1, sizeof(buf));
2736 len = str->WriteAscii(buf, 0, 4);
2737 CHECK_EQ(len, 4);
2738 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
2739
2740 memset(buf, 0x1, sizeof(buf));
2741 len = str->WriteAscii(buf, 0, 5);
2742 CHECK_EQ(len, 5);
2743 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
2744
2745 memset(buf, 0x1, sizeof(buf));
2746 len = str->WriteAscii(buf, 0, 6);
2747 CHECK_EQ(len, 5);
2748 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
2749
2750 memset(buf, 0x1, sizeof(buf));
2751 len = str->WriteAscii(buf, 4, -1);
2752 CHECK_EQ(len, 1);
2753 CHECK_EQ(strncmp("e\0", buf, 2), 0);
2754
2755 memset(buf, 0x1, sizeof(buf));
2756 len = str->WriteAscii(buf, 4, 6);
2757 CHECK_EQ(len, 1);
2758 CHECK_EQ(strncmp("e\0", buf, 2), 0);
2759
2760 memset(buf, 0x1, sizeof(buf));
2761 len = str->WriteAscii(buf, 4, 1);
2762 CHECK_EQ(len, 1);
2763 CHECK_EQ(strncmp("e\1", buf, 2), 0);
2764}
2765
2766
2767THREADED_TEST(ToArrayIndex) {
2768 v8::HandleScope scope;
2769 LocalContext context;
2770
2771 v8::Handle<String> str = v8_str("42");
2772 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
2773 CHECK(!index.IsEmpty());
2774 CHECK_EQ(42.0, index->Uint32Value());
2775 str = v8_str("42asdf");
2776 index = str->ToArrayIndex();
2777 CHECK(index.IsEmpty());
2778 str = v8_str("-42");
2779 index = str->ToArrayIndex();
2780 CHECK(index.IsEmpty());
2781 str = v8_str("4294967295");
2782 index = str->ToArrayIndex();
2783 CHECK(!index.IsEmpty());
2784 CHECK_EQ(4294967295.0, index->Uint32Value());
2785 v8::Handle<v8::Number> num = v8::Number::New(1);
2786 index = num->ToArrayIndex();
2787 CHECK(!index.IsEmpty());
2788 CHECK_EQ(1.0, index->Uint32Value());
2789 num = v8::Number::New(-1);
2790 index = num->ToArrayIndex();
2791 CHECK(index.IsEmpty());
2792 v8::Handle<v8::Object> obj = v8::Object::New();
2793 index = obj->ToArrayIndex();
2794 CHECK(index.IsEmpty());
2795}
2796
2797
2798THREADED_TEST(ErrorConstruction) {
2799 v8::HandleScope scope;
2800 LocalContext context;
2801
2802 v8::Handle<String> foo = v8_str("foo");
2803 v8::Handle<String> message = v8_str("message");
2804 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
2805 CHECK(range_error->IsObject());
2806 v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
2807 CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
2808 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
2809 CHECK(reference_error->IsObject());
2810 CHECK(
2811 v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
2812 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
2813 CHECK(syntax_error->IsObject());
2814 CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
2815 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
2816 CHECK(type_error->IsObject());
2817 CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
2818 v8::Handle<Value> error = v8::Exception::Error(foo);
2819 CHECK(error->IsObject());
2820 CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
2821}
2822
2823
2824static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
2825 ApiTestFuzzer::Fuzz();
2826 return v8_num(10);
2827}
2828
2829
2830static void YSetter(Local<String> name,
2831 Local<Value> value,
2832 const AccessorInfo& info) {
2833 if (info.This()->Has(name)) {
2834 info.This()->Delete(name);
2835 }
2836 info.This()->Set(name, value);
2837}
2838
2839
2840THREADED_TEST(DeleteAccessor) {
2841 v8::HandleScope scope;
2842 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2843 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
2844 LocalContext context;
2845 v8::Handle<v8::Object> holder = obj->NewInstance();
2846 context->Global()->Set(v8_str("holder"), holder);
2847 v8::Handle<Value> result = CompileRun(
2848 "holder.y = 11; holder.y = 12; holder.y");
2849 CHECK_EQ(12, result->Uint32Value());
2850}
2851
2852
2853THREADED_TEST(TypeSwitch) {
2854 v8::HandleScope scope;
2855 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
2856 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
2857 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
2858 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
2859 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
2860 LocalContext context;
2861 v8::Handle<v8::Object> obj0 = v8::Object::New();
2862 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
2863 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
2864 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
2865 for (int i = 0; i < 10; i++) {
2866 CHECK_EQ(0, type_switch->match(obj0));
2867 CHECK_EQ(1, type_switch->match(obj1));
2868 CHECK_EQ(2, type_switch->match(obj2));
2869 CHECK_EQ(3, type_switch->match(obj3));
2870 CHECK_EQ(3, type_switch->match(obj3));
2871 CHECK_EQ(2, type_switch->match(obj2));
2872 CHECK_EQ(1, type_switch->match(obj1));
2873 CHECK_EQ(0, type_switch->match(obj0));
2874 }
2875}
2876
2877
2878// For use within the TestSecurityHandler() test.
2879static bool g_security_callback_result = false;
2880static bool NamedSecurityTestCallback(Local<v8::Object> global,
2881 Local<Value> name,
2882 v8::AccessType type,
2883 Local<Value> data) {
2884 // Always allow read access.
2885 if (type == v8::ACCESS_GET)
2886 return true;
2887
2888 // Sometimes allow other access.
2889 return g_security_callback_result;
2890}
2891
2892
2893static bool IndexedSecurityTestCallback(Local<v8::Object> global,
2894 uint32_t key,
2895 v8::AccessType type,
2896 Local<Value> data) {
2897 // Always allow read access.
2898 if (type == v8::ACCESS_GET)
2899 return true;
2900
2901 // Sometimes allow other access.
2902 return g_security_callback_result;
2903}
2904
2905
2906static int trouble_nesting = 0;
2907static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
2908 ApiTestFuzzer::Fuzz();
2909 trouble_nesting++;
2910
2911 // Call a JS function that throws an uncaught exception.
2912 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
2913 Local<Value> trouble_callee = (trouble_nesting == 3) ?
2914 arg_this->Get(v8_str("trouble_callee")) :
2915 arg_this->Get(v8_str("trouble_caller"));
2916 CHECK(trouble_callee->IsFunction());
2917 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
2918}
2919
2920
2921static int report_count = 0;
2922static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
2923 v8::Handle<Value>) {
2924 report_count++;
2925}
2926
2927
2928// Counts uncaught exceptions, but other tests running in parallel
2929// also have uncaught exceptions.
2930TEST(ApiUncaughtException) {
2931 v8::HandleScope scope;
2932 LocalContext env;
2933 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
2934
2935 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
2936 v8::Local<v8::Object> global = env->Global();
2937 global->Set(v8_str("trouble"), fun->GetFunction());
2938
2939 Script::Compile(v8_str("function trouble_callee() {"
2940 " var x = null;"
2941 " return x.foo;"
2942 "};"
2943 "function trouble_caller() {"
2944 " trouble();"
2945 "};"))->Run();
2946 Local<Value> trouble = global->Get(v8_str("trouble"));
2947 CHECK(trouble->IsFunction());
2948 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
2949 CHECK(trouble_callee->IsFunction());
2950 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
2951 CHECK(trouble_caller->IsFunction());
2952 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
2953 CHECK_EQ(1, report_count);
2954}
2955
2956
2957// SecurityHandler can't be run twice
2958TEST(SecurityHandler) {
2959 v8::HandleScope scope0;
2960 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2961 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
2962 IndexedSecurityTestCallback);
2963 // Create an environment
2964 v8::Persistent<Context> context0 =
2965 Context::New(NULL, global_template);
2966 context0->Enter();
2967
2968 v8::Handle<v8::Object> global0 = context0->Global();
2969 v8::Handle<Script> script0 = v8_compile("foo = 111");
2970 script0->Run();
2971 global0->Set(v8_str("0"), v8_num(999));
2972 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
2973 CHECK_EQ(111, foo0->Int32Value());
2974 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
2975 CHECK_EQ(999, z0->Int32Value());
2976
2977 // Create another environment, should fail security checks.
2978 v8::HandleScope scope1;
2979
2980 v8::Persistent<Context> context1 =
2981 Context::New(NULL, global_template);
2982 context1->Enter();
2983
2984 v8::Handle<v8::Object> global1 = context1->Global();
2985 global1->Set(v8_str("othercontext"), global0);
2986 // This set will fail the security check.
2987 v8::Handle<Script> script1 =
2988 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
2989 script1->Run();
2990 // This read will pass the security check.
2991 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
2992 CHECK_EQ(111, foo1->Int32Value());
2993 // This read will pass the security check.
2994 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
2995 CHECK_EQ(999, z1->Int32Value());
2996
2997 // Create another environment, should pass security checks.
2998 { g_security_callback_result = true; // allow security handler to pass.
2999 v8::HandleScope scope2;
3000 LocalContext context2;
3001 v8::Handle<v8::Object> global2 = context2->Global();
3002 global2->Set(v8_str("othercontext"), global0);
3003 v8::Handle<Script> script2 =
3004 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3005 script2->Run();
3006 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3007 CHECK_EQ(333, foo2->Int32Value());
3008 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3009 CHECK_EQ(888, z2->Int32Value());
3010 }
3011
3012 context1->Exit();
3013 context1.Dispose();
3014
3015 context0->Exit();
3016 context0.Dispose();
3017}
3018
3019
3020THREADED_TEST(SecurityChecks) {
3021 v8::HandleScope handle_scope;
3022 LocalContext env1;
3023 v8::Persistent<Context> env2 = Context::New();
3024
3025 Local<Value> foo = v8_str("foo");
3026 Local<Value> bar = v8_str("bar");
3027
3028 // Set to the same domain.
3029 env1->SetSecurityToken(foo);
3030
3031 // Create a function in env1.
3032 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3033 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3034 CHECK(spy->IsFunction());
3035
3036 // Create another function accessing global objects.
3037 Script::Compile(v8_str("spy2=function(){return new Array();}"))->Run();
3038 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3039 CHECK(spy2->IsFunction());
3040
3041 // Switch to env2 in the same domain and invoke spy on env2.
3042 {
3043 env2->SetSecurityToken(foo);
3044 // Enter env2
3045 Context::Scope scope_env2(env2);
3046 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3047 CHECK(result->IsFunction());
3048 }
3049
3050 // Change env2 to a new domain and invoke spy on env2. It should be blocked
3051 // by security check.
3052 {
3053 env2->SetSecurityToken(bar);
3054 Context::Scope scope_env2(env2);
3055 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3056 CHECK(result->IsUndefined());
3057
3058 // Call cross_domain_call, it should throw an exception
3059 v8::TryCatch try_catch;
3060 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3061 CHECK(try_catch.HasCaught());
3062 }
3063
3064 env2.Dispose();
3065}
3066
3067
3068// Regression test case for issue 1183439.
3069THREADED_TEST(SecurityChecksForPrototypeChain) {
3070 v8::HandleScope scope;
3071 LocalContext current;
3072 v8::Persistent<Context> other = Context::New();
3073
3074 // Change context to be able to get to the Object function in the
3075 // other context without hitting the security checks.
3076 v8::Local<Value> other_object;
3077 { Context::Scope scope(other);
3078 other_object = other->Global()->Get(v8_str("Object"));
3079 other->Global()->Set(v8_num(42), v8_num(87));
3080 }
3081
3082 current->Global()->Set(v8_str("other"), other->Global());
3083 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3084
3085 // Make sure the security check fails here and we get an undefined
3086 // result instead of getting the Object function. Repeat in a loop
3087 // to make sure to exercise the IC code.
3088 v8::Local<Script> access_other0 = v8_compile("other.Object");
3089 v8::Local<Script> access_other1 = v8_compile("other[42]");
3090 for (int i = 0; i < 5; i++) {
3091 CHECK(!access_other0->Run()->Equals(other_object));
3092 CHECK(access_other0->Run()->IsUndefined());
3093 CHECK(!access_other1->Run()->Equals(v8_num(87)));
3094 CHECK(access_other1->Run()->IsUndefined());
3095 }
3096
3097 // Create an object that has 'other' in its prototype chain and make
3098 // sure we cannot access the Object function indirectly through
3099 // that. Repeat in a loop to make sure to exercise the IC code.
3100 v8_compile("function F() { };"
3101 "F.prototype = other;"
3102 "var f = new F();")->Run();
3103 v8::Local<Script> access_f0 = v8_compile("f.Object");
3104 v8::Local<Script> access_f1 = v8_compile("f[42]");
3105 for (int j = 0; j < 5; j++) {
3106 CHECK(!access_f0->Run()->Equals(other_object));
3107 CHECK(access_f0->Run()->IsUndefined());
3108 CHECK(!access_f1->Run()->Equals(v8_num(87)));
3109 CHECK(access_f1->Run()->IsUndefined());
3110 }
3111
3112 // Now it gets hairy: Set the prototype for the other global object
3113 // to be the current global object. The prototype chain for 'f' now
3114 // goes through 'other' but ends up in the current global object.
3115 { Context::Scope scope(other);
3116 other->Global()->Set(v8_str("__proto__"), current->Global());
3117 }
3118 // Set a named and an index property on the current global
3119 // object. To force the lookup to go through the other global object,
3120 // the properties must not exist in the other global object.
3121 current->Global()->Set(v8_str("foo"), v8_num(100));
3122 current->Global()->Set(v8_num(99), v8_num(101));
3123 // Try to read the properties from f and make sure that the access
3124 // gets stopped by the security checks on the other global object.
3125 Local<Script> access_f2 = v8_compile("f.foo");
3126 Local<Script> access_f3 = v8_compile("f[99]");
3127 for (int k = 0; k < 5; k++) {
3128 CHECK(!access_f2->Run()->Equals(v8_num(100)));
3129 CHECK(access_f2->Run()->IsUndefined());
3130 CHECK(!access_f3->Run()->Equals(v8_num(101)));
3131 CHECK(access_f3->Run()->IsUndefined());
3132 }
3133 other.Dispose();
3134}
3135
3136
3137THREADED_TEST(CrossDomainDelete) {
3138 v8::HandleScope handle_scope;
3139 LocalContext env1;
3140 v8::Persistent<Context> env2 = Context::New();
3141
3142 Local<Value> foo = v8_str("foo");
3143 Local<Value> bar = v8_str("bar");
3144
3145 // Set to the same domain.
3146 env1->SetSecurityToken(foo);
3147 env2->SetSecurityToken(foo);
3148
3149 env1->Global()->Set(v8_str("prop"), v8_num(3));
3150 env2->Global()->Set(v8_str("env1"), env1->Global());
3151
3152 // Change env2 to a different domain and delete env1.prop.
3153 env2->SetSecurityToken(bar);
3154 {
3155 Context::Scope scope_env2(env2);
3156 Local<Value> result =
3157 Script::Compile(v8_str("delete env1.prop"))->Run();
3158 CHECK(result->IsFalse());
3159 }
3160
3161 // Check that env1.prop still exists.
3162 Local<Value> v = env1->Global()->Get(v8_str("prop"));
3163 CHECK(v->IsNumber());
3164 CHECK_EQ(3, v->Int32Value());
3165
3166 env2.Dispose();
3167}
3168
3169
3170
3171static bool NamedAccessBlocker(Local<v8::Object> global,
3172 Local<Value> name,
3173 v8::AccessType type,
3174 Local<Value> data) {
3175 return Context::GetCurrentSecurityContext()->Global()->Equals(global);
3176}
3177
3178
3179static bool IndexedAccessBlocker(Local<v8::Object> global,
3180 uint32_t key,
3181 v8::AccessType type,
3182 Local<Value> data) {
3183 return Context::GetCurrentSecurityContext()->Global()->Equals(global);
3184}
3185
3186
3187static int g_echo_value = -1;
3188static v8::Handle<Value> EchoGetter(Local<String> name,
3189 const AccessorInfo& info) {
3190 return v8_num(g_echo_value);
3191}
3192
3193
3194static void EchoSetter(Local<String> name,
3195 Local<Value> value,
3196 const AccessorInfo& info) {
3197 if (value->IsNumber())
3198 g_echo_value = value->Int32Value();
3199}
3200
3201
3202static v8::Handle<Value> UnreachableGetter(Local<String> name,
3203 const AccessorInfo& info) {
3204 CHECK(false); // This function should not be called..
3205 return v8::Undefined();
3206}
3207
3208
3209static void UnreachableSetter(Local<String> name,
3210 Local<Value> value,
3211 const AccessorInfo& info) {
3212 CHECK(false); // This function should nto be called.
3213}
3214
3215
3216THREADED_TEST(AccessControl) {
3217 v8::HandleScope handle_scope;
3218 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3219
3220 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
3221 IndexedAccessBlocker);
3222
3223 // Add an accessor accessible by cross-domain JS code.
3224 global_template->SetAccessor(
3225 v8_str("accessible_prop"),
3226 EchoGetter, EchoSetter,
3227 v8::Handle<Value>(),
3228 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
3229
3230 // Add an accessor that is not accessible by cross-domain JS code.
3231 global_template->SetAccessor(v8_str("blocked_access_prop"),
3232 UnreachableGetter, UnreachableSetter,
3233 v8::Handle<Value>(),
3234 v8::DEFAULT);
3235
3236 // Create an environment
3237 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3238 context0->Enter();
3239
3240 v8::Handle<v8::Object> global0 = context0->Global();
3241
3242 v8::HandleScope scope1;
3243
3244 v8::Persistent<Context> context1 = Context::New();
3245 context1->Enter();
3246
3247 v8::Handle<v8::Object> global1 = context1->Global();
3248 global1->Set(v8_str("other"), global0);
3249
3250 v8::Handle<Value> value;
3251
3252 // Access blocked property
3253 value = v8_compile("other.blocked_prop = 1")->Run();
3254 value = v8_compile("other.blocked_prop")->Run();
3255 CHECK(value->IsUndefined());
3256
3257 // Access accessible property
3258 value = v8_compile("other.accessible_prop = 3")->Run();
3259 CHECK(value->IsNumber());
3260 CHECK_EQ(3, value->Int32Value());
3261
3262 value = v8_compile("other.accessible_prop")->Run();
3263 CHECK(value->IsNumber());
3264 CHECK_EQ(3, value->Int32Value());
3265
3266 context1->Exit();
3267 context0->Exit();
3268 context1.Dispose();
3269 context0.Dispose();
3270}
3271
3272
3273static v8::Handle<Value> ConstTenGetter(Local<String> name,
3274 const AccessorInfo& info) {
3275 return v8_num(10);
3276}
3277
3278
3279THREADED_TEST(CrossDomainAccessors) {
3280 v8::HandleScope handle_scope;
3281
3282 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
3283
3284 v8::Handle<v8::ObjectTemplate> global_template =
3285 func_template->InstanceTemplate();
3286
3287 v8::Handle<v8::ObjectTemplate> proto_template =
3288 func_template->PrototypeTemplate();
3289
3290 // Add an accessor to proto that's accessible by cross-domain JS code.
3291 proto_template->SetAccessor(v8_str("accessible"),
3292 ConstTenGetter, 0,
3293 v8::Handle<Value>(),
3294 v8::ALL_CAN_READ);
3295
3296 // Add an accessor that is not accessible by cross-domain JS code.
3297 global_template->SetAccessor(v8_str("unreachable"),
3298 UnreachableGetter, 0,
3299 v8::Handle<Value>(),
3300 v8::DEFAULT);
3301
3302 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3303 context0->Enter();
3304
3305 Local<v8::Object> global = context0->Global();
3306 // Add a normal property that shadows 'accessible'
3307 global->Set(v8_str("accessible"), v8_num(11));
3308
3309 // Enter a new context.
3310 v8::HandleScope scope1;
3311 v8::Persistent<Context> context1 = Context::New();
3312 context1->Enter();
3313
3314 v8::Handle<v8::Object> global1 = context1->Global();
3315 global1->Set(v8_str("other"), global);
3316
3317 // Should return 10, instead of 11
3318 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
3319 CHECK(value->IsNumber());
3320 CHECK_EQ(10, value->Int32Value());
3321
3322 value = v8_compile("other.unreachable")->Run();
3323 CHECK(value->IsUndefined());
3324
3325 context1->Exit();
3326 context0->Exit();
3327 context1.Dispose();
3328 context0.Dispose();
3329}
3330
3331
3332static int named_access_count = 0;
3333static int indexed_access_count = 0;
3334
3335static bool NamedAccessCounter(Local<v8::Object> global,
3336 Local<Value> name,
3337 v8::AccessType type,
3338 Local<Value> data) {
3339 named_access_count++;
3340 return true;
3341}
3342
3343
3344static bool IndexedAccessCounter(Local<v8::Object> global,
3345 uint32_t key,
3346 v8::AccessType type,
3347 Local<Value> data) {
3348 indexed_access_count++;
3349 return true;
3350}
3351
3352
3353// This one is too easily disturbed by other tests.
3354TEST(AccessControlIC) {
3355 named_access_count = 0;
3356 indexed_access_count = 0;
3357
3358 v8::HandleScope handle_scope;
3359
3360 // Create an environment.
3361 v8::Persistent<Context> context0 = Context::New();
3362 context0->Enter();
3363
3364 // Create an object that requires access-check functions to be
3365 // called for cross-domain access.
3366 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3367 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
3368 IndexedAccessCounter);
3369 Local<v8::Object> object = object_template->NewInstance();
3370
3371 v8::HandleScope scope1;
3372
3373 // Create another environment.
3374 v8::Persistent<Context> context1 = Context::New();
3375 context1->Enter();
3376
3377 // Make easy access to the object from the other environment.
3378 v8::Handle<v8::Object> global1 = context1->Global();
3379 global1->Set(v8_str("obj"), object);
3380
3381 v8::Handle<Value> value;
3382
3383 // Check that the named access-control function is called every time.
3384 value = v8_compile("for (var i = 0; i < 10; i++) obj.prop = 1;")->Run();
3385 value = v8_compile("for (var i = 0; i < 10; i++) obj.prop;"
3386 "obj.prop")->Run();
3387 CHECK(value->IsNumber());
3388 CHECK_EQ(1, value->Int32Value());
3389 CHECK_EQ(21, named_access_count);
3390
3391 // Check that the named access-control function is called every time.
3392 value = v8_compile("var p = 'prop';")->Run();
3393 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
3394 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
3395 "obj[p]")->Run();
3396 CHECK(value->IsNumber());
3397 CHECK_EQ(1, value->Int32Value());
3398 CHECK_EQ(42, named_access_count);
3399
3400 // Check that the indexed access-control function is called every time.
3401 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
3402 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
3403 "obj[0]")->Run();
3404 CHECK(value->IsNumber());
3405 CHECK_EQ(1, value->Int32Value());
3406 CHECK_EQ(21, indexed_access_count);
3407
3408 context1->Exit();
3409 context0->Exit();
3410 context1.Dispose();
3411 context0.Dispose();
3412}
3413
3414
3415static bool NamedAccessFlatten(Local<v8::Object> global,
3416 Local<Value> name,
3417 v8::AccessType type,
3418 Local<Value> data) {
3419 char buf[100];
3420 int len;
3421
3422 CHECK(name->IsString());
3423
3424 memset(buf, 0x1, sizeof(buf));
3425 len = Local<String>::Cast(name)->WriteAscii(buf);
3426 CHECK_EQ(4, len);
3427
3428 uint16_t buf2[100];
3429
3430 memset(buf, 0x1, sizeof(buf));
3431 len = Local<String>::Cast(name)->Write(buf2);
3432 CHECK_EQ(4, len);
3433
3434 return true;
3435}
3436
3437
3438static bool IndexedAccessFlatten(Local<v8::Object> global,
3439 uint32_t key,
3440 v8::AccessType type,
3441 Local<Value> data) {
3442 return true;
3443}
3444
3445
3446// Regression test. In access checks, operations that may cause
3447// garbage collection are not allowed. It used to be the case that
3448// using the Write operation on a string could cause a garbage
3449// collection due to flattening of the string. This is no longer the
3450// case.
3451THREADED_TEST(AccessControlFlatten) {
3452 named_access_count = 0;
3453 indexed_access_count = 0;
3454
3455 v8::HandleScope handle_scope;
3456
3457 // Create an environment.
3458 v8::Persistent<Context> context0 = Context::New();
3459 context0->Enter();
3460
3461 // Create an object that requires access-check functions to be
3462 // called for cross-domain access.
3463 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3464 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
3465 IndexedAccessFlatten);
3466 Local<v8::Object> object = object_template->NewInstance();
3467
3468 v8::HandleScope scope1;
3469
3470 // Create another environment.
3471 v8::Persistent<Context> context1 = Context::New();
3472 context1->Enter();
3473
3474 // Make easy access to the object from the other environment.
3475 v8::Handle<v8::Object> global1 = context1->Global();
3476 global1->Set(v8_str("obj"), object);
3477
3478 v8::Handle<Value> value;
3479
3480 value = v8_compile("var p = 'as' + 'df';")->Run();
3481 value = v8_compile("obj[p];")->Run();
3482
3483 context1->Exit();
3484 context0->Exit();
3485 context1.Dispose();
3486 context0.Dispose();
3487}
3488
3489
3490static v8::Handle<Value> AccessControlNamedGetter(Local<String> name,
3491 const AccessorInfo& info) {
3492 return v8::Integer::New(42);
3493}
3494
3495
3496static v8::Handle<Value> AccessControlNamedSetter(Local<String> key,
3497 Local<Value> value,
3498 const AccessorInfo&) {
3499 return value;
3500}
3501
3502
3503static v8::Handle<Value> AccessControlIndexedGetter(
3504 uint32_t index,
3505 const AccessorInfo& info) {
3506 return v8_num(42);
3507}
3508
3509
3510static v8::Handle<Value> AccessControlIndexedSetter(uint32_t index,
3511 Local<Value> value,
3512 const AccessorInfo&) {
3513 return value;
3514}
3515
3516
3517THREADED_TEST(AccessControlInterceptorIC) {
3518 named_access_count = 0;
3519 indexed_access_count = 0;
3520
3521 v8::HandleScope handle_scope;
3522
3523 // Create an environment.
3524 v8::Persistent<Context> context0 = Context::New();
3525 context0->Enter();
3526
3527 // Create an object that requires access-check functions to be
3528 // called for cross-domain access. The object also has interceptors
3529 // interceptor.
3530 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
3531 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
3532 IndexedAccessCounter);
3533 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
3534 AccessControlNamedSetter);
3535 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
3536 AccessControlIndexedSetter);
3537 Local<v8::Object> object = object_template->NewInstance();
3538
3539 v8::HandleScope scope1;
3540
3541 // Create another environment.
3542 v8::Persistent<Context> context1 = Context::New();
3543 context1->Enter();
3544
3545 // Make easy access to the object from the other environment.
3546 v8::Handle<v8::Object> global1 = context1->Global();
3547 global1->Set(v8_str("obj"), object);
3548
3549 v8::Handle<Value> value;
3550
3551 // Check that the named access-control function is called every time
3552 // eventhough there is an interceptor on the object.
3553 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
3554 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
3555 "obj.x")->Run();
3556 CHECK(value->IsNumber());
3557 CHECK_EQ(42, value->Int32Value());
3558 CHECK_EQ(21, named_access_count);
3559
3560 value = v8_compile("var p = 'x';")->Run();
3561 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
3562 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
3563 "obj[p]")->Run();
3564 CHECK(value->IsNumber());
3565 CHECK_EQ(42, value->Int32Value());
3566 CHECK_EQ(42, named_access_count);
3567
3568 // Check that the indexed access-control function is called every
3569 // time eventhough there is an interceptor on the object.
3570 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
3571 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
3572 "obj[0]")->Run();
3573 CHECK(value->IsNumber());
3574 CHECK_EQ(42, value->Int32Value());
3575 CHECK_EQ(21, indexed_access_count);
3576
3577 context1->Exit();
3578 context0->Exit();
3579 context1.Dispose();
3580 context0.Dispose();
3581}
3582
3583
3584THREADED_TEST(Version) {
3585 v8::V8::GetVersion();
3586}
3587
3588
3589static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
3590 ApiTestFuzzer::Fuzz();
3591 return v8_num(12);
3592}
3593
3594
3595THREADED_TEST(InstanceProperties) {
3596 v8::HandleScope handle_scope;
3597 LocalContext context;
3598
3599 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3600 Local<ObjectTemplate> instance = t->InstanceTemplate();
3601
3602 instance->Set(v8_str("x"), v8_num(42));
3603 instance->Set(v8_str("f"),
3604 v8::FunctionTemplate::New(InstanceFunctionCallback));
3605
3606 Local<Value> o = t->GetFunction()->NewInstance();
3607
3608 context->Global()->Set(v8_str("i"), o);
3609 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
3610 CHECK_EQ(42, value->Int32Value());
3611
3612 value = Script::Compile(v8_str("i.f()"))->Run();
3613 CHECK_EQ(12, value->Int32Value());
3614}
3615
3616
3617static v8::Handle<Value>
3618GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
3619 ApiTestFuzzer::Fuzz();
3620 return v8::Handle<Value>();
3621}
3622
3623
3624THREADED_TEST(GlobalObjectInstanceProperties) {
3625 v8::HandleScope handle_scope;
3626
3627 Local<Value> global_object;
3628
3629 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3630 t->InstanceTemplate()->SetNamedPropertyHandler(
3631 GlobalObjectInstancePropertiesGet);
3632 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
3633 instance_template->Set(v8_str("x"), v8_num(42));
3634 instance_template->Set(v8_str("f"),
3635 v8::FunctionTemplate::New(InstanceFunctionCallback));
3636
3637 {
3638 LocalContext env(NULL, instance_template);
3639 // Hold on to the global object so it can be used again in another
3640 // environment initialization.
3641 global_object = env->Global();
3642
3643 Local<Value> value = Script::Compile(v8_str("x"))->Run();
3644 CHECK_EQ(42, value->Int32Value());
3645 value = Script::Compile(v8_str("f()"))->Run();
3646 CHECK_EQ(12, value->Int32Value());
3647 }
3648
3649 {
3650 // Create new environment reusing the global object.
3651 LocalContext env(NULL, instance_template, global_object);
3652 Local<Value> value = Script::Compile(v8_str("x"))->Run();
3653 CHECK_EQ(42, value->Int32Value());
3654 value = Script::Compile(v8_str("f()"))->Run();
3655 CHECK_EQ(12, value->Int32Value());
3656 }
3657}
3658
3659
3660static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
3661 ApiTestFuzzer::Fuzz();
3662 return v8_num(42);
3663}
3664
3665
3666static int shadow_y;
3667static int shadow_y_setter_call_count;
3668static int shadow_y_getter_call_count;
3669
3670
3671static void ShadowYSetter(Local<String> name,
3672 Local<Value> value,
3673 const AccessorInfo& info) {
3674 shadow_y_setter_call_count++;
3675 shadow_y = 42;
3676}
3677
3678
3679static v8::Handle<Value> ShadowYGetter(Local<String> name,
3680 const AccessorInfo& info) {
3681 ApiTestFuzzer::Fuzz();
3682 shadow_y_getter_call_count++;
3683 return v8_num(shadow_y);
3684}
3685
3686
3687static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
3688 const AccessorInfo& info) {
3689 return v8::Handle<Value>();
3690}
3691
3692
3693static v8::Handle<Value> ShadowNamedGet(Local<String> key,
3694 const AccessorInfo&) {
3695 return v8::Handle<Value>();
3696}
3697
3698
3699THREADED_TEST(ShadowObject) {
3700 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
3701 v8::HandleScope handle_scope;
3702
3703 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
3704 LocalContext context(NULL, global_template);
3705
3706 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3707 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
3708 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
3709 Local<ObjectTemplate> proto = t->PrototypeTemplate();
3710 Local<ObjectTemplate> instance = t->InstanceTemplate();
3711
3712 // Only allow calls of f on instances of t.
3713 Local<v8::Signature> signature = v8::Signature::New(t);
3714 proto->Set(v8_str("f"),
3715 v8::FunctionTemplate::New(ShadowFunctionCallback,
3716 Local<Value>(),
3717 signature));
3718 proto->Set(v8_str("x"), v8_num(12));
3719
3720 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
3721
3722 Local<Value> o = t->GetFunction()->NewInstance();
3723 context->Global()->Set(v8_str("__proto__"), o);
3724
3725 Local<Value> value =
3726 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
3727 CHECK(value->IsBoolean());
3728 CHECK(!value->BooleanValue());
3729
3730 value = Script::Compile(v8_str("x"))->Run();
3731 CHECK_EQ(12, value->Int32Value());
3732
3733 value = Script::Compile(v8_str("f()"))->Run();
3734 CHECK_EQ(42, value->Int32Value());
3735
3736 Script::Compile(v8_str("y = 42"))->Run();
3737 CHECK_EQ(1, shadow_y_setter_call_count);
3738 value = Script::Compile(v8_str("y"))->Run();
3739 CHECK_EQ(1, shadow_y_getter_call_count);
3740 CHECK_EQ(42, value->Int32Value());
3741}
3742
3743
3744THREADED_TEST(HiddenPrototype) {
3745 v8::HandleScope handle_scope;
3746 LocalContext context;
3747
3748 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
3749 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
3750 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
3751 t1->SetHiddenPrototype(true);
3752 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
3753 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
3754 t2->SetHiddenPrototype(true);
3755 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
3756 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
3757 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
3758
3759 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
3760 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
3761 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
3762 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
3763
3764 // Setting the prototype on an object skips hidden prototypes.
3765 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3766 o0->Set(v8_str("__proto__"), o1);
3767 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3768 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3769 o0->Set(v8_str("__proto__"), o2);
3770 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3771 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3772 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
3773 o0->Set(v8_str("__proto__"), o3);
3774 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
3775 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
3776 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
3777 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
3778
3779 // Getting the prototype of o0 should get the first visible one
3780 // which is o3. Therefore, z should not be defined on the prototype
3781 // object.
3782 Local<Value> proto = o0->Get(v8_str("__proto__"));
3783 CHECK(proto->IsObject());
3784 CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
3785}
3786
3787
3788THREADED_TEST(GetterSetterExceptions) {
3789 v8::HandleScope handle_scope;
3790 LocalContext context;
3791 CompileRun(
3792 "function Foo() { };"
3793 "function Throw() { throw 5; };"
3794 "var x = { };"
3795 "x.__defineSetter__('set', Throw);"
3796 "x.__defineGetter__('get', Throw);");
3797 Local<v8::Object> x =
3798 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
3799 v8::TryCatch try_catch;
3800 x->Set(v8_str("set"), v8::Integer::New(8));
3801 x->Get(v8_str("get"));
3802 x->Set(v8_str("set"), v8::Integer::New(8));
3803 x->Get(v8_str("get"));
3804 x->Set(v8_str("set"), v8::Integer::New(8));
3805 x->Get(v8_str("get"));
3806 x->Set(v8_str("set"), v8::Integer::New(8));
3807 x->Get(v8_str("get"));
3808}
3809
3810
3811THREADED_TEST(Constructor) {
3812 v8::HandleScope handle_scope;
3813 LocalContext context;
3814 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
3815 templ->SetClassName(v8_str("Fun"));
3816 Local<Function> cons = templ->GetFunction();
3817 context->Global()->Set(v8_str("Fun"), cons);
3818 Local<v8::Object> inst = cons->NewInstance();
3819 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
3820 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
3821 CHECK(value->BooleanValue());
3822}
3823
3824THREADED_TEST(FunctionDescriptorException) {
3825 v8::HandleScope handle_scope;
3826 LocalContext context;
3827 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
3828 templ->SetClassName(v8_str("Fun"));
3829 Local<Function> cons = templ->GetFunction();
3830 context->Global()->Set(v8_str("Fun"), cons);
3831 Local<Value> value = CompileRun(
3832 "function test() {"
3833 " try {"
3834 " (new Fun()).blah()"
3835 " } catch (e) {"
3836 " var str = String(e);"
3837 " if (str.indexOf('TypeError') == -1) return 1;"
3838 " if (str.indexOf('[object Fun]') != -1) return 2;"
3839 " if (str.indexOf('#<a Fun>') == -1) return 3;"
3840 " return 0;"
3841 " }"
3842 " return 4;"
3843 "}"
3844 "test();");
3845 CHECK_EQ(0, value->Int32Value());
3846}
3847
3848
3849THREADED_TEST(CrossEval) {
3850 v8::HandleScope scope;
3851 LocalContext other;
3852 LocalContext current;
3853
3854 Local<String> token = v8_str("<security token>");
3855 other->SetSecurityToken(token);
3856 current->SetSecurityToken(token);
3857
3858 // Setup reference from current to other.
3859 current->Global()->Set(v8_str("other"), other->Global());
3860
3861 // Check that new variables are introduced in other context.
3862 Local<Script> script =
3863 Script::Compile(v8_str("other.eval('var foo = 1234')"));
3864 script->Run();
3865 Local<Value> foo = other->Global()->Get(v8_str("foo"));
3866 CHECK_EQ(1234, foo->Int32Value());
3867 CHECK(!current->Global()->Has(v8_str("foo")));
3868
3869 // Check that writing to non-existing properties introduces them in
3870 // the current context.
3871 script =
3872 Script::Compile(v8_str("other.eval('na = 1234')"));
3873 script->Run();
3874 CHECK_EQ(1234, current->Global()->Get(v8_str("na"))->Int32Value());
3875 CHECK(!other->Global()->Has(v8_str("na")));
3876
3877 // Check that variables in current context are visible in other
3878 // context. This must include local variables.
3879 script =
3880 Script::Compile(v8_str("var bar = 42;"
3881 "(function() { "
3882 " var baz = 87;"
3883 " return other.eval('bar + baz');"
3884 "})();"));
3885 Local<Value> result = script->Run();
3886 CHECK_EQ(42 + 87, result->Int32Value());
3887
3888 // Check that global variables in the other environment are visible
3889 // when evaluting code.
3890 other->Global()->Set(v8_str("bis"), v8_num(1234));
3891 script = Script::Compile(v8_str("other.eval('bis')"));
3892 CHECK_EQ(1234, script->Run()->Int32Value());
3893
3894 // Check that the 'this' pointer isn't touched as a result of
3895 // calling eval across environments.
3896 script =
3897 Script::Compile(v8_str("var t = this; other.eval('this == t')"));
3898 result = script->Run();
3899 CHECK(result->IsBoolean());
3900 CHECK(result->BooleanValue());
3901
3902 // Check that doing a cross eval works from within a global
3903 // with-statement.
3904 script =
3905 Script::Compile(v8_str("other.y = 1;"
3906 "with({x:2}){other.eval('x+y')}"));
3907 result = script->Run();
3908 CHECK_EQ(3, result->Int32Value());
3909}
3910
3911
3912THREADED_TEST(CrossLazyLoad) {
3913 v8::HandleScope scope;
3914 LocalContext other;
3915 LocalContext current;
3916
3917 Local<String> token = v8_str("<security token>");
3918 other->SetSecurityToken(token);
3919 current->SetSecurityToken(token);
3920
3921 // Setup reference from current to other.
3922 current->Global()->Set(v8_str("other"), other->Global());
3923
3924 // Trigger lazy loading in other context.
3925 Local<Script> script =
3926 Script::Compile(v8_str("other.eval('new Date(42)')"));
3927 Local<Value> value = script->Run();
3928 CHECK_EQ(42.0, value->NumberValue());
3929}
3930
3931
3932static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
3933 ApiTestFuzzer::Fuzz();
3934 return args[0];
3935}
3936
3937
3938// Test that a call handler can be set for objects which will allow
3939// non-function objects created through the API to be called as
3940// functions.
3941THREADED_TEST(CallAsFunction) {
3942 v8::HandleScope scope;
3943 LocalContext context;
3944
3945 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
3946 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
3947 instance_template->SetCallAsFunctionHandler(call_as_function);
3948 Local<v8::Object> instance = t->GetFunction()->NewInstance();
3949 context->Global()->Set(v8_str("obj"), instance);
3950 v8::TryCatch try_catch;
3951 Local<Value> value;
3952 CHECK(!try_catch.HasCaught());
3953
3954 value = Script::Compile(v8_str("obj(42)"))->Run();
3955 CHECK(!try_catch.HasCaught());
3956 CHECK_EQ(42, value->Int32Value());
3957
3958 value = Script::Compile(v8_str("(function(o){return o(49)})(obj)"))->Run();
3959 CHECK(!try_catch.HasCaught());
3960 CHECK_EQ(49, value->Int32Value());
3961
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003962 // test special case of call as function
3963 value = Script::Compile(v8_str("[obj]['0'](45)"))->Run();
3964 CHECK(!try_catch.HasCaught());
3965 CHECK_EQ(45, value->Int32Value());
3966
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003967 value = Script::Compile(v8_str("obj.call = Function.prototype.call;"
3968 "obj.call(null, 87)"))->Run();
3969 CHECK(!try_catch.HasCaught());
3970 CHECK_EQ(87, value->Int32Value());
3971
3972 // Regression tests for bug #1116356: Calling call through call/apply
3973 // must work for non-function receivers.
3974 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
3975 value = Script::Compile(v8_str(apply_99))->Run();
3976 CHECK(!try_catch.HasCaught());
3977 CHECK_EQ(99, value->Int32Value());
3978
3979 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
3980 value = Script::Compile(v8_str(call_17))->Run();
3981 CHECK(!try_catch.HasCaught());
3982 CHECK_EQ(17, value->Int32Value());
3983
3984 // Try something that will cause an exception: Call the object as a
3985 // constructor. This should be the last test.
3986 value = Script::Compile(v8_str("new obj(42)"))->Run();
3987 CHECK(try_catch.HasCaught());
3988}
3989
3990
3991static int CountHandles() {
3992 return v8::HandleScope::NumberOfHandles();
3993}
3994
3995
3996static int Recurse(int depth, int iterations) {
3997 v8::HandleScope scope;
3998 if (depth == 0) return CountHandles();
3999 for (int i = 0; i < iterations; i++) {
4000 Local<v8::Number> n = v8::Integer::New(42);
4001 }
4002 return Recurse(depth - 1, iterations);
4003}
4004
4005
4006THREADED_TEST(HandleIteration) {
4007 static const int kIterations = 500;
4008 static const int kNesting = 200;
4009 CHECK_EQ(0, CountHandles());
4010 {
4011 v8::HandleScope scope1;
4012 CHECK_EQ(0, CountHandles());
4013 for (int i = 0; i < kIterations; i++) {
4014 Local<v8::Number> n = v8::Integer::New(42);
4015 CHECK_EQ(i + 1, CountHandles());
4016 }
4017
4018 CHECK_EQ(kIterations, CountHandles());
4019 {
4020 v8::HandleScope scope2;
4021 for (int j = 0; j < kIterations; j++) {
4022 Local<v8::Number> n = v8::Integer::New(42);
4023 CHECK_EQ(j + 1 + kIterations, CountHandles());
4024 }
4025 }
4026 CHECK_EQ(kIterations, CountHandles());
4027 }
4028 CHECK_EQ(0, CountHandles());
4029 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
4030}
4031
4032
4033static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
4034 Local<String> name,
4035 const AccessorInfo& info) {
4036 ApiTestFuzzer::Fuzz();
4037 return v8::Handle<Value>();
4038}
4039
4040
4041THREADED_TEST(InterceptorHasOwnProperty) {
4042 v8::HandleScope scope;
4043 LocalContext context;
4044 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4045 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
4046 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
4047 Local<Function> function = fun_templ->GetFunction();
4048 context->Global()->Set(v8_str("constructor"), function);
4049 v8::Handle<Value> value = CompileRun(
4050 "var o = new constructor();"
4051 "o.hasOwnProperty('ostehaps');");
4052 CHECK_EQ(false, value->BooleanValue());
4053 value = CompileRun(
4054 "o.ostehaps = 42;"
4055 "o.hasOwnProperty('ostehaps');");
4056 CHECK_EQ(true, value->BooleanValue());
4057 value = CompileRun(
4058 "var p = new constructor();"
4059 "p.hasOwnProperty('ostehaps');");
4060 CHECK_EQ(false, value->BooleanValue());
4061}
4062
4063
4064static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
4065 const AccessorInfo& info) {
4066 ApiTestFuzzer::Fuzz();
4067 CHECK(v8_str("x")->Equals(name));
4068 return v8::Integer::New(42);
4069}
4070
4071
4072// This test should hit the load IC for the interceptor case.
4073THREADED_TEST(InterceptorLoadIC) {
4074 v8::HandleScope scope;
4075 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4076 templ->SetNamedPropertyHandler(InterceptorLoadICGetter);
4077 LocalContext context;
4078 context->Global()->Set(v8_str("o"), templ->NewInstance());
4079 v8::Handle<Value> value = CompileRun(
4080 "var result = 0;"
4081 "for (var i = 0; i < 1000; i++) {"
4082 " result = o.x;"
4083 "}");
4084 CHECK_EQ(42, value->Int32Value());
4085}
4086
4087
4088static v8::Handle<Value> InterceptorStoreICSetter(
4089 Local<String> key,
4090 Local<Value> value,
4091 const AccessorInfo&) {
4092 CHECK(v8_str("x")->Equals(key));
4093 CHECK_EQ(42, value->Int32Value());
4094 return value;
4095}
4096
4097
4098// This test should hit the store IC for the interceptor case.
4099THREADED_TEST(InterceptorStoreIC) {
4100 v8::HandleScope scope;
4101 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4102 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
4103 InterceptorStoreICSetter);
4104 LocalContext context;
4105 context->Global()->Set(v8_str("o"), templ->NewInstance());
4106 v8::Handle<Value> value = CompileRun(
4107 "for (var i = 0; i < 1000; i++) {"
4108 " o.x = 42;"
4109 "}");
4110}
4111
4112
4113
4114v8::Handle<Value> call_ic_function;
4115v8::Handle<Value> call_ic_function2;
4116v8::Handle<Value> call_ic_function3;
4117
4118static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
4119 const AccessorInfo& info) {
4120 ApiTestFuzzer::Fuzz();
4121 CHECK(v8_str("x")->Equals(name));
4122 return call_ic_function;
4123}
4124
4125
4126// This test should hit the call IC for the interceptor case.
4127THREADED_TEST(InterceptorCallIC) {
4128 v8::HandleScope scope;
4129 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4130 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
4131 LocalContext context;
4132 context->Global()->Set(v8_str("o"), templ->NewInstance());
4133 call_ic_function =
4134 v8_compile("function f(x) { return x + 1; }; f")->Run();
4135 v8::Handle<Value> value = CompileRun(
4136 "var result = 0;"
4137 "for (var i = 0; i < 1000; i++) {"
4138 " result = o.x(41);"
4139 "}");
4140 CHECK_EQ(42, value->Int32Value());
4141}
4142
4143static int interceptor_call_count = 0;
4144
4145static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
4146 const AccessorInfo& info) {
4147 ApiTestFuzzer::Fuzz();
4148 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
4149 return call_ic_function2;
4150 }
4151 return v8::Handle<Value>();
4152}
4153
4154
4155// This test should hit load and call ICs for the interceptor case.
4156// Once in a while, the interceptor will reply that a property was not
4157// found in which case we should get a reference error.
4158THREADED_TEST(InterceptorICReferenceErrors) {
4159 v8::HandleScope scope;
4160 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4161 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
4162 LocalContext context(0, templ, v8::Handle<Value>());
4163 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
4164 v8::Handle<Value> value = CompileRun(
4165 "function f() {"
4166 " for (var i = 0; i < 1000; i++) {"
4167 " try { x; } catch(e) { return true; }"
4168 " }"
4169 " return false;"
4170 "};"
4171 "f();");
4172 CHECK_EQ(true, value->BooleanValue());
4173 interceptor_call_count = 0;
4174 value = CompileRun(
4175 "function g() {"
4176 " for (var i = 0; i < 1000; i++) {"
4177 " try { x(42); } catch(e) { return true; }"
4178 " }"
4179 " return false;"
4180 "};"
4181 "g();");
4182 CHECK_EQ(true, value->BooleanValue());
4183}
4184
4185
4186static int interceptor_ic_exception_get_count = 0;
4187
4188static v8::Handle<Value> InterceptorICExceptionGetter(
4189 Local<String> name,
4190 const AccessorInfo& info) {
4191 ApiTestFuzzer::Fuzz();
4192 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
4193 return call_ic_function3;
4194 }
4195 if (interceptor_ic_exception_get_count == 20) {
4196 return v8::ThrowException(v8_num(42));
4197 }
4198 // Do not handle get for properties other than x.
4199 return v8::Handle<Value>();
4200}
4201
4202// Test interceptor load/call IC where the interceptor throws an
4203// exception once in a while.
4204THREADED_TEST(InterceptorICGetterExceptions) {
4205 interceptor_ic_exception_get_count = 0;
4206 v8::HandleScope scope;
4207 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4208 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
4209 LocalContext context(0, templ, v8::Handle<Value>());
4210 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
4211 v8::Handle<Value> value = CompileRun(
4212 "function f() {"
4213 " for (var i = 0; i < 100; i++) {"
4214 " try { x; } catch(e) { return true; }"
4215 " }"
4216 " return false;"
4217 "};"
4218 "f();");
4219 CHECK_EQ(true, value->BooleanValue());
4220 interceptor_ic_exception_get_count = 0;
4221 value = CompileRun(
4222 "function f() {"
4223 " for (var i = 0; i < 100; i++) {"
4224 " try { x(42); } catch(e) { return true; }"
4225 " }"
4226 " return false;"
4227 "};"
4228 "f();");
4229 CHECK_EQ(true, value->BooleanValue());
4230}
4231
4232
4233static int interceptor_ic_exception_set_count = 0;
4234
4235static v8::Handle<Value> InterceptorICExceptionSetter(
4236 Local<String> key,
4237 Local<Value> value,
4238 const AccessorInfo&) {
4239 ApiTestFuzzer::Fuzz();
4240 if (++interceptor_ic_exception_set_count > 20) {
4241 return v8::ThrowException(v8_num(42));
4242 }
4243 // Do not actually handle setting.
4244 return v8::Handle<Value>();
4245}
4246
4247// Test interceptor store IC where the interceptor throws an exception
4248// once in a while.
4249THREADED_TEST(InterceptorICSetterExceptions) {
4250 interceptor_ic_exception_set_count = 0;
4251 v8::HandleScope scope;
4252 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4253 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
4254 LocalContext context(0, templ, v8::Handle<Value>());
4255 v8::Handle<Value> value = CompileRun(
4256 "function f() {"
4257 " for (var i = 0; i < 100; i++) {"
4258 " try { x = 42; } catch(e) { return true; }"
4259 " }"
4260 " return false;"
4261 "};"
4262 "f();");
4263 CHECK_EQ(true, value->BooleanValue());
4264}
4265
4266
4267// Test that we ignore null interceptors.
4268THREADED_TEST(NullNamedInterceptor) {
4269 v8::HandleScope scope;
4270 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4271 templ->SetNamedPropertyHandler(0);
4272 LocalContext context;
4273 templ->Set("x", v8_num(42));
4274 v8::Handle<v8::Object> obj = templ->NewInstance();
4275 context->Global()->Set(v8_str("obj"), obj);
4276 v8::Handle<Value> value = CompileRun("obj.x");
4277 CHECK(value->IsInt32());
4278 CHECK_EQ(42, value->Int32Value());
4279}
4280
4281
4282// Test that we ignore null interceptors.
4283THREADED_TEST(NullIndexedInterceptor) {
4284 v8::HandleScope scope;
4285 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4286 templ->SetIndexedPropertyHandler(0);
4287 LocalContext context;
4288 templ->Set("42", v8_num(42));
4289 v8::Handle<v8::Object> obj = templ->NewInstance();
4290 context->Global()->Set(v8_str("obj"), obj);
4291 v8::Handle<Value> value = CompileRun("obj[42]");
4292 CHECK(value->IsInt32());
4293 CHECK_EQ(42, value->Int32Value());
4294}
4295
4296
4297static v8::Handle<Value> ParentGetter(Local<String> name,
4298 const AccessorInfo& info) {
4299 ApiTestFuzzer::Fuzz();
4300 return v8_num(1);
4301}
4302
4303
4304static v8::Handle<Value> ChildGetter(Local<String> name,
4305 const AccessorInfo& info) {
4306 ApiTestFuzzer::Fuzz();
4307 return v8_num(42);
4308}
4309
4310
4311THREADED_TEST(Overriding) {
4312 v8::HandleScope scope;
4313 LocalContext context;
4314
4315 // Parent template.
4316 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
4317 Local<ObjectTemplate> parent_instance_templ =
4318 parent_templ->InstanceTemplate();
4319 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
4320
4321 // Template that inherits from the parent template.
4322 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
4323 Local<ObjectTemplate> child_instance_templ =
4324 child_templ->InstanceTemplate();
4325 child_templ->Inherit(parent_templ);
4326 // Override 'f'. The child version of 'f' should get called for child
4327 // instances.
4328 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
4329 // Add 'g' twice. The 'g' added last should get called for instances.
4330 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
4331 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
4332
4333 // Add 'h' as an accessor to the proto template with ReadOnly attributes
4334 // so 'h' can be shadowed on the instance object.
4335 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
4336 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
4337 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
4338
4339 // Add 'i' as an accessor to the instance template with ReadOnly attributes
4340 // but the attribute does not have effect because it is duplicated with
4341 // NULL setter.
4342 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
4343 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
4344
4345
4346
4347 // Instantiate the child template.
4348 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
4349
4350 // Check that the child function overrides the parent one.
4351 context->Global()->Set(v8_str("o"), instance);
4352 Local<Value> value = v8_compile("o.f")->Run();
4353 // Check that the 'g' that was added last is hit.
4354 CHECK_EQ(42, value->Int32Value());
4355 value = v8_compile("o.g")->Run();
4356 CHECK_EQ(42, value->Int32Value());
4357
4358 // Check 'h' can be shadowed.
4359 value = v8_compile("o.h = 3; o.h")->Run();
4360 CHECK_EQ(3, value->Int32Value());
4361
4362 // Check 'i' is cannot be shadowed or changed.
4363 value = v8_compile("o.i = 3; o.i")->Run();
4364 CHECK_EQ(42, value->Int32Value());
4365}
4366
4367
4368static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
4369 ApiTestFuzzer::Fuzz();
4370 if (args.IsConstructCall()) {
4371 return v8::Boolean::New(true);
4372 }
4373 return v8::Boolean::New(false);
4374}
4375
4376
4377THREADED_TEST(IsConstructCall) {
4378 v8::HandleScope scope;
4379
4380 // Function template with call handler.
4381 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4382 templ->SetCallHandler(IsConstructHandler);
4383
4384 LocalContext context;
4385
4386 context->Global()->Set(v8_str("f"), templ->GetFunction());
4387 Local<Value> value = v8_compile("f()")->Run();
4388 CHECK(!value->BooleanValue());
4389 value = v8_compile("new f()")->Run();
4390 CHECK(value->BooleanValue());
4391}
4392
4393
4394THREADED_TEST(ObjectProtoToString) {
4395 v8::HandleScope scope;
4396 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4397 templ->SetClassName(v8_str("MyClass"));
4398
4399 LocalContext context;
4400
4401 Local<String> customized_tostring = v8_str("customized toString");
4402
4403 // Replace Object.prototype.toString
4404 v8_compile("Object.prototype.toString = function() {"
4405 " return 'customized toString';"
4406 "}")->Run();
4407
4408 // Normal ToString call should call replaced Object.prototype.toString
4409 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
4410 Local<String> value = instance->ToString();
4411 CHECK(value->IsString() && value->Equals(customized_tostring));
4412
4413 // ObjectProtoToString should not call replace toString function.
4414 value = instance->ObjectProtoToString();
4415 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
4416
4417 // Check global
4418 value = context->Global()->ObjectProtoToString();
4419 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
4420
4421 // Check ordinary object
4422 Local<Value> object = v8_compile("new Object()")->Run();
4423 value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
4424 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
4425}
4426
4427
4428bool ApiTestFuzzer::fuzzing_ = false;
4429v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
4430 v8::internal::OS::CreateSemaphore(0);
4431int ApiTestFuzzer::active_tests_;
4432int ApiTestFuzzer::tests_being_run_;
4433int ApiTestFuzzer::current_;
4434
4435
4436// We are in a callback and want to switch to another thread (if we
4437// are currently running the thread fuzzing test).
4438void ApiTestFuzzer::Fuzz() {
4439 if (!fuzzing_) return;
4440 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
4441 test->ContextSwitch();
4442}
4443
4444
4445// Let the next thread go. Since it is also waiting on the V8 lock it may
4446// not start immediately.
4447bool ApiTestFuzzer::NextThread() {
4448 int test_position = GetNextTestNumber();
4449 int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
4450 if (test_position == current_) {
4451 printf("Stay with %d\n", test_number);
4452 return false;
4453 }
4454 printf("Switch from %d to %d\n",
4455 current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
4456 current_ = test_position;
4457 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
4458 return true;
4459}
4460
4461
4462void ApiTestFuzzer::Run() {
4463 // When it is our turn...
4464 gate_->Wait();
4465 {
4466 // ... get the V8 lock and start running the test.
4467 v8::Locker locker;
4468 CallTest();
4469 }
4470 // This test finished.
4471 active_ = false;
4472 active_tests_--;
4473 // If it was the last then signal that fact.
4474 if (active_tests_ == 0) {
4475 all_tests_done_->Signal();
4476 } else {
4477 // Otherwise select a new test and start that.
4478 NextThread();
4479 }
4480}
4481
4482
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004483static unsigned linear_congruential_generator;
4484
4485
4486void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004487 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004488 fuzzing_ = true;
4489 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
4490 int end = (part == FIRST_PART)
4491 ? (RegisterThreadedTest::count() >> 1)
4492 : RegisterThreadedTest::count();
4493 active_tests_ = tests_being_run_ = end - start;
4494 for (int i = 0; i < tests_being_run_; i++) {
4495 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
4496 }
4497 for (int i = 0; i < active_tests_; i++) {
4498 RegisterThreadedTest::nth(i)->fuzzer_->Start();
4499 }
4500}
4501
4502
4503static void CallTestNumber(int test_number) {
4504 (RegisterThreadedTest::nth(test_number)->callback())();
4505}
4506
4507
4508void ApiTestFuzzer::RunAllTests() {
4509 // Set off the first test.
4510 current_ = -1;
4511 NextThread();
4512 // Wait till they are all done.
4513 all_tests_done_->Wait();
4514}
4515
4516
4517int ApiTestFuzzer::GetNextTestNumber() {
4518 int next_test;
4519 do {
4520 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
4521 linear_congruential_generator *= 1664525u;
4522 linear_congruential_generator += 1013904223u;
4523 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
4524 return next_test;
4525}
4526
4527
4528void ApiTestFuzzer::ContextSwitch() {
4529 // If the new thread is the same as the current thread there is nothing to do.
4530 if (NextThread()) {
4531 // Now it can start.
4532 v8::Unlocker unlocker;
4533 // Wait till someone starts us again.
4534 gate_->Wait();
4535 // And we're off.
4536 }
4537}
4538
4539
4540void ApiTestFuzzer::TearDown() {
4541 fuzzing_ = false;
4542}
4543
4544
4545// Lets not be needlessly self-referential.
4546TEST(Threading) {
4547 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
4548 ApiTestFuzzer::RunAllTests();
4549 ApiTestFuzzer::TearDown();
4550}
4551
4552TEST(Threading2) {
4553 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
4554 ApiTestFuzzer::RunAllTests();
4555 ApiTestFuzzer::TearDown();
4556}
4557
4558
4559void ApiTestFuzzer::CallTest() {
4560 printf("Start test %d\n", test_number_);
4561 CallTestNumber(test_number_);
4562 printf("End test %d\n", test_number_);
4563}
4564
4565
4566static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004567 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004568 ApiTestFuzzer::Fuzz();
4569 v8::Unlocker unlocker;
4570 const char* code = "throw 7;";
4571 {
4572 v8::Locker nested_locker;
4573 v8::HandleScope scope;
4574 v8::Handle<Value> exception;
4575 { v8::TryCatch try_catch;
4576 v8::Handle<Value> value = CompileRun(code);
4577 CHECK(value.IsEmpty());
4578 CHECK(try_catch.HasCaught());
4579 // Make sure to wrap the exception in a new handle because
4580 // the handle returned from the TryCatch is destroyed
4581 // when the TryCatch is destroyed.
4582 exception = Local<Value>::New(try_catch.Exception());
4583 }
4584 return v8::ThrowException(exception);
4585 }
4586}
4587
4588
4589static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004590 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004591 ApiTestFuzzer::Fuzz();
4592 v8::Unlocker unlocker;
4593 const char* code = "throw 7;";
4594 {
4595 v8::Locker nested_locker;
4596 v8::HandleScope scope;
4597 v8::Handle<Value> value = CompileRun(code);
4598 CHECK(value.IsEmpty());
4599 return v8_str("foo");
4600 }
4601}
4602
4603
4604// These are locking tests that don't need to be run again
4605// as part of the locking aggregation tests.
4606TEST(NestedLockers) {
4607 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004608 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004609 v8::HandleScope scope;
4610 LocalContext env;
4611 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
4612 Local<Function> fun = fun_templ->GetFunction();
4613 env->Global()->Set(v8_str("throw_in_js"), fun);
4614 Local<Script> script = v8_compile("(function () {"
4615 " try {"
4616 " throw_in_js();"
4617 " return 42;"
4618 " } catch (e) {"
4619 " return e * 13;"
4620 " }"
4621 "})();");
4622 CHECK_EQ(91, script->Run()->Int32Value());
4623}
4624
4625
4626// These are locking tests that don't need to be run again
4627// as part of the locking aggregation tests.
4628TEST(NestedLockersNoTryCatch) {
4629 v8::Locker locker;
4630 v8::HandleScope scope;
4631 LocalContext env;
4632 Local<v8::FunctionTemplate> fun_templ =
4633 v8::FunctionTemplate::New(ThrowInJSNoCatch);
4634 Local<Function> fun = fun_templ->GetFunction();
4635 env->Global()->Set(v8_str("throw_in_js"), fun);
4636 Local<Script> script = v8_compile("(function () {"
4637 " try {"
4638 " throw_in_js();"
4639 " return 42;"
4640 " } catch (e) {"
4641 " return e * 13;"
4642 " }"
4643 "})();");
4644 CHECK_EQ(91, script->Run()->Int32Value());
4645}
4646
4647
4648THREADED_TEST(RecursiveLocking) {
4649 v8::Locker locker;
4650 {
4651 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004652 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004653 }
4654}
4655
4656
4657static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
4658 ApiTestFuzzer::Fuzz();
4659 v8::Unlocker unlocker;
4660 return v8::Undefined();
4661}
4662
4663
4664THREADED_TEST(LockUnlockLock) {
4665 {
4666 v8::Locker locker;
4667 v8::HandleScope scope;
4668 LocalContext env;
4669 Local<v8::FunctionTemplate> fun_templ =
4670 v8::FunctionTemplate::New(UnlockForAMoment);
4671 Local<Function> fun = fun_templ->GetFunction();
4672 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
4673 Local<Script> script = v8_compile("(function () {"
4674 " unlock_for_a_moment();"
4675 " return 42;"
4676 "})();");
4677 CHECK_EQ(42, script->Run()->Int32Value());
4678 }
4679 {
4680 v8::Locker locker;
4681 v8::HandleScope scope;
4682 LocalContext env;
4683 Local<v8::FunctionTemplate> fun_templ =
4684 v8::FunctionTemplate::New(UnlockForAMoment);
4685 Local<Function> fun = fun_templ->GetFunction();
4686 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
4687 Local<Script> script = v8_compile("(function () {"
4688 " unlock_for_a_moment();"
4689 " return 42;"
4690 "})();");
4691 CHECK_EQ(42, script->Run()->Int32Value());
4692 }
4693}
4694
4695
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004696static int GetSurvivingGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004697 int count = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004698 v8::internal::Heap::CollectAllGarbage();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004699 v8::internal::HeapIterator it;
4700 while (it.has_next()) {
4701 v8::internal::HeapObject* object = it.next();
4702 if (object->IsJSGlobalObject()) {
4703 count++;
4704 }
4705 }
4706#ifdef DEBUG
4707 if (count > 0) v8::internal::Heap::TracePathToGlobal();
4708#endif
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004709 return count;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004710}
4711
4712
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004713TEST(DontLeakGlobalObjects) {
4714 // Regression test for issues 1139850 and 1174891.
4715
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004716 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004717
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004718 int count = GetSurvivingGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004719
4720 for (int i = 0; i < 5; i++) {
4721 { v8::HandleScope scope;
4722 LocalContext context;
4723 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004724 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004725
4726 { v8::HandleScope scope;
4727 LocalContext context;
4728 v8_compile("Date")->Run();
4729 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004730 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004731
4732 { v8::HandleScope scope;
4733 LocalContext context;
4734 v8_compile("/aaa/")->Run();
4735 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004736 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004737
4738 { v8::HandleScope scope;
4739 const char* extension_list[] = { "v8/gc" };
4740 v8::ExtensionConfiguration extensions(1, extension_list);
4741 LocalContext context(&extensions);
4742 v8_compile("gc();")->Run();
4743 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004744 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004745
4746 { v8::HandleScope scope;
4747 const char* extension_list[] = { "v8/print" };
4748 v8::ExtensionConfiguration extensions(1, extension_list);
4749 LocalContext context(&extensions);
4750 v8_compile("print('hest');")->Run();
4751 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004752 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004753 }
4754}
4755
4756
4757THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004758 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004759
4760 const int nof = 2;
4761 const char* sources[nof] = {
4762 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
4763 "Object()"
4764 };
4765
4766 for (int i = 0; i < nof; i++) {
4767 const char* source = sources[i];
4768 { v8::HandleScope scope;
4769 LocalContext context;
4770 CompileRun(source);
4771 }
4772 { v8::HandleScope scope;
4773 LocalContext context;
4774 CompileRun(source);
4775 }
4776 }
4777}
4778
4779
4780static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
4781 v8::HandleScope inner;
4782 env->Enter();
4783 v8::Handle<Value> three = v8_num(3);
4784 v8::Handle<Value> value = inner.Close(three);
4785 env->Exit();
4786 return value;
4787}
4788
4789
4790THREADED_TEST(NestedHandleScopeAndContexts) {
4791 v8::HandleScope outer;
4792 v8::Persistent<Context> env = Context::New();
4793 env->Enter();
4794 v8::Handle<Value> value = NestedScope(env);
4795 v8::Handle<String> str = value->ToString();
4796 env->Exit();
4797 env.Dispose();
4798}
4799
4800
4801THREADED_TEST(ExternalAllocatedMemory) {
4802 v8::HandleScope outer;
4803 const int kSize = 1024*1024;
4804 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
4805 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
4806}
4807
4808
4809THREADED_TEST(DisposeEnteredContext) {
4810 v8::HandleScope scope;
4811 LocalContext outer;
4812 { v8::Persistent<v8::Context> inner = v8::Context::New();
4813 inner->Enter();
4814 inner.Dispose();
4815 inner.Clear();
4816 inner->Exit();
4817 }
4818}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004819
4820
4821// Regression test for issue 54, object templates with internal fields
4822// but no accessors or interceptors did not get their internal field
4823// count set on instances.
4824THREADED_TEST(Regress54) {
4825 v8::HandleScope outer;
4826 LocalContext context;
4827 static v8::Persistent<v8::ObjectTemplate> templ;
4828 if (templ.IsEmpty()) {
4829 v8::HandleScope inner;
4830 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
4831 local->SetInternalFieldCount(1);
4832 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
4833 }
4834 v8::Handle<v8::Object> result = templ->NewInstance();
4835 CHECK_EQ(1, result->InternalFieldCount());
4836}
4837
4838
4839// If part of the threaded tests, this test makes ThreadingTest fail
4840// on mac.
4841TEST(CatchStackOverflow) {
4842 v8::HandleScope scope;
4843 LocalContext context;
4844 v8::TryCatch try_catch;
4845 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
4846 "function f() {"
4847 " return f();"
4848 "}"
4849 ""
4850 "f();"));
4851 v8::Handle<v8::Value> result = script->Run();
4852 CHECK(result.IsEmpty());
4853}
4854
4855
4856THREADED_TEST(TryCatchSourceInfo) {
4857 v8::HandleScope scope;
4858 LocalContext context;
4859 v8::Handle<v8::String> source = v8::String::New(
4860 "function Foo() {\n"
4861 " return Bar();\n"
4862 "}\n"
4863 "\n"
4864 "function Bar() {\n"
4865 " return Baz();\n"
4866 "}\n"
4867 "\n"
4868 "function Baz() {\n"
4869 " throw 'nirk';\n"
4870 "}\n"
4871 "\n"
4872 "Foo();\n");
4873 v8::Handle<v8::Script> script =
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004874 v8::Script::Compile(source, v8::String::New("test.js"));
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004875 v8::TryCatch try_catch;
4876 v8::Handle<v8::Value> result = script->Run();
4877 CHECK(result.IsEmpty());
4878 CHECK(try_catch.HasCaught());
4879 v8::Handle<v8::Message> message = try_catch.Message();
4880 CHECK(!message.IsEmpty());
4881 CHECK_EQ(10, message->GetLineNumber());
4882 CHECK_EQ(91, message->GetStartPosition());
4883 CHECK_EQ(92, message->GetEndPosition());
4884 CHECK_EQ(2, message->GetStartColumn());
4885 CHECK_EQ(3, message->GetEndColumn());
4886 v8::String::AsciiValue line(message->GetSourceLine());
4887 CHECK_EQ(" throw 'nirk';", *line);
4888 v8::String::AsciiValue name(message->GetScriptResourceName());
4889 CHECK_EQ("test.js", *name);
4890}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004891
4892
4893THREADED_TEST(CompilationCache) {
4894 v8::HandleScope scope;
4895 LocalContext context;
4896 v8::Handle<v8::String> source0 = v8::String::New("1234");
4897 v8::Handle<v8::String> source1 = v8::String::New("1234");
4898 v8::Handle<v8::Script> script0 =
4899 v8::Script::Compile(source0, v8::String::New("test.js"));
4900 v8::Handle<v8::Script> script1 =
4901 v8::Script::Compile(source1, v8::String::New("test.js"));
4902 v8::Handle<v8::Script> script2 =
4903 v8::Script::Compile(source0); // different origin
4904 CHECK_EQ(1234, script0->Run()->Int32Value());
4905 CHECK_EQ(1234, script1->Run()->Int32Value());
4906 CHECK_EQ(1234, script2->Run()->Int32Value());
4907}