blob: d192ebb27d6fbcd2bb6c3fdcf716a3a937b55588 [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
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000028#include <stdlib.h>
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include "v8.h"
31
32#include "api.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000033#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000034#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 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 ~ApiTestFuzzer() { delete gate_; }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000119
120 // The ApiTestFuzzer is also a Thread, so it has a Run method.
121 virtual void Run();
122
123 enum PartOfTest { FIRST_PART, SECOND_PART };
124
125 static void Setup(PartOfTest part);
126 static void RunAllTests();
127 static void TearDown();
128 // This method switches threads if we are running the Threading test.
129 // Otherwise it does nothing.
130 static void Fuzz();
131 private:
132 static bool fuzzing_;
133 static int tests_being_run_;
134 static int current_;
135 static int active_tests_;
136 static bool NextThread();
137 int test_number_;
138 v8::internal::Semaphore* gate_;
139 bool active_;
140 void ContextSwitch();
141 static int GetNextTestNumber();
142 static v8::internal::Semaphore* all_tests_done_;
143};
144
145
146#define THREADED_TEST(Name) \
147 static void Test##Name(); \
148 RegisterThreadedTest register_##Name(Test##Name); \
149 /* */ TEST(Name)
150
151
152class RegisterThreadedTest {
153 public:
154 explicit RegisterThreadedTest(CcTest::TestFunction* callback)
ager@chromium.org41826e72009-03-30 13:30:57 +0000155 : fuzzer_(NULL), callback_(callback) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000156 prev_ = first_;
157 first_ = this;
158 count_++;
159 }
160 static int count() { return count_; }
161 static RegisterThreadedTest* nth(int i) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000162 CHECK(i < count());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000163 RegisterThreadedTest* current = first_;
164 while (i > 0) {
165 i--;
166 current = current->prev_;
167 }
168 return current;
169 }
170 CcTest::TestFunction* callback() { return callback_; }
171 ApiTestFuzzer* fuzzer_;
172
173 private:
174 static RegisterThreadedTest* first_;
175 static int count_;
176 CcTest::TestFunction* callback_;
177 RegisterThreadedTest* prev_;
178};
179
180
181RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
182int RegisterThreadedTest::count_ = 0;
183
184
185static int signature_callback_count;
186static v8::Handle<Value> IncrementingSignatureCallback(
187 const v8::Arguments& args) {
188 ApiTestFuzzer::Fuzz();
189 signature_callback_count++;
190 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
191 for (int i = 0; i < args.Length(); i++)
192 result->Set(v8::Integer::New(i), args[i]);
193 return result;
194}
195
196
197static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
198 ApiTestFuzzer::Fuzz();
199 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
200 for (int i = 0; i < args.Length(); i++) {
201 result->Set(v8::Integer::New(i), args[i]);
202 }
203 return result;
204}
205
206
207THREADED_TEST(Handles) {
208 v8::HandleScope scope;
209 Local<Context> local_env;
210 {
211 LocalContext env;
212 local_env = env.local();
213 }
214
215 // Local context should still be live.
216 CHECK(!local_env.IsEmpty());
217 local_env->Enter();
218
219 v8::Handle<v8::Primitive> undef = v8::Undefined();
220 CHECK(!undef.IsEmpty());
221 CHECK(undef->IsUndefined());
222
223 const char* c_source = "1 + 2 + 3";
224 Local<String> source = String::New(c_source);
225 Local<Script> script = Script::Compile(source);
226 CHECK_EQ(6, script->Run()->Int32Value());
227
228 local_env->Exit();
229}
230
231
232// Helper function that compiles and runs the source.
233static Local<Value> CompileRun(const char* source) {
234 return Script::Compile(String::New(source))->Run();
235}
236
237THREADED_TEST(ReceiverSignature) {
238 v8::HandleScope scope;
239 LocalContext env;
240 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
241 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
242 fun->PrototypeTemplate()->Set(
243 v8_str("m"),
244 v8::FunctionTemplate::New(IncrementingSignatureCallback,
245 v8::Handle<Value>(),
246 sig));
247 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
248 signature_callback_count = 0;
249 CompileRun(
250 "var o = new Fun();"
251 "o.m();");
252 CHECK_EQ(1, signature_callback_count);
253 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
254 sub_fun->Inherit(fun);
255 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
256 CompileRun(
257 "var o = new SubFun();"
258 "o.m();");
259 CHECK_EQ(2, signature_callback_count);
260
261 v8::TryCatch try_catch;
262 CompileRun(
263 "var o = { };"
264 "o.m = Fun.prototype.m;"
265 "o.m();");
266 CHECK_EQ(2, signature_callback_count);
267 CHECK(try_catch.HasCaught());
268 try_catch.Reset();
269 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
270 sub_fun->Inherit(fun);
271 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
272 CompileRun(
273 "var o = new UnrelFun();"
274 "o.m = Fun.prototype.m;"
275 "o.m();");
276 CHECK_EQ(2, signature_callback_count);
277 CHECK(try_catch.HasCaught());
278}
279
280
281
282
283THREADED_TEST(ArgumentSignature) {
284 v8::HandleScope scope;
285 LocalContext env;
286 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
287 cons->SetClassName(v8_str("Cons"));
288 v8::Handle<v8::Signature> sig =
289 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
290 v8::Handle<v8::FunctionTemplate> fun =
291 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
292 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
293 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
294
295 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000296 CHECK(value1->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000297
298 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000299 CHECK(value2->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000300
301 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000302 CHECK(value3->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000303
304 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
305 cons1->SetClassName(v8_str("Cons1"));
306 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
307 cons2->SetClassName(v8_str("Cons2"));
308 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
309 cons3->SetClassName(v8_str("Cons3"));
310
311 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
312 v8::Handle<v8::Signature> wsig =
313 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
314 v8::Handle<v8::FunctionTemplate> fun2 =
315 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
316
317 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
318 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
319 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
320 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
321 v8::Handle<Value> value4 = CompileRun(
322 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
323 "'[object Cons1],[object Cons2],[object Cons3]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000324 CHECK(value4->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325
326 v8::Handle<Value> value5 = CompileRun(
327 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000328 CHECK(value5->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329
330 v8::Handle<Value> value6 = CompileRun(
331 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000332 CHECK(value6->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000333
334 v8::Handle<Value> value7 = CompileRun(
335 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
336 "'[object Cons1],[object Cons2],[object Cons3],d';");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000337 CHECK(value7->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338
339 v8::Handle<Value> value8 = CompileRun(
340 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000341 CHECK(value8->IsTrue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000342}
343
344
345THREADED_TEST(HulIgennem) {
346 v8::HandleScope scope;
347 LocalContext env;
348 v8::Handle<v8::Primitive> undef = v8::Undefined();
349 Local<String> undef_str = undef->ToString();
350 char* value = i::NewArray<char>(undef_str->Length() + 1);
351 undef_str->WriteAscii(value);
352 CHECK_EQ(0, strcmp(value, "undefined"));
353 i::DeleteArray(value);
354}
355
356
357THREADED_TEST(Access) {
358 v8::HandleScope scope;
359 LocalContext env;
360 Local<v8::Object> obj = v8::Object::New();
361 Local<Value> foo_before = obj->Get(v8_str("foo"));
362 CHECK(foo_before->IsUndefined());
363 Local<String> bar_str = v8_str("bar");
364 obj->Set(v8_str("foo"), bar_str);
365 Local<Value> foo_after = obj->Get(v8_str("foo"));
366 CHECK(!foo_after->IsUndefined());
367 CHECK(foo_after->IsString());
368 CHECK_EQ(bar_str, foo_after);
369}
370
371
372THREADED_TEST(Script) {
373 v8::HandleScope scope;
374 LocalContext env;
375 const char* c_source = "1 + 2 + 3";
376 Local<String> source = String::New(c_source);
377 Local<Script> script = Script::Compile(source);
378 CHECK_EQ(6, script->Run()->Int32Value());
379}
380
381
382static uint16_t* AsciiToTwoByteString(const char* source) {
383 size_t array_length = strlen(source) + 1;
384 uint16_t* converted = i::NewArray<uint16_t>(array_length);
385 for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
386 return converted;
387}
388
389
390class TestResource: public String::ExternalStringResource {
391 public:
392 static int dispose_count;
393
394 explicit TestResource(uint16_t* data)
395 : data_(data), length_(0) {
396 while (data[length_]) ++length_;
397 }
398
399 ~TestResource() {
400 i::DeleteArray(data_);
401 ++dispose_count;
402 }
403
404 const uint16_t* data() const {
405 return data_;
406 }
407
408 size_t length() const {
409 return length_;
410 }
411 private:
412 uint16_t* data_;
413 size_t length_;
414};
415
416
417int TestResource::dispose_count = 0;
418
419
420class TestAsciiResource: public String::ExternalAsciiStringResource {
421 public:
422 static int dispose_count;
423
ager@chromium.org5ec48922009-05-05 07:25:34 +0000424 explicit TestAsciiResource(const char* data)
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425 : data_(data),
426 length_(strlen(data)) { }
427
428 ~TestAsciiResource() {
429 i::DeleteArray(data_);
430 ++dispose_count;
431 }
432
433 const char* data() const {
434 return data_;
435 }
436
437 size_t length() const {
438 return length_;
439 }
440 private:
ager@chromium.org5ec48922009-05-05 07:25:34 +0000441 const char* data_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000442 size_t length_;
443};
444
445
446int TestAsciiResource::dispose_count = 0;
447
448
449THREADED_TEST(ScriptUsingStringResource) {
450 TestResource::dispose_count = 0;
451 const char* c_source = "1 + 2 * 3";
452 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
453 {
454 v8::HandleScope scope;
455 LocalContext env;
456 TestResource* resource = new TestResource(two_byte_source);
457 Local<String> source = String::NewExternal(resource);
458 Local<Script> script = Script::Compile(source);
459 Local<Value> value = script->Run();
460 CHECK(value->IsNumber());
461 CHECK_EQ(7, value->Int32Value());
462 CHECK(source->IsExternal());
463 CHECK_EQ(resource,
464 static_cast<TestResource*>(source->GetExternalStringResource()));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000465 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000466 CHECK_EQ(0, TestResource::dispose_count);
467 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000468 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000469 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000470 CHECK_EQ(1, TestResource::dispose_count);
471}
472
473
474THREADED_TEST(ScriptUsingAsciiStringResource) {
475 TestAsciiResource::dispose_count = 0;
476 const char* c_source = "1 + 2 * 3";
477 {
478 v8::HandleScope scope;
479 LocalContext env;
480 Local<String> source =
481 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
482 Local<Script> script = Script::Compile(source);
483 Local<Value> value = script->Run();
484 CHECK(value->IsNumber());
485 CHECK_EQ(7, value->Int32Value());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000486 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000487 CHECK_EQ(0, TestAsciiResource::dispose_count);
488 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000489 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000490 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 CHECK_EQ(1, TestAsciiResource::dispose_count);
492}
493
494
ager@chromium.org6f10e412009-02-13 10:11:16 +0000495THREADED_TEST(ScriptMakingExternalString) {
496 TestResource::dispose_count = 0;
497 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
498 {
499 v8::HandleScope scope;
500 LocalContext env;
501 Local<String> source = String::New(two_byte_source);
502 bool success = source->MakeExternal(new TestResource(two_byte_source));
503 CHECK(success);
504 Local<Script> script = Script::Compile(source);
505 Local<Value> value = script->Run();
506 CHECK(value->IsNumber());
507 CHECK_EQ(7, value->Int32Value());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000508 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000509 CHECK_EQ(0, TestResource::dispose_count);
510 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000511 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000512 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000513 CHECK_EQ(1, TestResource::dispose_count);
514}
515
516
517THREADED_TEST(ScriptMakingExternalAsciiString) {
518 TestAsciiResource::dispose_count = 0;
519 const char* c_source = "1 + 2 * 3";
520 {
521 v8::HandleScope scope;
522 LocalContext env;
523 Local<String> source = v8_str(c_source);
524 bool success = source->MakeExternal(
525 new TestAsciiResource(i::StrDup(c_source)));
526 CHECK(success);
527 Local<Script> script = Script::Compile(source);
528 Local<Value> value = script->Run();
529 CHECK(value->IsNumber());
530 CHECK_EQ(7, value->Int32Value());
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000531 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000532 CHECK_EQ(0, TestAsciiResource::dispose_count);
533 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000534 v8::internal::CompilationCache::Clear();
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000535 v8::internal::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000536 CHECK_EQ(1, TestAsciiResource::dispose_count);
537}
538
539
540THREADED_TEST(UsingExternalString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000541 {
542 v8::HandleScope scope;
543 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
544 Local<String> string =
545 String::NewExternal(new TestResource(two_byte_string));
546 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
547 // Trigger GCs so that the newly allocated string moves to old gen.
548 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
549 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
550 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
551 CHECK(isymbol->IsSymbol());
552 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000553 i::Heap::CollectAllGarbage(false);
554 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000555}
556
557
558THREADED_TEST(UsingExternalAsciiString) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000559 {
560 v8::HandleScope scope;
561 const char* one_byte_string = "test string";
562 Local<String> string = String::NewExternal(
563 new TestAsciiResource(i::StrDup(one_byte_string)));
564 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
565 // Trigger GCs so that the newly allocated string moves to old gen.
566 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in survivor space now
567 i::Heap::CollectGarbage(0, i::NEW_SPACE); // in old gen now
568 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
569 CHECK(isymbol->IsSymbol());
570 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000571 i::Heap::CollectAllGarbage(false);
572 i::Heap::CollectAllGarbage(false);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000573}
574
575
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576THREADED_TEST(GlobalProperties) {
577 v8::HandleScope scope;
578 LocalContext env;
579 v8::Handle<v8::Object> global = env->Global();
580 global->Set(v8_str("pi"), v8_num(3.1415926));
581 Local<Value> pi = global->Get(v8_str("pi"));
582 CHECK_EQ(3.1415926, pi->NumberValue());
583}
584
585
586static v8::Handle<Value> handle_call(const v8::Arguments& args) {
587 ApiTestFuzzer::Fuzz();
588 return v8_num(102);
589}
590
591
592static v8::Handle<Value> construct_call(const v8::Arguments& args) {
593 ApiTestFuzzer::Fuzz();
594 args.This()->Set(v8_str("x"), v8_num(1));
595 args.This()->Set(v8_str("y"), v8_num(2));
596 return args.This();
597}
598
599THREADED_TEST(FunctionTemplate) {
600 v8::HandleScope scope;
601 LocalContext env;
602 {
603 Local<v8::FunctionTemplate> fun_templ =
604 v8::FunctionTemplate::New(handle_call);
605 Local<Function> fun = fun_templ->GetFunction();
606 env->Global()->Set(v8_str("obj"), fun);
607 Local<Script> script = v8_compile("obj()");
608 CHECK_EQ(102, script->Run()->Int32Value());
609 }
610 // Use SetCallHandler to initialize a function template, should work like the
611 // previous one.
612 {
613 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
614 fun_templ->SetCallHandler(handle_call);
615 Local<Function> fun = fun_templ->GetFunction();
616 env->Global()->Set(v8_str("obj"), fun);
617 Local<Script> script = v8_compile("obj()");
618 CHECK_EQ(102, script->Run()->Int32Value());
619 }
620 // Test constructor calls.
621 {
622 Local<v8::FunctionTemplate> fun_templ =
623 v8::FunctionTemplate::New(construct_call);
624 fun_templ->SetClassName(v8_str("funky"));
625 Local<Function> fun = fun_templ->GetFunction();
626 env->Global()->Set(v8_str("obj"), fun);
627 Local<Script> script = v8_compile("var s = new obj(); s.x");
628 CHECK_EQ(1, script->Run()->Int32Value());
629
630 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
631 CHECK_EQ(v8_str("[object funky]"), result);
632 }
633}
634
635
sgjesse@chromium.org900d3b72009-08-07 11:24:25 +0000636THREADED_TEST(FindInstanceInPrototypeChain) {
637 v8::HandleScope scope;
638 LocalContext env;
639
640 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
641 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
642 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
643 derived->Inherit(base);
644
645 Local<v8::Function> base_function = base->GetFunction();
646 Local<v8::Function> derived_function = derived->GetFunction();
647 Local<v8::Function> other_function = other->GetFunction();
648
649 Local<v8::Object> base_instance = base_function->NewInstance();
650 Local<v8::Object> derived_instance = derived_function->NewInstance();
651 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
652 Local<v8::Object> other_instance = other_function->NewInstance();
653 derived_instance2->Set(v8_str("__proto__"), derived_instance);
654 other_instance->Set(v8_str("__proto__"), derived_instance2);
655
656 // base_instance is only an instance of base.
657 CHECK_EQ(base_instance,
658 base_instance->FindInstanceInPrototypeChain(base));
659 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
660 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
661
662 // derived_instance is an instance of base and derived.
663 CHECK_EQ(derived_instance,
664 derived_instance->FindInstanceInPrototypeChain(base));
665 CHECK_EQ(derived_instance,
666 derived_instance->FindInstanceInPrototypeChain(derived));
667 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
668
669 // other_instance is an instance of other and its immediate
670 // prototype derived_instance2 is an instance of base and derived.
671 // Note, derived_instance is an instance of base and derived too,
672 // but it comes after derived_instance2 in the prototype chain of
673 // other_instance.
674 CHECK_EQ(derived_instance2,
675 other_instance->FindInstanceInPrototypeChain(base));
676 CHECK_EQ(derived_instance2,
677 other_instance->FindInstanceInPrototypeChain(derived));
678 CHECK_EQ(other_instance,
679 other_instance->FindInstanceInPrototypeChain(other));
680}
681
682
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000683static v8::Handle<Value> handle_property(Local<String> name,
684 const AccessorInfo&) {
685 ApiTestFuzzer::Fuzz();
686 return v8_num(900);
687}
688
689
690THREADED_TEST(PropertyHandler) {
691 v8::HandleScope scope;
692 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
693 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
694 LocalContext env;
695 Local<Function> fun = fun_templ->GetFunction();
696 env->Global()->Set(v8_str("Fun"), fun);
697 Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
698 CHECK_EQ(900, getter->Run()->Int32Value());
699 Local<Script> setter = v8_compile("obj.foo = 901;");
700 CHECK_EQ(901, setter->Run()->Int32Value());
701}
702
703
704THREADED_TEST(Number) {
705 v8::HandleScope scope;
706 LocalContext env;
707 double PI = 3.1415926;
708 Local<v8::Number> pi_obj = v8::Number::New(PI);
709 CHECK_EQ(PI, pi_obj->NumberValue());
710}
711
712
713THREADED_TEST(ToNumber) {
714 v8::HandleScope scope;
715 LocalContext env;
716 Local<String> str = v8_str("3.1415926");
717 CHECK_EQ(3.1415926, str->NumberValue());
718 v8::Handle<v8::Boolean> t = v8::True();
719 CHECK_EQ(1.0, t->NumberValue());
720 v8::Handle<v8::Boolean> f = v8::False();
721 CHECK_EQ(0.0, f->NumberValue());
722}
723
724
725THREADED_TEST(Date) {
726 v8::HandleScope scope;
727 LocalContext env;
728 double PI = 3.1415926;
729 Local<Value> date_obj = v8::Date::New(PI);
730 CHECK_EQ(3.0, date_obj->NumberValue());
731}
732
733
734THREADED_TEST(Boolean) {
735 v8::HandleScope scope;
736 LocalContext env;
737 v8::Handle<v8::Boolean> t = v8::True();
738 CHECK(t->Value());
739 v8::Handle<v8::Boolean> f = v8::False();
740 CHECK(!f->Value());
741 v8::Handle<v8::Primitive> u = v8::Undefined();
742 CHECK(!u->BooleanValue());
743 v8::Handle<v8::Primitive> n = v8::Null();
744 CHECK(!n->BooleanValue());
745 v8::Handle<String> str1 = v8_str("");
746 CHECK(!str1->BooleanValue());
747 v8::Handle<String> str2 = v8_str("x");
748 CHECK(str2->BooleanValue());
749 CHECK(!v8::Number::New(0)->BooleanValue());
750 CHECK(v8::Number::New(-1)->BooleanValue());
751 CHECK(v8::Number::New(1)->BooleanValue());
752 CHECK(v8::Number::New(42)->BooleanValue());
753 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
754}
755
756
757static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
758 ApiTestFuzzer::Fuzz();
759 return v8_num(13.4);
760}
761
762
763static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
764 ApiTestFuzzer::Fuzz();
765 return v8_num(876);
766}
767
768
769THREADED_TEST(GlobalPrototype) {
770 v8::HandleScope scope;
771 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
772 func_templ->PrototypeTemplate()->Set(
773 "dummy",
774 v8::FunctionTemplate::New(DummyCallHandler));
775 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
776 templ->Set("x", v8_num(200));
777 templ->SetAccessor(v8_str("m"), GetM);
778 LocalContext env(0, templ);
779 v8::Handle<v8::Object> obj = env->Global();
780 v8::Handle<Script> script = v8_compile("dummy()");
781 v8::Handle<Value> result = script->Run();
782 CHECK_EQ(13.4, result->NumberValue());
783 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
784 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
785}
786
787
788static v8::Handle<Value> GetIntValue(Local<String> property,
789 const AccessorInfo& info) {
790 ApiTestFuzzer::Fuzz();
791 int* value =
792 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
793 return v8_num(*value);
794}
795
796static void SetIntValue(Local<String> property,
797 Local<Value> value,
798 const AccessorInfo& info) {
799 int* field =
800 static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
801 *field = value->Int32Value();
802}
803
804int foo, bar, baz;
805
806THREADED_TEST(GlobalVariableAccess) {
807 foo = 0;
808 bar = -4;
809 baz = 10;
810 v8::HandleScope scope;
811 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
812 templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
813 GetIntValue,
814 SetIntValue,
815 v8::External::New(&foo));
816 templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
817 GetIntValue,
818 SetIntValue,
819 v8::External::New(&bar));
820 templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
821 GetIntValue,
822 SetIntValue,
823 v8::External::New(&baz));
824 LocalContext env(0, templ->InstanceTemplate());
825 v8_compile("foo = (++bar) + baz")->Run();
826 CHECK_EQ(bar, -3);
827 CHECK_EQ(foo, 7);
828}
829
830
831THREADED_TEST(ObjectTemplate) {
832 v8::HandleScope scope;
833 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
834 templ1->Set("x", v8_num(10));
835 templ1->Set("y", v8_num(13));
836 LocalContext env;
837 Local<v8::Object> instance1 = templ1->NewInstance();
838 env->Global()->Set(v8_str("p"), instance1);
839 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
840 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
841 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
842 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
843 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
844 templ2->Set("a", v8_num(12));
845 templ2->Set("b", templ1);
846 Local<v8::Object> instance2 = templ2->NewInstance();
847 env->Global()->Set(v8_str("q"), instance2);
848 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
849 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
850 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
851 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
852}
853
854
855static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
856 ApiTestFuzzer::Fuzz();
857 return v8_num(17.2);
858}
859
860
861static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
862 ApiTestFuzzer::Fuzz();
863 return v8_num(15.2);
864}
865
866
867THREADED_TEST(DescriptorInheritance) {
868 v8::HandleScope scope;
869 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
870 super->PrototypeTemplate()->Set("flabby",
871 v8::FunctionTemplate::New(GetFlabby));
872 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
873
874 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
875
876 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
877 base1->Inherit(super);
878 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
879
880 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
881 base2->Inherit(super);
882 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
883
884 LocalContext env;
885
886 env->Global()->Set(v8_str("s"), super->GetFunction());
887 env->Global()->Set(v8_str("base1"), base1->GetFunction());
888 env->Global()->Set(v8_str("base2"), base2->GetFunction());
889
890 // Checks right __proto__ chain.
891 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
892 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
893
894 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
895
896 // Instance accessor should not be visible on function object or its prototype
897 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
898 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
899 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
900
901 env->Global()->Set(v8_str("obj"),
902 base1->GetFunction()->NewInstance());
903 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
904 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
905 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
906 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
907 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
908
909 env->Global()->Set(v8_str("obj2"),
910 base2->GetFunction()->NewInstance());
911 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
912 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
913 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
914 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
915 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
916
917 // base1 and base2 cannot cross reference to each's prototype
918 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
919 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
920}
921
922
923int echo_named_call_count;
924
925
926static v8::Handle<Value> EchoNamedProperty(Local<String> name,
927 const AccessorInfo& info) {
928 ApiTestFuzzer::Fuzz();
929 CHECK_EQ(v8_str("data"), info.Data());
930 echo_named_call_count++;
931 return name;
932}
933
934
935THREADED_TEST(NamedPropertyHandlerGetter) {
936 echo_named_call_count = 0;
937 v8::HandleScope scope;
938 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
939 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
940 0, 0, 0, 0,
941 v8_str("data"));
942 LocalContext env;
943 env->Global()->Set(v8_str("obj"),
944 templ->GetFunction()->NewInstance());
945 CHECK_EQ(echo_named_call_count, 0);
946 v8_compile("obj.x")->Run();
947 CHECK_EQ(echo_named_call_count, 1);
948 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
949 v8::Handle<Value> str = CompileRun(code);
950 String::AsciiValue value(str);
951 CHECK_EQ(*value, "oddlepoddle");
952 // Check default behavior
953 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
954 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
955 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
956}
957
958
959int echo_indexed_call_count = 0;
960
961
962static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
963 const AccessorInfo& info) {
964 ApiTestFuzzer::Fuzz();
965 CHECK_EQ(v8_num(637), info.Data());
966 echo_indexed_call_count++;
967 return v8_num(index);
968}
969
970
971THREADED_TEST(IndexedPropertyHandlerGetter) {
972 v8::HandleScope scope;
973 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
974 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
975 0, 0, 0, 0,
976 v8_num(637));
977 LocalContext env;
978 env->Global()->Set(v8_str("obj"),
979 templ->GetFunction()->NewInstance());
980 Local<Script> script = v8_compile("obj[900]");
981 CHECK_EQ(script->Run()->Int32Value(), 900);
982}
983
984
985v8::Handle<v8::Object> bottom;
986
987static v8::Handle<Value> CheckThisIndexedPropertyHandler(
988 uint32_t index,
989 const AccessorInfo& info) {
990 ApiTestFuzzer::Fuzz();
991 CHECK(info.This()->Equals(bottom));
992 return v8::Handle<Value>();
993}
994
995static v8::Handle<Value> CheckThisNamedPropertyHandler(
996 Local<String> name,
997 const AccessorInfo& info) {
998 ApiTestFuzzer::Fuzz();
999 CHECK(info.This()->Equals(bottom));
1000 return v8::Handle<Value>();
1001}
1002
1003
1004v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1005 Local<Value> value,
1006 const AccessorInfo& info) {
1007 ApiTestFuzzer::Fuzz();
1008 CHECK(info.This()->Equals(bottom));
1009 return v8::Handle<Value>();
1010}
1011
1012
1013v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1014 Local<Value> value,
1015 const AccessorInfo& info) {
1016 ApiTestFuzzer::Fuzz();
1017 CHECK(info.This()->Equals(bottom));
1018 return v8::Handle<Value>();
1019}
1020
1021v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1022 uint32_t index,
1023 const AccessorInfo& info) {
1024 ApiTestFuzzer::Fuzz();
1025 CHECK(info.This()->Equals(bottom));
1026 return v8::Handle<v8::Boolean>();
1027}
1028
1029
1030v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1031 const AccessorInfo& info) {
1032 ApiTestFuzzer::Fuzz();
1033 CHECK(info.This()->Equals(bottom));
1034 return v8::Handle<v8::Boolean>();
1035}
1036
1037
1038v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1039 uint32_t index,
1040 const AccessorInfo& info) {
1041 ApiTestFuzzer::Fuzz();
1042 CHECK(info.This()->Equals(bottom));
1043 return v8::Handle<v8::Boolean>();
1044}
1045
1046
1047v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1048 Local<String> property,
1049 const AccessorInfo& info) {
1050 ApiTestFuzzer::Fuzz();
1051 CHECK(info.This()->Equals(bottom));
1052 return v8::Handle<v8::Boolean>();
1053}
1054
1055
1056v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1057 const AccessorInfo& info) {
1058 ApiTestFuzzer::Fuzz();
1059 CHECK(info.This()->Equals(bottom));
1060 return v8::Handle<v8::Array>();
1061}
1062
1063
1064v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1065 const AccessorInfo& info) {
1066 ApiTestFuzzer::Fuzz();
1067 CHECK(info.This()->Equals(bottom));
1068 return v8::Handle<v8::Array>();
1069}
1070
1071
1072THREADED_TEST(PropertyHandlerInPrototype) {
1073 v8::HandleScope scope;
1074 LocalContext env;
1075
1076 // Set up a prototype chain with three interceptors.
1077 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1078 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1079 CheckThisIndexedPropertyHandler,
1080 CheckThisIndexedPropertySetter,
1081 CheckThisIndexedPropertyQuery,
1082 CheckThisIndexedPropertyDeleter,
1083 CheckThisIndexedPropertyEnumerator);
1084
1085 templ->InstanceTemplate()->SetNamedPropertyHandler(
1086 CheckThisNamedPropertyHandler,
1087 CheckThisNamedPropertySetter,
1088 CheckThisNamedPropertyQuery,
1089 CheckThisNamedPropertyDeleter,
1090 CheckThisNamedPropertyEnumerator);
1091
1092 bottom = templ->GetFunction()->NewInstance();
1093 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1094 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1095
1096 bottom->Set(v8_str("__proto__"), middle);
1097 middle->Set(v8_str("__proto__"), top);
1098 env->Global()->Set(v8_str("obj"), bottom);
1099
1100 // Indexed and named get.
1101 Script::Compile(v8_str("obj[0]"))->Run();
1102 Script::Compile(v8_str("obj.x"))->Run();
1103
1104 // Indexed and named set.
1105 Script::Compile(v8_str("obj[1] = 42"))->Run();
1106 Script::Compile(v8_str("obj.y = 42"))->Run();
1107
1108 // Indexed and named query.
1109 Script::Compile(v8_str("0 in obj"))->Run();
1110 Script::Compile(v8_str("'x' in obj"))->Run();
1111
1112 // Indexed and named deleter.
1113 Script::Compile(v8_str("delete obj[0]"))->Run();
1114 Script::Compile(v8_str("delete obj.x"))->Run();
1115
1116 // Enumerators.
1117 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1118}
1119
1120
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001121static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1122 const AccessorInfo& info) {
1123 ApiTestFuzzer::Fuzz();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001124 if (v8_str("pre")->Equals(key)) {
1125 return v8_str("PrePropertyHandler: pre");
1126 }
1127 return v8::Handle<String>();
1128}
1129
1130
1131static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1132 const AccessorInfo&) {
1133 if (v8_str("pre")->Equals(key)) {
1134 return v8::True();
1135 }
1136
1137 return v8::Handle<v8::Boolean>(); // do not intercept the call
1138}
1139
1140
1141THREADED_TEST(PrePropertyHandler) {
1142 v8::HandleScope scope;
1143 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1144 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1145 0,
1146 PrePropertyHandlerHas);
1147 LocalContext env(NULL, desc->InstanceTemplate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001148 Script::Compile(v8_str(
1149 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1150 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1151 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1152 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1153 CHECK_EQ(v8_str("Object: on"), result_on);
1154 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1155 CHECK(result_post.IsEmpty());
1156}
1157
1158
ager@chromium.org870a0b62008-11-04 11:43:05 +00001159THREADED_TEST(UndefinedIsNotEnumerable) {
1160 v8::HandleScope scope;
1161 LocalContext env;
1162 v8::Handle<Value> result = Script::Compile(v8_str(
1163 "this.propertyIsEnumerable(undefined)"))->Run();
1164 CHECK(result->IsFalse());
1165}
1166
1167
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001168v8::Handle<Script> call_recursively_script;
1169static const int kTargetRecursionDepth = 300; // near maximum
1170
1171
1172static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1173 ApiTestFuzzer::Fuzz();
1174 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1175 if (depth == kTargetRecursionDepth) return v8::Undefined();
1176 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1177 return call_recursively_script->Run();
1178}
1179
1180
1181static v8::Handle<Value> CallFunctionRecursivelyCall(
1182 const v8::Arguments& args) {
1183 ApiTestFuzzer::Fuzz();
1184 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1185 if (depth == kTargetRecursionDepth) {
1186 printf("[depth = %d]\n", depth);
1187 return v8::Undefined();
1188 }
1189 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1190 v8::Handle<Value> function =
1191 args.This()->Get(v8_str("callFunctionRecursively"));
1192 return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1193}
1194
1195
1196THREADED_TEST(DeepCrossLanguageRecursion) {
1197 v8::HandleScope scope;
1198 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1199 global->Set(v8_str("callScriptRecursively"),
1200 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1201 global->Set(v8_str("callFunctionRecursively"),
1202 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1203 LocalContext env(NULL, global);
1204
1205 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1206 call_recursively_script = v8_compile("callScriptRecursively()");
1207 v8::Handle<Value> result = call_recursively_script->Run();
1208 call_recursively_script = v8::Handle<Script>();
1209
1210 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1211 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1212}
1213
1214
1215static v8::Handle<Value>
1216 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1217 ApiTestFuzzer::Fuzz();
1218 return v8::ThrowException(key);
1219}
1220
1221
1222static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1223 Local<Value>,
1224 const AccessorInfo&) {
1225 v8::ThrowException(key);
1226 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1227}
1228
1229
1230THREADED_TEST(CallbackExceptionRegression) {
1231 v8::HandleScope scope;
1232 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1233 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1234 ThrowingPropertyHandlerSet);
1235 LocalContext env;
1236 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1237 v8::Handle<Value> otto = Script::Compile(v8_str(
1238 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1239 CHECK_EQ(v8_str("otto"), otto);
1240 v8::Handle<Value> netto = Script::Compile(v8_str(
1241 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1242 CHECK_EQ(v8_str("netto"), netto);
1243}
1244
1245
1246static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
1247 const AccessorInfo& info) {
1248 ApiTestFuzzer::Fuzz();
1249 return v8::ThrowException(v8_str("g"));
1250}
1251
1252
1253static void ThrowingSetAccessor(Local<String> name,
1254 Local<Value> value,
1255 const AccessorInfo& info) {
1256 v8::ThrowException(value);
1257}
1258
1259
1260THREADED_TEST(Regress1054726) {
1261 v8::HandleScope scope;
1262 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1263 obj->SetAccessor(v8_str("x"),
1264 ThrowingGetAccessor,
1265 ThrowingSetAccessor,
1266 Local<Value>());
1267
1268 LocalContext env;
1269 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1270
1271 // Use the throwing property setter/getter in a loop to force
1272 // the accessor ICs to be initialized.
1273 v8::Handle<Value> result;
1274 result = Script::Compile(v8_str(
1275 "var result = '';"
1276 "for (var i = 0; i < 5; i++) {"
1277 " try { obj.x; } catch (e) { result += e; }"
1278 "}; result"))->Run();
1279 CHECK_EQ(v8_str("ggggg"), result);
1280
1281 result = Script::Compile(String::New(
1282 "var result = '';"
1283 "for (var i = 0; i < 5; i++) {"
1284 " try { obj.x = i; } catch (e) { result += e; }"
1285 "}; result"))->Run();
1286 CHECK_EQ(v8_str("01234"), result);
1287}
1288
1289
1290THREADED_TEST(FunctionPrototype) {
1291 v8::HandleScope scope;
1292 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1293 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1294 LocalContext env;
1295 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1296 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1297 CHECK_EQ(script->Run()->Int32Value(), 321);
1298}
1299
1300
1301THREADED_TEST(InternalFields) {
1302 v8::HandleScope scope;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001303 LocalContext env;
1304
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001305 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1306 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1307 instance_templ->SetInternalFieldCount(1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001308 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1309 CHECK_EQ(1, obj->InternalFieldCount());
1310 CHECK(obj->GetInternalField(0)->IsUndefined());
1311 obj->SetInternalField(0, v8_num(17));
1312 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1313}
1314
1315
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001316THREADED_TEST(InternalFieldsNativePointers) {
1317 v8::HandleScope scope;
1318 LocalContext env;
1319
1320 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1321 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1322 instance_templ->SetInternalFieldCount(1);
1323 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1324 CHECK_EQ(1, obj->InternalFieldCount());
1325 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1326
1327 char* data = new char[100];
1328
1329 void* aligned = data;
1330 CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1331 void* unaligned = data + 1;
1332 CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1333
1334 // Check reading and writing aligned pointers.
1335 obj->SetPointerInInternalField(0, aligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001336 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001337 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1338
1339 // Check reading and writing unaligned pointers.
1340 obj->SetPointerInInternalField(0, unaligned);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001341 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001342 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1343
1344 delete[] data;
1345}
1346
1347
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001348THREADED_TEST(IdentityHash) {
1349 v8::HandleScope scope;
1350 LocalContext env;
1351
1352 // Ensure that the test starts with an fresh heap to test whether the hash
1353 // code is based on the address.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001354 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001355 Local<v8::Object> obj = v8::Object::New();
1356 int hash = obj->GetIdentityHash();
1357 int hash1 = obj->GetIdentityHash();
1358 CHECK_EQ(hash, hash1);
1359 int hash2 = v8::Object::New()->GetIdentityHash();
1360 // Since the identity hash is essentially a random number two consecutive
1361 // objects should not be assigned the same hash code. If the test below fails
1362 // the random number generator should be evaluated.
1363 CHECK_NE(hash, hash2);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001364 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001365 int hash3 = v8::Object::New()->GetIdentityHash();
1366 // Make sure that the identity hash is not based on the initial address of
1367 // the object alone. If the test below fails the random number generator
1368 // should be evaluated.
1369 CHECK_NE(hash, hash3);
1370 int hash4 = obj->GetIdentityHash();
1371 CHECK_EQ(hash, hash4);
1372}
1373
1374
1375THREADED_TEST(HiddenProperties) {
1376 v8::HandleScope scope;
1377 LocalContext env;
1378
1379 v8::Local<v8::Object> obj = v8::Object::New();
1380 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1381 v8::Local<v8::String> empty = v8_str("");
1382 v8::Local<v8::String> prop_name = v8_str("prop_name");
1383
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001384 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001385
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001386 // Make sure delete of a non-existent hidden value works
1387 CHECK(obj->DeleteHiddenValue(key));
1388
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001389 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1390 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1391 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1392 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1393
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001394 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001395
1396 // Make sure we do not find the hidden property.
1397 CHECK(!obj->Has(empty));
1398 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1399 CHECK(obj->Get(empty)->IsUndefined());
1400 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1401 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1402 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1403 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1404
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001405 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001406
1407 // Add another property and delete it afterwards to force the object in
1408 // slow case.
1409 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1410 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1411 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1412 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1413 CHECK(obj->Delete(prop_name));
1414 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1415
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001416 i::Heap::CollectAllGarbage(false);
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001417
1418 CHECK(obj->DeleteHiddenValue(key));
1419 CHECK(obj->GetHiddenValue(key).IsEmpty());
1420}
1421
1422
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001423static v8::Handle<Value> InterceptorForHiddenProperties(
1424 Local<String> name, const AccessorInfo& info) {
1425 // Make sure objects move.
1426 bool saved_always_compact = i::FLAG_always_compact;
1427 if (!i::FLAG_never_compact) {
1428 i::FLAG_always_compact = true;
1429 }
1430 // The whole goal of this interceptor is to cause a GC during local property
1431 // lookup.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001432 i::Heap::CollectAllGarbage(false);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001433 i::FLAG_always_compact = saved_always_compact;
1434 return v8::Handle<Value>();
1435}
1436
1437
1438THREADED_TEST(HiddenPropertiesWithInterceptors) {
1439 v8::HandleScope scope;
1440 LocalContext context;
1441
1442 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1443
1444 // Associate an interceptor with an object and start setting hidden values.
1445 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1446 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1447 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1448 Local<v8::Function> function = fun_templ->GetFunction();
1449 Local<v8::Object> obj = function->NewInstance();
1450 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1451 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1452}
1453
1454
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001455THREADED_TEST(External) {
1456 v8::HandleScope scope;
1457 int x = 3;
1458 Local<v8::External> ext = v8::External::New(&x);
1459 LocalContext env;
1460 env->Global()->Set(v8_str("ext"), ext);
1461 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1462 v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1463 int* ptr = static_cast<int*>(reext->Value());
1464 CHECK_EQ(x, 3);
1465 *ptr = 10;
1466 CHECK_EQ(x, 10);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001467
1468 // Make sure unaligned pointers are wrapped properly.
1469 char* data = i::StrDup("0123456789");
1470 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1471 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1472 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1473 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1474
1475 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1476 CHECK_EQ('0', *char_ptr);
1477 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1478 CHECK_EQ('1', *char_ptr);
1479 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1480 CHECK_EQ('2', *char_ptr);
1481 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1482 CHECK_EQ('3', *char_ptr);
1483 i::DeleteArray(data);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001484}
1485
1486
1487THREADED_TEST(GlobalHandle) {
1488 v8::Persistent<String> global;
1489 {
1490 v8::HandleScope scope;
1491 Local<String> str = v8_str("str");
1492 global = v8::Persistent<String>::New(str);
1493 }
1494 CHECK_EQ(global->Length(), 3);
1495 global.Dispose();
1496}
1497
1498
1499THREADED_TEST(ScriptException) {
1500 v8::HandleScope scope;
1501 LocalContext env;
1502 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1503 v8::TryCatch try_catch;
1504 Local<Value> result = script->Run();
1505 CHECK(result.IsEmpty());
1506 CHECK(try_catch.HasCaught());
1507 String::AsciiValue exception_value(try_catch.Exception());
1508 CHECK_EQ(*exception_value, "panama!");
1509}
1510
1511
1512bool message_received;
1513
1514
1515static void check_message(v8::Handle<v8::Message> message,
1516 v8::Handle<Value> data) {
1517 CHECK_EQ(5.76, data->NumberValue());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001518 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001519 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001520 message_received = true;
1521}
1522
1523
1524THREADED_TEST(MessageHandlerData) {
1525 message_received = false;
1526 v8::HandleScope scope;
1527 CHECK(!message_received);
1528 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1529 LocalContext context;
1530 v8::ScriptOrigin origin =
1531 v8::ScriptOrigin(v8_str("6.75"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001532 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1533 &origin);
1534 script->SetData(v8_str("7.56"));
1535 script->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001536 CHECK(message_received);
1537 // clear out the message listener
1538 v8::V8::RemoveMessageListeners(check_message);
1539}
1540
1541
1542THREADED_TEST(GetSetProperty) {
1543 v8::HandleScope scope;
1544 LocalContext context;
1545 context->Global()->Set(v8_str("foo"), v8_num(14));
1546 context->Global()->Set(v8_str("12"), v8_num(92));
1547 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1548 context->Global()->Set(v8_num(13), v8_num(56));
1549 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1550 CHECK_EQ(14, foo->Int32Value());
1551 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1552 CHECK_EQ(92, twelve->Int32Value());
1553 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1554 CHECK_EQ(32, sixteen->Int32Value());
1555 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1556 CHECK_EQ(56, thirteen->Int32Value());
1557 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1558 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1559 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1560 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1561 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1562 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1563 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1564 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1565 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1566}
1567
1568
1569THREADED_TEST(PropertyAttributes) {
1570 v8::HandleScope scope;
1571 LocalContext context;
1572 // read-only
1573 Local<String> prop = v8_str("read_only");
1574 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1575 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1576 Script::Compile(v8_str("read_only = 9"))->Run();
1577 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1578 context->Global()->Set(prop, v8_num(10));
1579 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1580 // dont-delete
1581 prop = v8_str("dont_delete");
1582 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1583 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1584 Script::Compile(v8_str("delete dont_delete"))->Run();
1585 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1586}
1587
1588
1589THREADED_TEST(Array) {
1590 v8::HandleScope scope;
1591 LocalContext context;
1592 Local<v8::Array> array = v8::Array::New();
1593 CHECK_EQ(0, array->Length());
1594 CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1595 CHECK(!array->Has(0));
1596 CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1597 CHECK(!array->Has(100));
1598 array->Set(v8::Integer::New(2), v8_num(7));
1599 CHECK_EQ(3, array->Length());
1600 CHECK(!array->Has(0));
1601 CHECK(!array->Has(1));
1602 CHECK(array->Has(2));
1603 CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1604 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1605 Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1606 CHECK_EQ(3, arr->Length());
1607 CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1608 CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1609 CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1610}
1611
1612
1613v8::Handle<Value> HandleF(const v8::Arguments& args) {
1614 v8::HandleScope scope;
1615 ApiTestFuzzer::Fuzz();
1616 Local<v8::Array> result = v8::Array::New(args.Length());
1617 for (int i = 0; i < args.Length(); i++)
1618 result->Set(v8::Integer::New(i), args[i]);
1619 return scope.Close(result);
1620}
1621
1622
1623THREADED_TEST(Vector) {
1624 v8::HandleScope scope;
1625 Local<ObjectTemplate> global = ObjectTemplate::New();
1626 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1627 LocalContext context(0, global);
1628
1629 const char* fun = "f()";
1630 Local<v8::Array> a0 =
1631 Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1632 CHECK_EQ(0, a0->Length());
1633
1634 const char* fun2 = "f(11)";
1635 Local<v8::Array> a1 =
1636 Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1637 CHECK_EQ(1, a1->Length());
1638 CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1639
1640 const char* fun3 = "f(12, 13)";
1641 Local<v8::Array> a2 =
1642 Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1643 CHECK_EQ(2, a2->Length());
1644 CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1645 CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1646
1647 const char* fun4 = "f(14, 15, 16)";
1648 Local<v8::Array> a3 =
1649 Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1650 CHECK_EQ(3, a3->Length());
1651 CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1652 CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1653 CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1654
1655 const char* fun5 = "f(17, 18, 19, 20)";
1656 Local<v8::Array> a4 =
1657 Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1658 CHECK_EQ(4, a4->Length());
1659 CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1660 CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1661 CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1662 CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1663}
1664
1665
1666THREADED_TEST(FunctionCall) {
1667 v8::HandleScope scope;
1668 LocalContext context;
1669 CompileRun(
1670 "function Foo() {"
1671 " var result = [];"
1672 " for (var i = 0; i < arguments.length; i++) {"
1673 " result.push(arguments[i]);"
1674 " }"
1675 " return result;"
1676 "}");
1677 Local<Function> Foo =
1678 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1679
1680 v8::Handle<Value>* args0 = NULL;
1681 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1682 CHECK_EQ(0, a0->Length());
1683
1684 v8::Handle<Value> args1[] = { v8_num(1.1) };
1685 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1686 CHECK_EQ(1, a1->Length());
1687 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1688
1689 v8::Handle<Value> args2[] = { v8_num(2.2),
1690 v8_num(3.3) };
1691 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1692 CHECK_EQ(2, a2->Length());
1693 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1694 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1695
1696 v8::Handle<Value> args3[] = { v8_num(4.4),
1697 v8_num(5.5),
1698 v8_num(6.6) };
1699 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1700 CHECK_EQ(3, a3->Length());
1701 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1702 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1703 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1704
1705 v8::Handle<Value> args4[] = { v8_num(7.7),
1706 v8_num(8.8),
1707 v8_num(9.9),
1708 v8_num(10.11) };
1709 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1710 CHECK_EQ(4, a4->Length());
1711 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1712 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1713 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1714 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1715}
1716
1717
1718static const char* js_code_causing_out_of_memory =
1719 "var a = new Array(); while(true) a.push(a);";
1720
1721
1722// These tests run for a long time and prevent us from running tests
1723// that come after them so they cannot run in parallel.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001724TEST(OutOfMemory) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001725 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001726 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001727 // Set heap limits.
1728 static const int K = 1024;
1729 v8::ResourceConstraints constraints;
1730 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001731 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001732 v8::SetResourceConstraints(&constraints);
1733
1734 // Execute a script that causes out of memory.
1735 v8::HandleScope scope;
1736 LocalContext context;
1737 v8::V8::IgnoreOutOfMemoryException();
1738 Local<Script> script =
1739 Script::Compile(String::New(js_code_causing_out_of_memory));
1740 Local<Value> result = script->Run();
1741
1742 // Check for out of memory state.
1743 CHECK(result.IsEmpty());
1744 CHECK(context->HasOutOfMemoryException());
1745}
1746
1747
1748v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1749 ApiTestFuzzer::Fuzz();
1750
1751 v8::HandleScope scope;
1752 LocalContext context;
1753 Local<Script> script =
1754 Script::Compile(String::New(js_code_causing_out_of_memory));
1755 Local<Value> result = script->Run();
1756
1757 // Check for out of memory state.
1758 CHECK(result.IsEmpty());
1759 CHECK(context->HasOutOfMemoryException());
1760
1761 return result;
1762}
1763
1764
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001765TEST(OutOfMemoryNested) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001766 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001767 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001768 // Set heap limits.
1769 static const int K = 1024;
1770 v8::ResourceConstraints constraints;
1771 constraints.set_max_young_space_size(256 * K);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001772 constraints.set_max_old_space_size(4 * K * K);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001773 v8::SetResourceConstraints(&constraints);
1774
1775 v8::HandleScope scope;
1776 Local<ObjectTemplate> templ = ObjectTemplate::New();
1777 templ->Set(v8_str("ProvokeOutOfMemory"),
1778 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1779 LocalContext context(0, templ);
1780 v8::V8::IgnoreOutOfMemoryException();
1781 Local<Value> result = CompileRun(
1782 "var thrown = false;"
1783 "try {"
1784 " ProvokeOutOfMemory();"
1785 "} catch (e) {"
1786 " thrown = true;"
1787 "}");
1788 // Check for out of memory state.
1789 CHECK(result.IsEmpty());
1790 CHECK(context->HasOutOfMemoryException());
1791}
1792
1793
1794TEST(HugeConsStringOutOfMemory) {
1795 // It's not possible to read a snapshot into a heap with different dimensions.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001796 if (v8::internal::Snapshot::IsEnabled()) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001797 v8::HandleScope scope;
1798 LocalContext context;
1799 // Set heap limits.
1800 static const int K = 1024;
1801 v8::ResourceConstraints constraints;
1802 constraints.set_max_young_space_size(256 * K);
1803 constraints.set_max_old_space_size(2 * K * K);
1804 v8::SetResourceConstraints(&constraints);
1805
1806 // Execute a script that causes out of memory.
1807 v8::V8::IgnoreOutOfMemoryException();
1808
1809 // Build huge string. This should fail with out of memory exception.
1810 Local<Value> result = CompileRun(
1811 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1812 "for (var i = 0; i < 21; i++) { str = str + str; }");
1813
1814 // Check for out of memory state.
1815 CHECK(result.IsEmpty());
1816 CHECK(context->HasOutOfMemoryException());
1817}
1818
1819
1820THREADED_TEST(ConstructCall) {
1821 v8::HandleScope scope;
1822 LocalContext context;
1823 CompileRun(
1824 "function Foo() {"
1825 " var result = [];"
1826 " for (var i = 0; i < arguments.length; i++) {"
1827 " result.push(arguments[i]);"
1828 " }"
1829 " return result;"
1830 "}");
1831 Local<Function> Foo =
1832 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1833
1834 v8::Handle<Value>* args0 = NULL;
1835 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1836 CHECK_EQ(0, a0->Length());
1837
1838 v8::Handle<Value> args1[] = { v8_num(1.1) };
1839 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1840 CHECK_EQ(1, a1->Length());
1841 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1842
1843 v8::Handle<Value> args2[] = { v8_num(2.2),
1844 v8_num(3.3) };
1845 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1846 CHECK_EQ(2, a2->Length());
1847 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1848 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1849
1850 v8::Handle<Value> args3[] = { v8_num(4.4),
1851 v8_num(5.5),
1852 v8_num(6.6) };
1853 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1854 CHECK_EQ(3, a3->Length());
1855 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1856 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1857 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1858
1859 v8::Handle<Value> args4[] = { v8_num(7.7),
1860 v8_num(8.8),
1861 v8_num(9.9),
1862 v8_num(10.11) };
1863 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1864 CHECK_EQ(4, a4->Length());
1865 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1866 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1867 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1868 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1869}
1870
1871
1872static void CheckUncle(v8::TryCatch* try_catch) {
1873 CHECK(try_catch->HasCaught());
1874 String::AsciiValue str_value(try_catch->Exception());
1875 CHECK_EQ(*str_value, "uncle?");
1876 try_catch->Reset();
1877}
1878
1879
1880THREADED_TEST(ConversionException) {
1881 v8::HandleScope scope;
1882 LocalContext env;
1883 CompileRun(
1884 "function TestClass() { };"
1885 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1886 "var obj = new TestClass();");
1887 Local<Value> obj = env->Global()->Get(v8_str("obj"));
1888
1889 v8::TryCatch try_catch;
1890
1891 Local<Value> to_string_result = obj->ToString();
1892 CHECK(to_string_result.IsEmpty());
1893 CheckUncle(&try_catch);
1894
1895 Local<Value> to_number_result = obj->ToNumber();
1896 CHECK(to_number_result.IsEmpty());
1897 CheckUncle(&try_catch);
1898
1899 Local<Value> to_integer_result = obj->ToInteger();
1900 CHECK(to_integer_result.IsEmpty());
1901 CheckUncle(&try_catch);
1902
1903 Local<Value> to_uint32_result = obj->ToUint32();
1904 CHECK(to_uint32_result.IsEmpty());
1905 CheckUncle(&try_catch);
1906
1907 Local<Value> to_int32_result = obj->ToInt32();
1908 CHECK(to_int32_result.IsEmpty());
1909 CheckUncle(&try_catch);
1910
1911 Local<Value> to_object_result = v8::Undefined()->ToObject();
1912 CHECK(to_object_result.IsEmpty());
1913 CHECK(try_catch.HasCaught());
1914 try_catch.Reset();
1915
1916 int32_t int32_value = obj->Int32Value();
1917 CHECK_EQ(0, int32_value);
1918 CheckUncle(&try_catch);
1919
1920 uint32_t uint32_value = obj->Uint32Value();
1921 CHECK_EQ(0, uint32_value);
1922 CheckUncle(&try_catch);
1923
1924 double number_value = obj->NumberValue();
1925 CHECK_NE(0, IsNaN(number_value));
1926 CheckUncle(&try_catch);
1927
1928 int64_t integer_value = obj->IntegerValue();
1929 CHECK_EQ(0.0, static_cast<double>(integer_value));
1930 CheckUncle(&try_catch);
1931}
1932
1933
1934v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1935 ApiTestFuzzer::Fuzz();
1936 return v8::ThrowException(v8_str("konto"));
1937}
1938
1939
ager@chromium.org8bb60582008-12-11 12:02:20 +00001940v8::Handle<Value> CCatcher(const v8::Arguments& args) {
1941 if (args.Length() < 1) return v8::Boolean::New(false);
1942 v8::HandleScope scope;
1943 v8::TryCatch try_catch;
ager@chromium.org71daaf62009-04-01 07:22:49 +00001944 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
1945 CHECK(!try_catch.HasCaught() || result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00001946 return v8::Boolean::New(try_catch.HasCaught());
1947}
1948
1949
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001950THREADED_TEST(APICatch) {
1951 v8::HandleScope scope;
1952 Local<ObjectTemplate> templ = ObjectTemplate::New();
1953 templ->Set(v8_str("ThrowFromC"),
1954 v8::FunctionTemplate::New(ThrowFromC));
1955 LocalContext context(0, templ);
1956 CompileRun(
1957 "var thrown = false;"
1958 "try {"
1959 " ThrowFromC();"
1960 "} catch (e) {"
1961 " thrown = true;"
1962 "}");
1963 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
1964 CHECK(thrown->BooleanValue());
1965}
1966
1967
ager@chromium.org8bb60582008-12-11 12:02:20 +00001968THREADED_TEST(APIThrowTryCatch) {
1969 v8::HandleScope scope;
1970 Local<ObjectTemplate> templ = ObjectTemplate::New();
1971 templ->Set(v8_str("ThrowFromC"),
1972 v8::FunctionTemplate::New(ThrowFromC));
1973 LocalContext context(0, templ);
1974 v8::TryCatch try_catch;
1975 CompileRun("ThrowFromC();");
1976 CHECK(try_catch.HasCaught());
1977}
1978
1979
1980// Test that a try-finally block doesn't shadow a try-catch block
1981// when setting up an external handler.
ager@chromium.org71daaf62009-04-01 07:22:49 +00001982//
1983// BUG(271): Some of the exception propagation does not work on the
1984// ARM simulator because the simulator separates the C++ stack and the
1985// JS stack. This test therefore fails on the simulator. The test is
1986// not threaded to allow the threading tests to run on the simulator.
1987TEST(TryCatchInTryFinally) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001988 v8::HandleScope scope;
1989 Local<ObjectTemplate> templ = ObjectTemplate::New();
1990 templ->Set(v8_str("CCatcher"),
1991 v8::FunctionTemplate::New(CCatcher));
1992 LocalContext context(0, templ);
1993 Local<Value> result = CompileRun("try {"
1994 " try {"
1995 " CCatcher('throw 7;');"
1996 " } finally {"
1997 " }"
1998 "} catch (e) {"
1999 "}");
2000 CHECK(result->IsTrue());
2001}
2002
2003
2004static void receive_message(v8::Handle<v8::Message> message,
2005 v8::Handle<v8::Value> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002006 message->Get();
ager@chromium.org8bb60582008-12-11 12:02:20 +00002007 message_received = true;
2008}
2009
2010
2011TEST(APIThrowMessage) {
2012 message_received = false;
2013 v8::HandleScope scope;
2014 v8::V8::AddMessageListener(receive_message);
2015 Local<ObjectTemplate> templ = ObjectTemplate::New();
2016 templ->Set(v8_str("ThrowFromC"),
2017 v8::FunctionTemplate::New(ThrowFromC));
2018 LocalContext context(0, templ);
2019 CompileRun("ThrowFromC();");
2020 CHECK(message_received);
2021 v8::V8::RemoveMessageListeners(check_message);
2022}
2023
2024
2025TEST(APIThrowMessageAndVerboseTryCatch) {
2026 message_received = false;
2027 v8::HandleScope scope;
2028 v8::V8::AddMessageListener(receive_message);
2029 Local<ObjectTemplate> templ = ObjectTemplate::New();
2030 templ->Set(v8_str("ThrowFromC"),
2031 v8::FunctionTemplate::New(ThrowFromC));
2032 LocalContext context(0, templ);
2033 v8::TryCatch try_catch;
2034 try_catch.SetVerbose(true);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002035 Local<Value> result = CompileRun("ThrowFromC();");
ager@chromium.org8bb60582008-12-11 12:02:20 +00002036 CHECK(try_catch.HasCaught());
ager@chromium.org71daaf62009-04-01 07:22:49 +00002037 CHECK(result.IsEmpty());
ager@chromium.org8bb60582008-12-11 12:02:20 +00002038 CHECK(message_received);
2039 v8::V8::RemoveMessageListeners(check_message);
2040}
2041
2042
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002043THREADED_TEST(ExternalScriptException) {
2044 v8::HandleScope scope;
2045 Local<ObjectTemplate> templ = ObjectTemplate::New();
2046 templ->Set(v8_str("ThrowFromC"),
2047 v8::FunctionTemplate::New(ThrowFromC));
2048 LocalContext context(0, templ);
2049
2050 v8::TryCatch try_catch;
2051 Local<Script> script
2052 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2053 Local<Value> result = script->Run();
2054 CHECK(result.IsEmpty());
2055 CHECK(try_catch.HasCaught());
2056 String::AsciiValue exception_value(try_catch.Exception());
2057 CHECK_EQ("konto", *exception_value);
2058}
2059
2060
2061
2062v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2063 ApiTestFuzzer::Fuzz();
2064 CHECK_EQ(4, args.Length());
2065 int count = args[0]->Int32Value();
2066 int cInterval = args[2]->Int32Value();
2067 if (count == 0) {
2068 return v8::ThrowException(v8_str("FromC"));
2069 } else {
2070 Local<v8::Object> global = Context::GetCurrent()->Global();
2071 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2072 v8::Handle<Value> argv[] = { v8_num(count - 1),
2073 args[1],
2074 args[2],
2075 args[3] };
2076 if (count % cInterval == 0) {
2077 v8::TryCatch try_catch;
2078 Local<Value> result =
2079 v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2080 int expected = args[3]->Int32Value();
2081 if (try_catch.HasCaught()) {
2082 CHECK_EQ(expected, count);
ager@chromium.org71daaf62009-04-01 07:22:49 +00002083 CHECK(result.IsEmpty());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002084 CHECK(!i::Top::has_scheduled_exception());
2085 } else {
2086 CHECK_NE(expected, count);
2087 }
2088 return result;
2089 } else {
2090 return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2091 }
2092 }
2093}
2094
2095
2096v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2097 ApiTestFuzzer::Fuzz();
2098 CHECK_EQ(3, args.Length());
2099 bool equality = args[0]->BooleanValue();
2100 int count = args[1]->Int32Value();
2101 int expected = args[2]->Int32Value();
2102 if (equality) {
2103 CHECK_EQ(count, expected);
2104 } else {
2105 CHECK_NE(count, expected);
2106 }
2107 return v8::Undefined();
2108}
2109
2110
ager@chromium.org8bb60582008-12-11 12:02:20 +00002111THREADED_TEST(EvalInTryFinally) {
2112 v8::HandleScope scope;
2113 LocalContext context;
2114 v8::TryCatch try_catch;
2115 CompileRun("(function() {"
2116 " try {"
2117 " eval('asldkf (*&^&*^');"
2118 " } finally {"
2119 " return;"
2120 " }"
2121 "})()");
2122 CHECK(!try_catch.HasCaught());
2123}
2124
2125
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002126// This test works by making a stack of alternating JavaScript and C
2127// activations. These activations set up exception handlers with regular
2128// intervals, one interval for C activations and another for JavaScript
2129// activations. When enough activations have been created an exception is
2130// thrown and we check that the right activation catches the exception and that
2131// no other activations do. The right activation is always the topmost one with
2132// a handler, regardless of whether it is in JavaScript or C.
2133//
2134// The notation used to describe a test case looks like this:
2135//
2136// *JS[4] *C[3] @JS[2] C[1] JS[0]
2137//
2138// Each entry is an activation, either JS or C. The index is the count at that
2139// level. Stars identify activations with exception handlers, the @ identifies
2140// the exception handler that should catch the exception.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002141//
2142// BUG(271): Some of the exception propagation does not work on the
2143// ARM simulator because the simulator separates the C++ stack and the
2144// JS stack. This test therefore fails on the simulator. The test is
2145// not threaded to allow the threading tests to run on the simulator.
2146TEST(ExceptionOrder) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002147 v8::HandleScope scope;
2148 Local<ObjectTemplate> templ = ObjectTemplate::New();
2149 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2150 templ->Set(v8_str("CThrowCountDown"),
2151 v8::FunctionTemplate::New(CThrowCountDown));
2152 LocalContext context(0, templ);
2153 CompileRun(
2154 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2155 " if (count == 0) throw 'FromJS';"
2156 " if (count % jsInterval == 0) {"
2157 " try {"
2158 " var value = CThrowCountDown(count - 1,"
2159 " jsInterval,"
2160 " cInterval,"
2161 " expected);"
2162 " check(false, count, expected);"
2163 " return value;"
2164 " } catch (e) {"
2165 " check(true, count, expected);"
2166 " }"
2167 " } else {"
2168 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2169 " }"
2170 "}");
2171 Local<Function> fun =
2172 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2173
2174 const int argc = 4;
2175 // count jsInterval cInterval expected
2176
2177 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2178 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2179 fun->Call(fun, argc, a0);
2180
2181 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2182 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2183 fun->Call(fun, argc, a1);
2184
2185 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2186 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2187 fun->Call(fun, argc, a2);
2188
2189 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2190 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2191 fun->Call(fun, argc, a3);
2192
2193 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2194 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2195 fun->Call(fun, argc, a4);
2196
2197 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2198 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2199 fun->Call(fun, argc, a5);
2200}
2201
2202
2203v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2204 ApiTestFuzzer::Fuzz();
2205 CHECK_EQ(1, args.Length());
2206 return v8::ThrowException(args[0]);
2207}
2208
2209
2210THREADED_TEST(ThrowValues) {
2211 v8::HandleScope scope;
2212 Local<ObjectTemplate> templ = ObjectTemplate::New();
2213 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2214 LocalContext context(0, templ);
2215 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2216 "function Run(obj) {"
2217 " try {"
2218 " Throw(obj);"
2219 " } catch (e) {"
2220 " return e;"
2221 " }"
2222 " return 'no exception';"
2223 "}"
2224 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2225 CHECK_EQ(5, result->Length());
2226 CHECK(result->Get(v8::Integer::New(0))->IsString());
2227 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2228 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2229 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2230 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2231 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2232 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2233}
2234
2235
2236THREADED_TEST(CatchZero) {
2237 v8::HandleScope scope;
2238 LocalContext context;
2239 v8::TryCatch try_catch;
2240 CHECK(!try_catch.HasCaught());
2241 Script::Compile(v8_str("throw 10"))->Run();
2242 CHECK(try_catch.HasCaught());
2243 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2244 try_catch.Reset();
2245 CHECK(!try_catch.HasCaught());
2246 Script::Compile(v8_str("throw 0"))->Run();
2247 CHECK(try_catch.HasCaught());
2248 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2249}
2250
2251
2252THREADED_TEST(CatchExceptionFromWith) {
2253 v8::HandleScope scope;
2254 LocalContext context;
2255 v8::TryCatch try_catch;
2256 CHECK(!try_catch.HasCaught());
2257 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2258 CHECK(try_catch.HasCaught());
2259}
2260
2261
2262THREADED_TEST(Equality) {
2263 v8::HandleScope scope;
2264 LocalContext context;
2265 // Check that equality works at all before relying on CHECK_EQ
2266 CHECK(v8_str("a")->Equals(v8_str("a")));
2267 CHECK(!v8_str("a")->Equals(v8_str("b")));
2268
2269 CHECK_EQ(v8_str("a"), v8_str("a"));
2270 CHECK_NE(v8_str("a"), v8_str("b"));
2271 CHECK_EQ(v8_num(1), v8_num(1));
2272 CHECK_EQ(v8_num(1.00), v8_num(1));
2273 CHECK_NE(v8_num(1), v8_num(2));
2274
2275 // Assume String is not symbol.
2276 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2277 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2278 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2279 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2280 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2281 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2282 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2283 CHECK(!not_a_number->StrictEquals(not_a_number));
2284 CHECK(v8::False()->StrictEquals(v8::False()));
2285 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2286
2287 v8::Handle<v8::Object> obj = v8::Object::New();
2288 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2289 CHECK(alias->StrictEquals(obj));
2290 alias.Dispose();
2291}
2292
2293
2294THREADED_TEST(MultiRun) {
2295 v8::HandleScope scope;
2296 LocalContext context;
2297 Local<Script> script = Script::Compile(v8_str("x"));
2298 for (int i = 0; i < 10; i++)
2299 script->Run();
2300}
2301
2302
2303static v8::Handle<Value> GetXValue(Local<String> name,
2304 const AccessorInfo& info) {
2305 ApiTestFuzzer::Fuzz();
2306 CHECK_EQ(info.Data(), v8_str("donut"));
2307 CHECK_EQ(name, v8_str("x"));
2308 return name;
2309}
2310
2311
2312THREADED_TEST(SimplePropertyRead) {
2313 v8::HandleScope scope;
2314 Local<ObjectTemplate> templ = ObjectTemplate::New();
2315 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2316 LocalContext context;
2317 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2318 Local<Script> script = Script::Compile(v8_str("obj.x"));
2319 for (int i = 0; i < 10; i++) {
2320 Local<Value> result = script->Run();
2321 CHECK_EQ(result, v8_str("x"));
2322 }
2323}
2324
2325
2326v8::Persistent<Value> xValue;
2327
2328
2329static void SetXValue(Local<String> name,
2330 Local<Value> value,
2331 const AccessorInfo& info) {
2332 CHECK_EQ(value, v8_num(4));
2333 CHECK_EQ(info.Data(), v8_str("donut"));
2334 CHECK_EQ(name, v8_str("x"));
2335 CHECK(xValue.IsEmpty());
2336 xValue = v8::Persistent<Value>::New(value);
2337}
2338
2339
2340THREADED_TEST(SimplePropertyWrite) {
2341 v8::HandleScope scope;
2342 Local<ObjectTemplate> templ = ObjectTemplate::New();
2343 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2344 LocalContext context;
2345 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2346 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2347 for (int i = 0; i < 10; i++) {
2348 CHECK(xValue.IsEmpty());
2349 script->Run();
2350 CHECK_EQ(v8_num(4), xValue);
2351 xValue.Dispose();
2352 xValue = v8::Persistent<Value>();
2353 }
2354}
2355
2356
2357static v8::Handle<Value> XPropertyGetter(Local<String> property,
2358 const AccessorInfo& info) {
2359 ApiTestFuzzer::Fuzz();
2360 CHECK(info.Data()->IsUndefined());
2361 return property;
2362}
2363
2364
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002365THREADED_TEST(NamedInterceptorPropertyRead) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002366 v8::HandleScope scope;
2367 Local<ObjectTemplate> templ = ObjectTemplate::New();
2368 templ->SetNamedPropertyHandler(XPropertyGetter);
2369 LocalContext context;
2370 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2371 Local<Script> script = Script::Compile(v8_str("obj.x"));
2372 for (int i = 0; i < 10; i++) {
2373 Local<Value> result = script->Run();
2374 CHECK_EQ(result, v8_str("x"));
2375 }
2376}
2377
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002378
2379static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2380 const AccessorInfo& info) {
2381 ApiTestFuzzer::Fuzz();
2382 if (index == 37) {
2383 return v8::Handle<Value>(v8_num(625));
2384 }
2385 return v8::Handle<Value>();
2386}
2387
2388
2389static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2390 Local<Value> value,
2391 const AccessorInfo& info) {
2392 ApiTestFuzzer::Fuzz();
2393 if (index == 39) {
2394 return value;
2395 }
2396 return v8::Handle<Value>();
2397}
2398
2399
2400THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2401 v8::HandleScope scope;
2402 Local<ObjectTemplate> templ = ObjectTemplate::New();
2403 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2404 IndexedPropertySetter);
2405 LocalContext context;
2406 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2407 Local<Script> getter_script = Script::Compile(v8_str(
2408 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2409 Local<Script> setter_script = Script::Compile(v8_str(
2410 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2411 "obj[17] = 23;"
2412 "obj.foo;"));
2413 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2414 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2415 "obj[39] = 47;"
2416 "obj.foo;")); // This setter should not run, due to the interceptor.
2417 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2418 "obj[37];"));
2419 Local<Value> result = getter_script->Run();
2420 CHECK_EQ(v8_num(5), result);
2421 result = setter_script->Run();
2422 CHECK_EQ(v8_num(23), result);
2423 result = interceptor_setter_script->Run();
2424 CHECK_EQ(v8_num(23), result);
2425 result = interceptor_getter_script->Run();
2426 CHECK_EQ(v8_num(625), result);
2427}
2428
2429
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002430THREADED_TEST(MultiContexts) {
2431 v8::HandleScope scope;
2432 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2433 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2434
2435 Local<String> password = v8_str("Password");
2436
2437 // Create an environment
2438 LocalContext context0(0, templ);
2439 context0->SetSecurityToken(password);
2440 v8::Handle<v8::Object> global0 = context0->Global();
2441 global0->Set(v8_str("custom"), v8_num(1234));
2442 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2443
2444 // Create an independent environment
2445 LocalContext context1(0, templ);
2446 context1->SetSecurityToken(password);
2447 v8::Handle<v8::Object> global1 = context1->Global();
2448 global1->Set(v8_str("custom"), v8_num(1234));
2449 CHECK_NE(global0, global1);
2450 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2451 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2452
2453 // Now create a new context with the old global
2454 LocalContext context2(0, templ, global1);
2455 context2->SetSecurityToken(password);
2456 v8::Handle<v8::Object> global2 = context2->Global();
2457 CHECK_EQ(global1, global2);
2458 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2459 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2460}
2461
2462
2463THREADED_TEST(FunctionPrototypeAcrossContexts) {
2464 // Make sure that functions created by cloning boilerplates cannot
2465 // communicate through their __proto__ field.
2466
2467 v8::HandleScope scope;
2468
2469 LocalContext env0;
2470 v8::Handle<v8::Object> global0 =
2471 env0->Global();
2472 v8::Handle<v8::Object> object0 =
2473 v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2474 v8::Handle<v8::Object> tostring0 =
2475 v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2476 v8::Handle<v8::Object> proto0 =
2477 v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2478 proto0->Set(v8_str("custom"), v8_num(1234));
2479
2480 LocalContext env1;
2481 v8::Handle<v8::Object> global1 =
2482 env1->Global();
2483 v8::Handle<v8::Object> object1 =
2484 v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2485 v8::Handle<v8::Object> tostring1 =
2486 v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2487 v8::Handle<v8::Object> proto1 =
2488 v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2489 CHECK(!proto1->Has(v8_str("custom")));
2490}
2491
2492
2493THREADED_TEST(Regress892105) {
2494 // Make sure that object and array literals created by cloning
2495 // boilerplates cannot communicate through their __proto__
2496 // field. This is rather difficult to check, but we try to add stuff
2497 // to Object.prototype and Array.prototype and create a new
2498 // environment. This should succeed.
2499
2500 v8::HandleScope scope;
2501
2502 Local<String> source = v8_str("Object.prototype.obj = 1234;"
2503 "Array.prototype.arr = 4567;"
2504 "8901");
2505
2506 LocalContext env0;
2507 Local<Script> script0 = Script::Compile(source);
2508 CHECK_EQ(8901.0, script0->Run()->NumberValue());
2509
2510 LocalContext env1;
2511 Local<Script> script1 = Script::Compile(source);
2512 CHECK_EQ(8901.0, script1->Run()->NumberValue());
2513}
2514
2515
2516static void ExpectString(const char* code, const char* expected) {
2517 Local<Value> result = CompileRun(code);
2518 CHECK(result->IsString());
2519 String::AsciiValue ascii(result);
2520 CHECK_EQ(0, strcmp(*ascii, expected));
2521}
2522
2523
2524static void ExpectBoolean(const char* code, bool expected) {
2525 Local<Value> result = CompileRun(code);
2526 CHECK(result->IsBoolean());
2527 CHECK_EQ(expected, result->BooleanValue());
2528}
2529
2530
2531static void ExpectObject(const char* code, Local<Value> expected) {
2532 Local<Value> result = CompileRun(code);
2533 CHECK(result->Equals(expected));
2534}
2535
2536
2537THREADED_TEST(UndetectableObject) {
2538 v8::HandleScope scope;
2539 LocalContext env;
2540
2541 Local<v8::FunctionTemplate> desc =
2542 v8::FunctionTemplate::New(0, v8::Handle<Value>());
2543 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
2544
2545 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2546 env->Global()->Set(v8_str("undetectable"), obj);
2547
2548 ExpectString("undetectable.toString()", "[object Object]");
2549 ExpectString("typeof undetectable", "undefined");
2550 ExpectString("typeof(undetectable)", "undefined");
2551 ExpectBoolean("typeof undetectable == 'undefined'", true);
2552 ExpectBoolean("typeof undetectable == 'object'", false);
2553 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2554 ExpectBoolean("!undetectable", true);
2555
2556 ExpectObject("true&&undetectable", obj);
2557 ExpectBoolean("false&&undetectable", false);
2558 ExpectBoolean("true||undetectable", true);
2559 ExpectObject("false||undetectable", obj);
2560
2561 ExpectObject("undetectable&&true", obj);
2562 ExpectObject("undetectable&&false", obj);
2563 ExpectBoolean("undetectable||true", true);
2564 ExpectBoolean("undetectable||false", false);
2565
2566 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002567 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002568 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002569 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002570 ExpectBoolean("undetectable==undetectable", true);
2571
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002572
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002573 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002574 ExpectBoolean("null===undetectable", false);
2575 ExpectBoolean("undetectable===undefined", false);
2576 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002577 ExpectBoolean("undetectable===undetectable", true);
2578}
2579
2580
2581THREADED_TEST(UndetectableString) {
2582 v8::HandleScope scope;
2583 LocalContext env;
2584
2585 Local<String> obj = String::NewUndetectable("foo");
2586 env->Global()->Set(v8_str("undetectable"), obj);
2587
2588 ExpectString("undetectable", "foo");
2589 ExpectString("typeof undetectable", "undefined");
2590 ExpectString("typeof(undetectable)", "undefined");
2591 ExpectBoolean("typeof undetectable == 'undefined'", true);
2592 ExpectBoolean("typeof undetectable == 'string'", false);
2593 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2594 ExpectBoolean("!undetectable", true);
2595
2596 ExpectObject("true&&undetectable", obj);
2597 ExpectBoolean("false&&undetectable", false);
2598 ExpectBoolean("true||undetectable", true);
2599 ExpectObject("false||undetectable", obj);
2600
2601 ExpectObject("undetectable&&true", obj);
2602 ExpectObject("undetectable&&false", obj);
2603 ExpectBoolean("undetectable||true", true);
2604 ExpectBoolean("undetectable||false", false);
2605
2606 ExpectBoolean("undetectable==null", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002607 ExpectBoolean("null==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002608 ExpectBoolean("undetectable==undefined", true);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002609 ExpectBoolean("undefined==undetectable", true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002610 ExpectBoolean("undetectable==undetectable", true);
2611
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002612
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002613 ExpectBoolean("undetectable===null", false);
kasperl@chromium.org8ccb0be2009-04-07 07:21:39 +00002614 ExpectBoolean("null===undetectable", false);
2615 ExpectBoolean("undetectable===undefined", false);
2616 ExpectBoolean("undefined===undetectable", false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002617 ExpectBoolean("undetectable===undetectable", true);
2618}
2619
2620
2621template <typename T> static void USE(T) { }
2622
2623
2624// This test is not intended to be run, just type checked.
2625static void PersistentHandles() {
2626 USE(PersistentHandles);
2627 Local<String> str = v8_str("foo");
2628 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
2629 USE(p_str);
2630 Local<Script> scr = Script::Compile(v8_str(""));
2631 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
2632 USE(p_scr);
2633 Local<ObjectTemplate> templ = ObjectTemplate::New();
2634 v8::Persistent<ObjectTemplate> p_templ =
2635 v8::Persistent<ObjectTemplate>::New(templ);
2636 USE(p_templ);
2637}
2638
2639
2640static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
2641 ApiTestFuzzer::Fuzz();
2642 return v8::Undefined();
2643}
2644
2645
2646THREADED_TEST(GlobalObjectTemplate) {
2647 v8::HandleScope handle_scope;
2648 Local<ObjectTemplate> global_template = ObjectTemplate::New();
2649 global_template->Set(v8_str("JSNI_Log"),
2650 v8::FunctionTemplate::New(HandleLogDelegator));
2651 v8::Persistent<Context> context = Context::New(0, global_template);
2652 Context::Scope context_scope(context);
2653 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
2654 context.Dispose();
2655}
2656
2657
2658static const char* kSimpleExtensionSource =
2659 "function Foo() {"
2660 " return 4;"
2661 "}";
2662
2663
2664THREADED_TEST(SimpleExtensions) {
2665 v8::HandleScope handle_scope;
2666 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
2667 const char* extension_names[] = { "simpletest" };
2668 v8::ExtensionConfiguration extensions(1, extension_names);
2669 v8::Handle<Context> context = Context::New(&extensions);
2670 Context::Scope lock(context);
2671 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2672 CHECK_EQ(result, v8::Integer::New(4));
2673}
2674
2675
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00002676static const char* kEvalExtensionSource =
2677 "function UseEval() {"
2678 " var x = 42;"
2679 " return eval('x');"
2680 "}";
2681
2682
2683THREADED_TEST(UseEvalFromExtension) {
2684 v8::HandleScope handle_scope;
2685 v8::RegisterExtension(new Extension("evaltest", kEvalExtensionSource));
2686 const char* extension_names[] = { "evaltest" };
2687 v8::ExtensionConfiguration extensions(1, extension_names);
2688 v8::Handle<Context> context = Context::New(&extensions);
2689 Context::Scope lock(context);
2690 v8::Handle<Value> result = Script::Compile(v8_str("UseEval()"))->Run();
2691 CHECK_EQ(result, v8::Integer::New(42));
2692}
2693
2694
2695static const char* kWithExtensionSource =
2696 "function UseWith() {"
2697 " var x = 42;"
2698 " with({x:87}) { return x; }"
2699 "}";
2700
2701
2702THREADED_TEST(UseWithFromExtension) {
2703 v8::HandleScope handle_scope;
2704 v8::RegisterExtension(new Extension("withtest", kWithExtensionSource));
2705 const char* extension_names[] = { "withtest" };
2706 v8::ExtensionConfiguration extensions(1, extension_names);
2707 v8::Handle<Context> context = Context::New(&extensions);
2708 Context::Scope lock(context);
2709 v8::Handle<Value> result = Script::Compile(v8_str("UseWith()"))->Run();
2710 CHECK_EQ(result, v8::Integer::New(87));
2711}
2712
2713
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002714THREADED_TEST(AutoExtensions) {
2715 v8::HandleScope handle_scope;
2716 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
2717 extension->set_auto_enable(true);
2718 v8::RegisterExtension(extension);
2719 v8::Handle<Context> context = Context::New();
2720 Context::Scope lock(context);
2721 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2722 CHECK_EQ(result, v8::Integer::New(4));
2723}
2724
2725
2726static void CheckDependencies(const char* name, const char* expected) {
2727 v8::HandleScope handle_scope;
2728 v8::ExtensionConfiguration config(1, &name);
2729 LocalContext context(&config);
2730 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
2731}
2732
2733
2734/*
2735 * Configuration:
2736 *
2737 * /-- B <--\
2738 * A <- -- D <-- E
2739 * \-- C <--/
2740 */
2741THREADED_TEST(ExtensionDependency) {
2742 static const char* kEDeps[] = { "D" };
2743 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
2744 static const char* kDDeps[] = { "B", "C" };
2745 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
2746 static const char* kBCDeps[] = { "A" };
2747 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
2748 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
2749 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
2750 CheckDependencies("A", "undefinedA");
2751 CheckDependencies("B", "undefinedAB");
2752 CheckDependencies("C", "undefinedAC");
2753 CheckDependencies("D", "undefinedABCD");
2754 CheckDependencies("E", "undefinedABCDE");
2755 v8::HandleScope handle_scope;
2756 static const char* exts[2] = { "C", "E" };
2757 v8::ExtensionConfiguration config(2, exts);
2758 LocalContext context(&config);
2759 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
2760}
2761
2762
2763static const char* kExtensionTestScript =
2764 "native function A();"
2765 "native function B();"
2766 "native function C();"
2767 "function Foo(i) {"
2768 " if (i == 0) return A();"
2769 " if (i == 1) return B();"
2770 " if (i == 2) return C();"
2771 "}";
2772
2773
2774static v8::Handle<Value> CallFun(const v8::Arguments& args) {
2775 ApiTestFuzzer::Fuzz();
2776 return args.Data();
2777}
2778
2779
2780class FunctionExtension : public Extension {
2781 public:
2782 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
2783 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
2784 v8::Handle<String> name);
2785};
2786
2787
2788static int lookup_count = 0;
2789v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
2790 v8::Handle<String> name) {
2791 lookup_count++;
2792 if (name->Equals(v8_str("A"))) {
2793 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
2794 } else if (name->Equals(v8_str("B"))) {
2795 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
2796 } else if (name->Equals(v8_str("C"))) {
2797 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
2798 } else {
2799 return v8::Handle<v8::FunctionTemplate>();
2800 }
2801}
2802
2803
2804THREADED_TEST(FunctionLookup) {
2805 v8::RegisterExtension(new FunctionExtension());
2806 v8::HandleScope handle_scope;
2807 static const char* exts[1] = { "functiontest" };
2808 v8::ExtensionConfiguration config(1, exts);
2809 LocalContext context(&config);
2810 CHECK_EQ(3, lookup_count);
2811 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
2812 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
2813 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
2814}
2815
2816
2817static const char* last_location;
2818static const char* last_message;
2819void StoringErrorCallback(const char* location, const char* message) {
2820 if (last_location == NULL) {
2821 last_location = location;
2822 last_message = message;
2823 }
2824}
2825
2826
2827// ErrorReporting creates a circular extensions configuration and
2828// tests that the fatal error handler gets called. This renders V8
2829// unusable and therefore this test cannot be run in parallel.
2830TEST(ErrorReporting) {
2831 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
2832 static const char* aDeps[] = { "B" };
2833 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
2834 static const char* bDeps[] = { "A" };
2835 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
2836 last_location = NULL;
2837 v8::ExtensionConfiguration config(1, bDeps);
2838 v8::Handle<Context> context = Context::New(&config);
2839 CHECK(context.IsEmpty());
2840 CHECK_NE(last_location, NULL);
2841}
2842
2843
ager@chromium.org7c537e22008-10-16 08:43:32 +00002844static const char* js_code_causing_huge_string_flattening =
2845 "var str = 'X';"
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002846 "for (var i = 0; i < 30; i++) {"
ager@chromium.org7c537e22008-10-16 08:43:32 +00002847 " str = str + str;"
2848 "}"
2849 "str.match(/X/);";
2850
2851
2852void OOMCallback(const char* location, const char* message) {
2853 exit(0);
2854}
2855
2856
2857TEST(RegexpOutOfMemory) {
2858 // Execute a script that causes out of memory when flattening a string.
2859 v8::HandleScope scope;
2860 v8::V8::SetFatalErrorHandler(OOMCallback);
2861 LocalContext context;
2862 Local<Script> script =
2863 Script::Compile(String::New(js_code_causing_huge_string_flattening));
2864 last_location = NULL;
2865 Local<Value> result = script->Run();
2866
2867 CHECK(false); // Should not return.
2868}
2869
2870
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002871static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
2872 v8::Handle<Value> data) {
2873 CHECK_EQ(v8::Undefined(), data);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002874 CHECK(message->GetScriptResourceName()->IsUndefined());
2875 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002876 message->GetLineNumber();
2877 message->GetSourceLine();
2878}
2879
2880
2881THREADED_TEST(ErrorWithMissingScriptInfo) {
2882 v8::HandleScope scope;
2883 LocalContext context;
2884 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
2885 Script::Compile(v8_str("throw Error()"))->Run();
2886 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
2887}
2888
2889
2890int global_index = 0;
2891
2892class Snorkel {
2893 public:
2894 Snorkel() { index_ = global_index++; }
2895 int index_;
2896};
2897
2898class Whammy {
2899 public:
2900 Whammy() {
2901 cursor_ = 0;
2902 }
2903 ~Whammy() {
2904 script_.Dispose();
2905 }
2906 v8::Handle<Script> getScript() {
2907 if (script_.IsEmpty())
2908 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
2909 return Local<Script>(*script_);
2910 }
2911
2912 public:
2913 static const int kObjectCount = 256;
2914 int cursor_;
2915 v8::Persistent<v8::Object> objects_[kObjectCount];
2916 v8::Persistent<Script> script_;
2917};
2918
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002919static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002920 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
2921 delete snorkel;
2922 obj.ClearWeak();
2923}
2924
2925v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
2926 const AccessorInfo& info) {
2927 Whammy* whammy =
2928 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
2929
2930 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
2931
2932 v8::Handle<v8::Object> obj = v8::Object::New();
2933 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
2934 if (!prev.IsEmpty()) {
2935 prev->Set(v8_str("next"), obj);
2936 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
2937 whammy->objects_[whammy->cursor_].Clear();
2938 }
2939 whammy->objects_[whammy->cursor_] = global;
2940 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
2941 return whammy->getScript()->Run();
2942}
2943
2944THREADED_TEST(WeakReference) {
2945 v8::HandleScope handle_scope;
2946 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
2947 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
2948 0, 0, 0, 0,
2949 v8::External::New(new Whammy()));
2950 const char* extension_list[] = { "v8/gc" };
2951 v8::ExtensionConfiguration extensions(1, extension_list);
2952 v8::Persistent<Context> context = Context::New(&extensions);
2953 Context::Scope context_scope(context);
2954
2955 v8::Handle<v8::Object> interceptor = templ->NewInstance();
2956 context->Global()->Set(v8_str("whammy"), interceptor);
2957 const char* code =
2958 "var last;"
2959 "for (var i = 0; i < 10000; i++) {"
2960 " var obj = whammy.length;"
2961 " if (last) last.next = obj;"
2962 " last = obj;"
2963 "}"
2964 "gc();"
2965 "4";
2966 v8::Handle<Value> result = CompileRun(code);
2967 CHECK_EQ(4.0, result->NumberValue());
2968
2969 context.Dispose();
2970}
2971
2972
2973v8::Handle<Function> args_fun;
2974
2975
2976static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
2977 ApiTestFuzzer::Fuzz();
2978 CHECK_EQ(args_fun, args.Callee());
2979 CHECK_EQ(3, args.Length());
2980 CHECK_EQ(v8::Integer::New(1), args[0]);
2981 CHECK_EQ(v8::Integer::New(2), args[1]);
2982 CHECK_EQ(v8::Integer::New(3), args[2]);
2983 CHECK_EQ(v8::Undefined(), args[3]);
2984 v8::HandleScope scope;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00002985 i::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002986 return v8::Undefined();
2987}
2988
2989
2990THREADED_TEST(Arguments) {
2991 v8::HandleScope scope;
2992 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2993 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
2994 LocalContext context(NULL, global);
2995 args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
2996 v8_compile("f(1, 2, 3)")->Run();
2997}
2998
2999
3000static int x_register = 0;
3001static v8::Handle<v8::Object> x_receiver;
3002static v8::Handle<v8::Object> x_holder;
3003
3004
3005static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
3006 ApiTestFuzzer::Fuzz();
3007 CHECK_EQ(x_receiver, info.This());
3008 CHECK_EQ(x_holder, info.Holder());
3009 return v8_num(x_register);
3010}
3011
3012
3013static void XSetter(Local<String> name,
3014 Local<Value> value,
3015 const AccessorInfo& info) {
3016 CHECK_EQ(x_holder, info.This());
3017 CHECK_EQ(x_holder, info.Holder());
3018 x_register = value->Int32Value();
3019}
3020
3021
3022THREADED_TEST(AccessorIC) {
3023 v8::HandleScope scope;
3024 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3025 obj->SetAccessor(v8_str("x"), XGetter, XSetter);
3026 LocalContext context;
3027 x_holder = obj->NewInstance();
3028 context->Global()->Set(v8_str("holder"), x_holder);
3029 x_receiver = v8::Object::New();
3030 context->Global()->Set(v8_str("obj"), x_receiver);
3031 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
3032 "obj.__proto__ = holder;"
3033 "var result = [];"
3034 "for (var i = 0; i < 10; i++) {"
3035 " holder.x = i;"
3036 " result.push(obj.x);"
3037 "}"
3038 "result"));
3039 CHECK_EQ(10, array->Length());
3040 for (int i = 0; i < 10; i++) {
3041 v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
3042 CHECK_EQ(v8::Integer::New(i), entry);
3043 }
3044}
3045
3046
3047static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3048 const AccessorInfo&) {
3049 return v8::Handle<Value>();
3050}
3051
3052
3053static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3054 const AccessorInfo&) {
3055 return v8::Handle<Value>();
3056}
3057
3058
3059static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3060 const AccessorInfo&) {
3061 if (!name->Equals(v8_str("foo"))) {
3062 return v8::Handle<v8::Boolean>(); // not intercepted
3063 }
3064
3065 return v8::False(); // intercepted, and don't delete the property
3066}
3067
3068
3069static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3070 if (index != 2) {
3071 return v8::Handle<v8::Boolean>(); // not intercepted
3072 }
3073
3074 return v8::False(); // intercepted, and don't delete the property
3075}
3076
3077
3078THREADED_TEST(Deleter) {
3079 v8::HandleScope scope;
3080 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3081 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3082 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3083 LocalContext context;
3084 context->Global()->Set(v8_str("k"), obj->NewInstance());
3085 CompileRun(
3086 "k.foo = 'foo';"
3087 "k.bar = 'bar';"
3088 "k[2] = 2;"
3089 "k[4] = 4;");
3090 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3091 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3092
3093 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3094 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3095
3096 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3097 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3098
3099 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3100 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3101}
3102
3103
3104static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3105 ApiTestFuzzer::Fuzz();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003106 if (name->Equals(v8_str("foo")) ||
3107 name->Equals(v8_str("bar")) ||
3108 name->Equals(v8_str("baz"))) {
3109 return v8::Undefined();
3110 }
3111 return v8::Handle<Value>();
3112}
3113
3114
3115static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3116 ApiTestFuzzer::Fuzz();
3117 if (index == 0 || index == 1) return v8::Undefined();
3118 return v8::Handle<Value>();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003119}
3120
3121
3122static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3123 ApiTestFuzzer::Fuzz();
3124 v8::Handle<v8::Array> result = v8::Array::New(3);
3125 result->Set(v8::Integer::New(0), v8_str("foo"));
3126 result->Set(v8::Integer::New(1), v8_str("bar"));
3127 result->Set(v8::Integer::New(2), v8_str("baz"));
3128 return result;
3129}
3130
3131
3132static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3133 ApiTestFuzzer::Fuzz();
3134 v8::Handle<v8::Array> result = v8::Array::New(2);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003135 result->Set(v8::Integer::New(0), v8_str("0"));
3136 result->Set(v8::Integer::New(1), v8_str("1"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003137 return result;
3138}
3139
3140
3141THREADED_TEST(Enumerators) {
3142 v8::HandleScope scope;
3143 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3144 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003145 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003146 LocalContext context;
3147 context->Global()->Set(v8_str("k"), obj->NewInstance());
3148 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003149 "k[10] = 0;"
3150 "k.a = 0;"
3151 "k[5] = 0;"
3152 "k.b = 0;"
3153 "k[4294967295] = 0;"
3154 "k.c = 0;"
3155 "k[4294967296] = 0;"
3156 "k.d = 0;"
3157 "k[140000] = 0;"
3158 "k.e = 0;"
3159 "k[30000000000] = 0;"
3160 "k.f = 0;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003161 "var result = [];"
3162 "for (var prop in k) {"
3163 " result.push(prop);"
3164 "}"
3165 "result"));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003166 // Check that we get all the property names returned including the
3167 // ones from the enumerators in the right order: indexed properties
3168 // in numerical order, indexed interceptor properties, named
3169 // properties in insertion order, named interceptor properties.
3170 // This order is not mandated by the spec, so this test is just
3171 // documenting our behavior.
3172 CHECK_EQ(17, result->Length());
3173 // Indexed properties in numerical order.
3174 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3175 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3176 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3177 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3178 // Indexed interceptor properties in the order they are returned
3179 // from the enumerator interceptor.
3180 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3181 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3182 // Named properties in insertion order.
3183 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3184 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3185 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3186 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3187 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3188 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3189 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3190 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3191 // Named interceptor properties.
3192 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3193 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3194 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003195}
3196
3197
3198int p_getter_count;
3199int p_getter_count2;
3200
3201
3202static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3203 ApiTestFuzzer::Fuzz();
3204 p_getter_count++;
3205 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3206 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3207 if (name->Equals(v8_str("p1"))) {
3208 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3209 } else if (name->Equals(v8_str("p2"))) {
3210 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3211 } else if (name->Equals(v8_str("p3"))) {
3212 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3213 } else if (name->Equals(v8_str("p4"))) {
3214 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3215 }
3216 return v8::Undefined();
3217}
3218
3219
3220static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3221 ApiTestFuzzer::Fuzz();
3222 LocalContext context;
3223 context->Global()->Set(v8_str("o1"), obj->NewInstance());
3224 CompileRun(
3225 "o1.__proto__ = { };"
3226 "var o2 = { __proto__: o1 };"
3227 "var o3 = { __proto__: o2 };"
3228 "var o4 = { __proto__: o3 };"
3229 "for (var i = 0; i < 10; i++) o4.p4;"
3230 "for (var i = 0; i < 10; i++) o3.p3;"
3231 "for (var i = 0; i < 10; i++) o2.p2;"
3232 "for (var i = 0; i < 10; i++) o1.p1;");
3233}
3234
3235
3236static v8::Handle<Value> PGetter2(Local<String> name,
3237 const AccessorInfo& info) {
3238 ApiTestFuzzer::Fuzz();
3239 p_getter_count2++;
3240 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3241 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3242 if (name->Equals(v8_str("p1"))) {
3243 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3244 } else if (name->Equals(v8_str("p2"))) {
3245 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3246 } else if (name->Equals(v8_str("p3"))) {
3247 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3248 } else if (name->Equals(v8_str("p4"))) {
3249 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3250 }
3251 return v8::Undefined();
3252}
3253
3254
3255THREADED_TEST(GetterHolders) {
3256 v8::HandleScope scope;
3257 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3258 obj->SetAccessor(v8_str("p1"), PGetter);
3259 obj->SetAccessor(v8_str("p2"), PGetter);
3260 obj->SetAccessor(v8_str("p3"), PGetter);
3261 obj->SetAccessor(v8_str("p4"), PGetter);
3262 p_getter_count = 0;
3263 RunHolderTest(obj);
3264 CHECK_EQ(40, p_getter_count);
3265}
3266
3267
3268THREADED_TEST(PreInterceptorHolders) {
3269 v8::HandleScope scope;
3270 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3271 obj->SetNamedPropertyHandler(PGetter2);
3272 p_getter_count2 = 0;
3273 RunHolderTest(obj);
3274 CHECK_EQ(40, p_getter_count2);
3275}
3276
3277
3278THREADED_TEST(ObjectInstantiation) {
3279 v8::HandleScope scope;
3280 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3281 templ->SetAccessor(v8_str("t"), PGetter2);
3282 LocalContext context;
3283 context->Global()->Set(v8_str("o"), templ->NewInstance());
3284 for (int i = 0; i < 100; i++) {
3285 v8::HandleScope inner_scope;
3286 v8::Handle<v8::Object> obj = templ->NewInstance();
3287 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3288 context->Global()->Set(v8_str("o2"), obj);
3289 v8::Handle<Value> value =
3290 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3291 CHECK_EQ(v8::True(), value);
3292 context->Global()->Set(v8_str("o"), obj);
3293 }
3294}
3295
3296
3297THREADED_TEST(StringWrite) {
3298 v8::HandleScope scope;
3299 v8::Handle<String> str = v8_str("abcde");
3300
3301 char buf[100];
3302 int len;
3303
3304 memset(buf, 0x1, sizeof(buf));
3305 len = str->WriteAscii(buf);
3306 CHECK_EQ(len, 5);
3307 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3308
3309 memset(buf, 0x1, sizeof(buf));
3310 len = str->WriteAscii(buf, 0, 4);
3311 CHECK_EQ(len, 4);
3312 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3313
3314 memset(buf, 0x1, sizeof(buf));
3315 len = str->WriteAscii(buf, 0, 5);
3316 CHECK_EQ(len, 5);
3317 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3318
3319 memset(buf, 0x1, sizeof(buf));
3320 len = str->WriteAscii(buf, 0, 6);
3321 CHECK_EQ(len, 5);
3322 CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3323
3324 memset(buf, 0x1, sizeof(buf));
3325 len = str->WriteAscii(buf, 4, -1);
3326 CHECK_EQ(len, 1);
3327 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3328
3329 memset(buf, 0x1, sizeof(buf));
3330 len = str->WriteAscii(buf, 4, 6);
3331 CHECK_EQ(len, 1);
3332 CHECK_EQ(strncmp("e\0", buf, 2), 0);
3333
3334 memset(buf, 0x1, sizeof(buf));
3335 len = str->WriteAscii(buf, 4, 1);
3336 CHECK_EQ(len, 1);
3337 CHECK_EQ(strncmp("e\1", buf, 2), 0);
3338}
3339
3340
3341THREADED_TEST(ToArrayIndex) {
3342 v8::HandleScope scope;
3343 LocalContext context;
3344
3345 v8::Handle<String> str = v8_str("42");
3346 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3347 CHECK(!index.IsEmpty());
3348 CHECK_EQ(42.0, index->Uint32Value());
3349 str = v8_str("42asdf");
3350 index = str->ToArrayIndex();
3351 CHECK(index.IsEmpty());
3352 str = v8_str("-42");
3353 index = str->ToArrayIndex();
3354 CHECK(index.IsEmpty());
3355 str = v8_str("4294967295");
3356 index = str->ToArrayIndex();
3357 CHECK(!index.IsEmpty());
3358 CHECK_EQ(4294967295.0, index->Uint32Value());
3359 v8::Handle<v8::Number> num = v8::Number::New(1);
3360 index = num->ToArrayIndex();
3361 CHECK(!index.IsEmpty());
3362 CHECK_EQ(1.0, index->Uint32Value());
3363 num = v8::Number::New(-1);
3364 index = num->ToArrayIndex();
3365 CHECK(index.IsEmpty());
3366 v8::Handle<v8::Object> obj = v8::Object::New();
3367 index = obj->ToArrayIndex();
3368 CHECK(index.IsEmpty());
3369}
3370
3371
3372THREADED_TEST(ErrorConstruction) {
3373 v8::HandleScope scope;
3374 LocalContext context;
3375
3376 v8::Handle<String> foo = v8_str("foo");
3377 v8::Handle<String> message = v8_str("message");
3378 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3379 CHECK(range_error->IsObject());
3380 v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
3381 CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
3382 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3383 CHECK(reference_error->IsObject());
3384 CHECK(
3385 v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
3386 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
3387 CHECK(syntax_error->IsObject());
3388 CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
3389 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
3390 CHECK(type_error->IsObject());
3391 CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
3392 v8::Handle<Value> error = v8::Exception::Error(foo);
3393 CHECK(error->IsObject());
3394 CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
3395}
3396
3397
3398static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
3399 ApiTestFuzzer::Fuzz();
3400 return v8_num(10);
3401}
3402
3403
3404static void YSetter(Local<String> name,
3405 Local<Value> value,
3406 const AccessorInfo& info) {
3407 if (info.This()->Has(name)) {
3408 info.This()->Delete(name);
3409 }
3410 info.This()->Set(name, value);
3411}
3412
3413
3414THREADED_TEST(DeleteAccessor) {
3415 v8::HandleScope scope;
3416 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3417 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
3418 LocalContext context;
3419 v8::Handle<v8::Object> holder = obj->NewInstance();
3420 context->Global()->Set(v8_str("holder"), holder);
3421 v8::Handle<Value> result = CompileRun(
3422 "holder.y = 11; holder.y = 12; holder.y");
3423 CHECK_EQ(12, result->Uint32Value());
3424}
3425
3426
3427THREADED_TEST(TypeSwitch) {
3428 v8::HandleScope scope;
3429 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
3430 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
3431 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
3432 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
3433 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
3434 LocalContext context;
3435 v8::Handle<v8::Object> obj0 = v8::Object::New();
3436 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
3437 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
3438 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
3439 for (int i = 0; i < 10; i++) {
3440 CHECK_EQ(0, type_switch->match(obj0));
3441 CHECK_EQ(1, type_switch->match(obj1));
3442 CHECK_EQ(2, type_switch->match(obj2));
3443 CHECK_EQ(3, type_switch->match(obj3));
3444 CHECK_EQ(3, type_switch->match(obj3));
3445 CHECK_EQ(2, type_switch->match(obj2));
3446 CHECK_EQ(1, type_switch->match(obj1));
3447 CHECK_EQ(0, type_switch->match(obj0));
3448 }
3449}
3450
3451
3452// For use within the TestSecurityHandler() test.
3453static bool g_security_callback_result = false;
3454static bool NamedSecurityTestCallback(Local<v8::Object> global,
3455 Local<Value> name,
3456 v8::AccessType type,
3457 Local<Value> data) {
3458 // Always allow read access.
3459 if (type == v8::ACCESS_GET)
3460 return true;
3461
3462 // Sometimes allow other access.
3463 return g_security_callback_result;
3464}
3465
3466
3467static bool IndexedSecurityTestCallback(Local<v8::Object> global,
3468 uint32_t key,
3469 v8::AccessType type,
3470 Local<Value> data) {
3471 // Always allow read access.
3472 if (type == v8::ACCESS_GET)
3473 return true;
3474
3475 // Sometimes allow other access.
3476 return g_security_callback_result;
3477}
3478
3479
3480static int trouble_nesting = 0;
3481static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
3482 ApiTestFuzzer::Fuzz();
3483 trouble_nesting++;
3484
3485 // Call a JS function that throws an uncaught exception.
3486 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
3487 Local<Value> trouble_callee = (trouble_nesting == 3) ?
3488 arg_this->Get(v8_str("trouble_callee")) :
3489 arg_this->Get(v8_str("trouble_caller"));
3490 CHECK(trouble_callee->IsFunction());
3491 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
3492}
3493
3494
3495static int report_count = 0;
3496static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
3497 v8::Handle<Value>) {
3498 report_count++;
3499}
3500
3501
3502// Counts uncaught exceptions, but other tests running in parallel
3503// also have uncaught exceptions.
3504TEST(ApiUncaughtException) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00003505 report_count = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003506 v8::HandleScope scope;
3507 LocalContext env;
3508 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
3509
3510 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
3511 v8::Local<v8::Object> global = env->Global();
3512 global->Set(v8_str("trouble"), fun->GetFunction());
3513
3514 Script::Compile(v8_str("function trouble_callee() {"
3515 " var x = null;"
3516 " return x.foo;"
3517 "};"
3518 "function trouble_caller() {"
3519 " trouble();"
3520 "};"))->Run();
3521 Local<Value> trouble = global->Get(v8_str("trouble"));
3522 CHECK(trouble->IsFunction());
3523 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
3524 CHECK(trouble_callee->IsFunction());
3525 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
3526 CHECK(trouble_caller->IsFunction());
3527 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
3528 CHECK_EQ(1, report_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003529 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
3530}
3531
3532
3533TEST(CompilationErrorUsingTryCatchHandler) {
3534 v8::HandleScope scope;
3535 LocalContext env;
3536 v8::TryCatch try_catch;
3537 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
3538 CHECK_NE(NULL, *try_catch.Exception());
3539 CHECK(try_catch.HasCaught());
3540}
3541
3542
3543TEST(TryCatchFinallyUsingTryCatchHandler) {
3544 v8::HandleScope scope;
3545 LocalContext env;
3546 v8::TryCatch try_catch;
3547 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
3548 CHECK(!try_catch.HasCaught());
3549 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
3550 CHECK(try_catch.HasCaught());
3551 try_catch.Reset();
3552 Script::Compile(v8_str("(function() {"
3553 "try { throw ''; } finally { return; }"
3554 "})()"))->Run();
3555 CHECK(!try_catch.HasCaught());
3556 Script::Compile(v8_str("(function()"
3557 " { try { throw ''; } finally { throw 0; }"
3558 "})()"))->Run();
3559 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003560}
3561
3562
3563// SecurityHandler can't be run twice
3564TEST(SecurityHandler) {
3565 v8::HandleScope scope0;
3566 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3567 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
3568 IndexedSecurityTestCallback);
3569 // Create an environment
3570 v8::Persistent<Context> context0 =
3571 Context::New(NULL, global_template);
3572 context0->Enter();
3573
3574 v8::Handle<v8::Object> global0 = context0->Global();
3575 v8::Handle<Script> script0 = v8_compile("foo = 111");
3576 script0->Run();
3577 global0->Set(v8_str("0"), v8_num(999));
3578 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
3579 CHECK_EQ(111, foo0->Int32Value());
3580 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
3581 CHECK_EQ(999, z0->Int32Value());
3582
3583 // Create another environment, should fail security checks.
3584 v8::HandleScope scope1;
3585
3586 v8::Persistent<Context> context1 =
3587 Context::New(NULL, global_template);
3588 context1->Enter();
3589
3590 v8::Handle<v8::Object> global1 = context1->Global();
3591 global1->Set(v8_str("othercontext"), global0);
3592 // This set will fail the security check.
3593 v8::Handle<Script> script1 =
3594 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
3595 script1->Run();
3596 // This read will pass the security check.
3597 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
3598 CHECK_EQ(111, foo1->Int32Value());
3599 // This read will pass the security check.
3600 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
3601 CHECK_EQ(999, z1->Int32Value());
3602
3603 // Create another environment, should pass security checks.
3604 { g_security_callback_result = true; // allow security handler to pass.
3605 v8::HandleScope scope2;
3606 LocalContext context2;
3607 v8::Handle<v8::Object> global2 = context2->Global();
3608 global2->Set(v8_str("othercontext"), global0);
3609 v8::Handle<Script> script2 =
3610 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3611 script2->Run();
3612 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3613 CHECK_EQ(333, foo2->Int32Value());
3614 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3615 CHECK_EQ(888, z2->Int32Value());
3616 }
3617
3618 context1->Exit();
3619 context1.Dispose();
3620
3621 context0->Exit();
3622 context0.Dispose();
3623}
3624
3625
3626THREADED_TEST(SecurityChecks) {
3627 v8::HandleScope handle_scope;
3628 LocalContext env1;
3629 v8::Persistent<Context> env2 = Context::New();
3630
3631 Local<Value> foo = v8_str("foo");
3632 Local<Value> bar = v8_str("bar");
3633
3634 // Set to the same domain.
3635 env1->SetSecurityToken(foo);
3636
3637 // Create a function in env1.
3638 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3639 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3640 CHECK(spy->IsFunction());
3641
3642 // Create another function accessing global objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003643 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003644 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3645 CHECK(spy2->IsFunction());
3646
3647 // Switch to env2 in the same domain and invoke spy on env2.
3648 {
3649 env2->SetSecurityToken(foo);
3650 // Enter env2
3651 Context::Scope scope_env2(env2);
3652 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3653 CHECK(result->IsFunction());
3654 }
3655
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003656 {
3657 env2->SetSecurityToken(bar);
3658 Context::Scope scope_env2(env2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003659
3660 // Call cross_domain_call, it should throw an exception
3661 v8::TryCatch try_catch;
3662 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3663 CHECK(try_catch.HasCaught());
3664 }
3665
3666 env2.Dispose();
3667}
3668
3669
3670// Regression test case for issue 1183439.
3671THREADED_TEST(SecurityChecksForPrototypeChain) {
3672 v8::HandleScope scope;
3673 LocalContext current;
3674 v8::Persistent<Context> other = Context::New();
3675
3676 // Change context to be able to get to the Object function in the
3677 // other context without hitting the security checks.
3678 v8::Local<Value> other_object;
3679 { Context::Scope scope(other);
3680 other_object = other->Global()->Get(v8_str("Object"));
3681 other->Global()->Set(v8_num(42), v8_num(87));
3682 }
3683
3684 current->Global()->Set(v8_str("other"), other->Global());
3685 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3686
3687 // Make sure the security check fails here and we get an undefined
3688 // result instead of getting the Object function. Repeat in a loop
3689 // to make sure to exercise the IC code.
3690 v8::Local<Script> access_other0 = v8_compile("other.Object");
3691 v8::Local<Script> access_other1 = v8_compile("other[42]");
3692 for (int i = 0; i < 5; i++) {
3693 CHECK(!access_other0->Run()->Equals(other_object));
3694 CHECK(access_other0->Run()->IsUndefined());
3695 CHECK(!access_other1->Run()->Equals(v8_num(87)));
3696 CHECK(access_other1->Run()->IsUndefined());
3697 }
3698
3699 // Create an object that has 'other' in its prototype chain and make
3700 // sure we cannot access the Object function indirectly through
3701 // that. Repeat in a loop to make sure to exercise the IC code.
3702 v8_compile("function F() { };"
3703 "F.prototype = other;"
3704 "var f = new F();")->Run();
3705 v8::Local<Script> access_f0 = v8_compile("f.Object");
3706 v8::Local<Script> access_f1 = v8_compile("f[42]");
3707 for (int j = 0; j < 5; j++) {
3708 CHECK(!access_f0->Run()->Equals(other_object));
3709 CHECK(access_f0->Run()->IsUndefined());
3710 CHECK(!access_f1->Run()->Equals(v8_num(87)));
3711 CHECK(access_f1->Run()->IsUndefined());
3712 }
3713
3714 // Now it gets hairy: Set the prototype for the other global object
3715 // to be the current global object. The prototype chain for 'f' now
3716 // goes through 'other' but ends up in the current global object.
3717 { Context::Scope scope(other);
3718 other->Global()->Set(v8_str("__proto__"), current->Global());
3719 }
3720 // Set a named and an index property on the current global
3721 // object. To force the lookup to go through the other global object,
3722 // the properties must not exist in the other global object.
3723 current->Global()->Set(v8_str("foo"), v8_num(100));
3724 current->Global()->Set(v8_num(99), v8_num(101));
3725 // Try to read the properties from f and make sure that the access
3726 // gets stopped by the security checks on the other global object.
3727 Local<Script> access_f2 = v8_compile("f.foo");
3728 Local<Script> access_f3 = v8_compile("f[99]");
3729 for (int k = 0; k < 5; k++) {
3730 CHECK(!access_f2->Run()->Equals(v8_num(100)));
3731 CHECK(access_f2->Run()->IsUndefined());
3732 CHECK(!access_f3->Run()->Equals(v8_num(101)));
3733 CHECK(access_f3->Run()->IsUndefined());
3734 }
3735 other.Dispose();
3736}
3737
3738
3739THREADED_TEST(CrossDomainDelete) {
3740 v8::HandleScope handle_scope;
3741 LocalContext env1;
3742 v8::Persistent<Context> env2 = Context::New();
3743
3744 Local<Value> foo = v8_str("foo");
3745 Local<Value> bar = v8_str("bar");
3746
3747 // Set to the same domain.
3748 env1->SetSecurityToken(foo);
3749 env2->SetSecurityToken(foo);
3750
3751 env1->Global()->Set(v8_str("prop"), v8_num(3));
3752 env2->Global()->Set(v8_str("env1"), env1->Global());
3753
3754 // Change env2 to a different domain and delete env1.prop.
3755 env2->SetSecurityToken(bar);
3756 {
3757 Context::Scope scope_env2(env2);
3758 Local<Value> result =
3759 Script::Compile(v8_str("delete env1.prop"))->Run();
3760 CHECK(result->IsFalse());
3761 }
3762
3763 // Check that env1.prop still exists.
3764 Local<Value> v = env1->Global()->Get(v8_str("prop"));
3765 CHECK(v->IsNumber());
3766 CHECK_EQ(3, v->Int32Value());
3767
3768 env2.Dispose();
3769}
3770
3771
ager@chromium.org870a0b62008-11-04 11:43:05 +00003772THREADED_TEST(CrossDomainIsPropertyEnumerable) {
3773 v8::HandleScope handle_scope;
3774 LocalContext env1;
3775 v8::Persistent<Context> env2 = Context::New();
3776
3777 Local<Value> foo = v8_str("foo");
3778 Local<Value> bar = v8_str("bar");
3779
3780 // Set to the same domain.
3781 env1->SetSecurityToken(foo);
3782 env2->SetSecurityToken(foo);
3783
3784 env1->Global()->Set(v8_str("prop"), v8_num(3));
3785 env2->Global()->Set(v8_str("env1"), env1->Global());
3786
3787 // env1.prop is enumerable in env2.
3788 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
3789 {
3790 Context::Scope scope_env2(env2);
3791 Local<Value> result = Script::Compile(test)->Run();
3792 CHECK(result->IsTrue());
3793 }
3794
3795 // Change env2 to a different domain and test again.
3796 env2->SetSecurityToken(bar);
3797 {
3798 Context::Scope scope_env2(env2);
3799 Local<Value> result = Script::Compile(test)->Run();
3800 CHECK(result->IsFalse());
3801 }
3802
3803 env2.Dispose();
3804}
3805
3806
ager@chromium.org236ad962008-09-25 09:45:57 +00003807THREADED_TEST(CrossDomainForIn) {
3808 v8::HandleScope handle_scope;
3809 LocalContext env1;
3810 v8::Persistent<Context> env2 = Context::New();
3811
3812 Local<Value> foo = v8_str("foo");
3813 Local<Value> bar = v8_str("bar");
3814
3815 // Set to the same domain.
3816 env1->SetSecurityToken(foo);
3817 env2->SetSecurityToken(foo);
3818
3819 env1->Global()->Set(v8_str("prop"), v8_num(3));
3820 env2->Global()->Set(v8_str("env1"), env1->Global());
3821
3822 // Change env2 to a different domain and set env1's global object
3823 // as the __proto__ of an object in env2 and enumerate properties
3824 // in for-in. It shouldn't enumerate properties on env1's global
3825 // object.
3826 env2->SetSecurityToken(bar);
3827 {
3828 Context::Scope scope_env2(env2);
3829 Local<Value> result =
3830 CompileRun("(function(){var obj = {'__proto__':env1};"
3831 "for (var p in obj)"
3832 " if (p == 'prop') return false;"
3833 "return true;})()");
3834 CHECK(result->IsTrue());
3835 }
3836 env2.Dispose();
3837}
3838
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003839
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003840TEST(ContextDetachGlobal) {
3841 v8::HandleScope handle_scope;
3842 LocalContext env1;
3843 v8::Persistent<Context> env2 = Context::New();
3844
3845 Local<v8::Object> global1 = env1->Global();
3846
3847 Local<Value> foo = v8_str("foo");
3848
3849 // Set to the same domain.
3850 env1->SetSecurityToken(foo);
3851 env2->SetSecurityToken(foo);
3852
3853 // Enter env2
3854 env2->Enter();
3855
3856 // Create a function in env1
3857 Local<v8::Object> global2 = env2->Global();
3858 global2->Set(v8_str("prop"), v8::Integer::New(1));
3859 CompileRun("function getProp() {return prop;}");
3860
3861 env1->Global()->Set(v8_str("getProp"),
3862 global2->Get(v8_str("getProp")));
3863
3864 // Detach env1's global, and reuse the global object of env1
3865 env2->Exit();
3866 env2->DetachGlobal();
3867 // env2 has a new global object.
3868 CHECK(!env2->Global()->Equals(global2));
3869
3870 v8::Persistent<Context> env3 =
3871 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
3872 env3->SetSecurityToken(v8_str("bar"));
3873 env3->Enter();
3874
3875 Local<v8::Object> global3 = env3->Global();
3876 CHECK_EQ(global2, global3);
3877 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
3878 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
3879 global3->Set(v8_str("prop"), v8::Integer::New(-1));
3880 global3->Set(v8_str("prop2"), v8::Integer::New(2));
3881 env3->Exit();
3882
3883 // Call getProp in env1, and it should return the value 1
3884 {
3885 Local<Value> get_prop = global1->Get(v8_str("getProp"));
3886 CHECK(get_prop->IsFunction());
3887 v8::TryCatch try_catch;
3888 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
3889 CHECK(!try_catch.HasCaught());
3890 CHECK_EQ(1, r->Int32Value());
3891 }
3892
3893 // Check that env3 is not accessible from env1
3894 {
3895 Local<Value> r = global3->Get(v8_str("prop2"));
3896 CHECK(r->IsUndefined());
3897 }
3898
3899 env2.Dispose();
3900 env3.Dispose();
3901}
3902
3903
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003904static bool NamedAccessBlocker(Local<v8::Object> global,
3905 Local<Value> name,
3906 v8::AccessType type,
3907 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003908 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003909}
3910
3911
3912static bool IndexedAccessBlocker(Local<v8::Object> global,
3913 uint32_t key,
3914 v8::AccessType type,
3915 Local<Value> data) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003916 return Context::GetCurrent()->Global()->Equals(global);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003917}
3918
3919
3920static int g_echo_value = -1;
3921static v8::Handle<Value> EchoGetter(Local<String> name,
3922 const AccessorInfo& info) {
3923 return v8_num(g_echo_value);
3924}
3925
3926
3927static void EchoSetter(Local<String> name,
3928 Local<Value> value,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003929 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003930 if (value->IsNumber())
3931 g_echo_value = value->Int32Value();
3932}
3933
3934
3935static v8::Handle<Value> UnreachableGetter(Local<String> name,
3936 const AccessorInfo& info) {
3937 CHECK(false); // This function should not be called..
3938 return v8::Undefined();
3939}
3940
3941
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003942static void UnreachableSetter(Local<String>, Local<Value>,
3943 const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 CHECK(false); // This function should nto be called.
3945}
3946
3947
3948THREADED_TEST(AccessControl) {
3949 v8::HandleScope handle_scope;
3950 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3951
3952 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
3953 IndexedAccessBlocker);
3954
3955 // Add an accessor accessible by cross-domain JS code.
3956 global_template->SetAccessor(
3957 v8_str("accessible_prop"),
3958 EchoGetter, EchoSetter,
3959 v8::Handle<Value>(),
3960 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
3961
3962 // Add an accessor that is not accessible by cross-domain JS code.
ager@chromium.org870a0b62008-11-04 11:43:05 +00003963 global_template->SetAccessor(v8_str("blocked_prop"),
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003964 UnreachableGetter, UnreachableSetter,
3965 v8::Handle<Value>(),
3966 v8::DEFAULT);
3967
3968 // Create an environment
3969 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3970 context0->Enter();
3971
3972 v8::Handle<v8::Object> global0 = context0->Global();
3973
3974 v8::HandleScope scope1;
3975
3976 v8::Persistent<Context> context1 = Context::New();
3977 context1->Enter();
3978
3979 v8::Handle<v8::Object> global1 = context1->Global();
3980 global1->Set(v8_str("other"), global0);
3981
3982 v8::Handle<Value> value;
3983
3984 // Access blocked property
3985 value = v8_compile("other.blocked_prop = 1")->Run();
3986 value = v8_compile("other.blocked_prop")->Run();
3987 CHECK(value->IsUndefined());
3988
ager@chromium.org870a0b62008-11-04 11:43:05 +00003989 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
3990 CHECK(value->IsFalse());
3991
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003992 // Access accessible property
3993 value = v8_compile("other.accessible_prop = 3")->Run();
3994 CHECK(value->IsNumber());
3995 CHECK_EQ(3, value->Int32Value());
3996
3997 value = v8_compile("other.accessible_prop")->Run();
3998 CHECK(value->IsNumber());
3999 CHECK_EQ(3, value->Int32Value());
4000
ager@chromium.org870a0b62008-11-04 11:43:05 +00004001 value =
4002 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4003 CHECK(value->IsTrue());
4004
4005 // Enumeration doesn't enumerate accessors from inaccessible objects in
4006 // the prototype chain even if the accessors are in themselves accessible.
4007 Local<Value> result =
4008 CompileRun("(function(){var obj = {'__proto__':other};"
4009 "for (var p in obj)"
4010 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
4011 " return false;"
4012 " }"
4013 "return true;})()");
4014 CHECK(result->IsTrue());
4015
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004016 context1->Exit();
4017 context0->Exit();
4018 context1.Dispose();
4019 context0.Dispose();
4020}
4021
4022
4023static v8::Handle<Value> ConstTenGetter(Local<String> name,
4024 const AccessorInfo& info) {
4025 return v8_num(10);
4026}
4027
4028
4029THREADED_TEST(CrossDomainAccessors) {
4030 v8::HandleScope handle_scope;
4031
4032 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4033
4034 v8::Handle<v8::ObjectTemplate> global_template =
4035 func_template->InstanceTemplate();
4036
4037 v8::Handle<v8::ObjectTemplate> proto_template =
4038 func_template->PrototypeTemplate();
4039
4040 // Add an accessor to proto that's accessible by cross-domain JS code.
4041 proto_template->SetAccessor(v8_str("accessible"),
4042 ConstTenGetter, 0,
4043 v8::Handle<Value>(),
4044 v8::ALL_CAN_READ);
4045
4046 // Add an accessor that is not accessible by cross-domain JS code.
4047 global_template->SetAccessor(v8_str("unreachable"),
4048 UnreachableGetter, 0,
4049 v8::Handle<Value>(),
4050 v8::DEFAULT);
4051
4052 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4053 context0->Enter();
4054
4055 Local<v8::Object> global = context0->Global();
4056 // Add a normal property that shadows 'accessible'
4057 global->Set(v8_str("accessible"), v8_num(11));
4058
4059 // Enter a new context.
4060 v8::HandleScope scope1;
4061 v8::Persistent<Context> context1 = Context::New();
4062 context1->Enter();
4063
4064 v8::Handle<v8::Object> global1 = context1->Global();
4065 global1->Set(v8_str("other"), global);
4066
4067 // Should return 10, instead of 11
4068 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4069 CHECK(value->IsNumber());
4070 CHECK_EQ(10, value->Int32Value());
4071
4072 value = v8_compile("other.unreachable")->Run();
4073 CHECK(value->IsUndefined());
4074
4075 context1->Exit();
4076 context0->Exit();
4077 context1.Dispose();
4078 context0.Dispose();
4079}
4080
4081
4082static int named_access_count = 0;
4083static int indexed_access_count = 0;
4084
4085static bool NamedAccessCounter(Local<v8::Object> global,
4086 Local<Value> name,
4087 v8::AccessType type,
4088 Local<Value> data) {
4089 named_access_count++;
4090 return true;
4091}
4092
4093
4094static bool IndexedAccessCounter(Local<v8::Object> global,
4095 uint32_t key,
4096 v8::AccessType type,
4097 Local<Value> data) {
4098 indexed_access_count++;
4099 return true;
4100}
4101
4102
4103// This one is too easily disturbed by other tests.
4104TEST(AccessControlIC) {
4105 named_access_count = 0;
4106 indexed_access_count = 0;
4107
4108 v8::HandleScope handle_scope;
4109
4110 // Create an environment.
4111 v8::Persistent<Context> context0 = Context::New();
4112 context0->Enter();
4113
4114 // Create an object that requires access-check functions to be
4115 // called for cross-domain access.
4116 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4117 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4118 IndexedAccessCounter);
4119 Local<v8::Object> object = object_template->NewInstance();
4120
4121 v8::HandleScope scope1;
4122
4123 // Create another environment.
4124 v8::Persistent<Context> context1 = Context::New();
4125 context1->Enter();
4126
4127 // Make easy access to the object from the other environment.
4128 v8::Handle<v8::Object> global1 = context1->Global();
4129 global1->Set(v8_str("obj"), object);
4130
4131 v8::Handle<Value> value;
4132
4133 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004134 CompileRun("function testProp(obj) {"
4135 " for (var i = 0; i < 10; i++) obj.prop = 1;"
4136 " for (var j = 0; j < 10; j++) obj.prop;"
4137 " return obj.prop"
4138 "}");
4139 value = CompileRun("testProp(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004140 CHECK(value->IsNumber());
4141 CHECK_EQ(1, value->Int32Value());
4142 CHECK_EQ(21, named_access_count);
4143
4144 // Check that the named access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004145 CompileRun("var p = 'prop';"
4146 "function testKeyed(obj) {"
4147 " for (var i = 0; i < 10; i++) obj[p] = 1;"
4148 " for (var j = 0; j < 10; j++) obj[p];"
4149 " return obj[p];"
4150 "}");
4151 // Use obj which requires access checks. No inline caching is used
4152 // in that case.
4153 value = CompileRun("testKeyed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 CHECK(value->IsNumber());
4155 CHECK_EQ(1, value->Int32Value());
4156 CHECK_EQ(42, named_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004157 // Force the inline caches into generic state and try again.
4158 CompileRun("testKeyed({ a: 0 })");
4159 CompileRun("testKeyed({ b: 0 })");
4160 value = CompileRun("testKeyed(obj)");
4161 CHECK(value->IsNumber());
4162 CHECK_EQ(1, value->Int32Value());
4163 CHECK_EQ(63, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004164
4165 // Check that the indexed access-control function is called every time.
ager@chromium.org8bb60582008-12-11 12:02:20 +00004166 CompileRun("function testIndexed(obj) {"
4167 " for (var i = 0; i < 10; i++) obj[0] = 1;"
4168 " for (var j = 0; j < 10; j++) obj[0];"
4169 " return obj[0]"
4170 "}");
4171 value = CompileRun("testIndexed(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172 CHECK(value->IsNumber());
4173 CHECK_EQ(1, value->Int32Value());
4174 CHECK_EQ(21, indexed_access_count);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004175 // Force the inline caches into generic state.
4176 CompileRun("testIndexed(new Array(1))");
4177 // Test that the indexed access check is called.
4178 value = CompileRun("testIndexed(obj)");
4179 CHECK(value->IsNumber());
4180 CHECK_EQ(1, value->Int32Value());
4181 CHECK_EQ(42, indexed_access_count);
4182
4183 // Check that the named access check is called when invoking
4184 // functions on an object that requires access checks.
4185 CompileRun("obj.f = function() {}");
4186 CompileRun("function testCallNormal(obj) {"
4187 " for (var i = 0; i < 10; i++) obj.f();"
4188 "}");
4189 CompileRun("testCallNormal(obj)");
4190 CHECK_EQ(74, named_access_count);
4191
4192 // Force obj into slow case.
4193 value = CompileRun("delete obj.prop");
4194 CHECK(value->BooleanValue());
4195 // Force inline caches into dictionary probing mode.
4196 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4197 // Test that the named access check is called.
4198 value = CompileRun("testProp(obj);");
4199 CHECK(value->IsNumber());
4200 CHECK_EQ(1, value->Int32Value());
4201 CHECK_EQ(96, named_access_count);
4202
4203 // Force the call inline cache into dictionary probing mode.
4204 CompileRun("o.f = function() {}; testCallNormal(o)");
4205 // Test that the named access check is still called for each
4206 // invocation of the function.
4207 value = CompileRun("testCallNormal(obj)");
4208 CHECK_EQ(106, named_access_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209
4210 context1->Exit();
4211 context0->Exit();
4212 context1.Dispose();
4213 context0.Dispose();
4214}
4215
4216
4217static bool NamedAccessFlatten(Local<v8::Object> global,
4218 Local<Value> name,
4219 v8::AccessType type,
4220 Local<Value> data) {
4221 char buf[100];
4222 int len;
4223
4224 CHECK(name->IsString());
4225
4226 memset(buf, 0x1, sizeof(buf));
4227 len = Local<String>::Cast(name)->WriteAscii(buf);
4228 CHECK_EQ(4, len);
4229
4230 uint16_t buf2[100];
4231
4232 memset(buf, 0x1, sizeof(buf));
4233 len = Local<String>::Cast(name)->Write(buf2);
4234 CHECK_EQ(4, len);
4235
4236 return true;
4237}
4238
4239
4240static bool IndexedAccessFlatten(Local<v8::Object> global,
4241 uint32_t key,
4242 v8::AccessType type,
4243 Local<Value> data) {
4244 return true;
4245}
4246
4247
4248// Regression test. In access checks, operations that may cause
4249// garbage collection are not allowed. It used to be the case that
4250// using the Write operation on a string could cause a garbage
4251// collection due to flattening of the string. This is no longer the
4252// case.
4253THREADED_TEST(AccessControlFlatten) {
4254 named_access_count = 0;
4255 indexed_access_count = 0;
4256
4257 v8::HandleScope handle_scope;
4258
4259 // Create an environment.
4260 v8::Persistent<Context> context0 = Context::New();
4261 context0->Enter();
4262
4263 // Create an object that requires access-check functions to be
4264 // called for cross-domain access.
4265 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4266 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
4267 IndexedAccessFlatten);
4268 Local<v8::Object> object = object_template->NewInstance();
4269
4270 v8::HandleScope scope1;
4271
4272 // Create another environment.
4273 v8::Persistent<Context> context1 = Context::New();
4274 context1->Enter();
4275
4276 // Make easy access to the object from the other environment.
4277 v8::Handle<v8::Object> global1 = context1->Global();
4278 global1->Set(v8_str("obj"), object);
4279
4280 v8::Handle<Value> value;
4281
4282 value = v8_compile("var p = 'as' + 'df';")->Run();
4283 value = v8_compile("obj[p];")->Run();
4284
4285 context1->Exit();
4286 context0->Exit();
4287 context1.Dispose();
4288 context0.Dispose();
4289}
4290
4291
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004292static v8::Handle<Value> AccessControlNamedGetter(
4293 Local<String>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004294 return v8::Integer::New(42);
4295}
4296
4297
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004298static v8::Handle<Value> AccessControlNamedSetter(
4299 Local<String>, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004300 return value;
4301}
4302
4303
4304static v8::Handle<Value> AccessControlIndexedGetter(
4305 uint32_t index,
4306 const AccessorInfo& info) {
4307 return v8_num(42);
4308}
4309
4310
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004311static v8::Handle<Value> AccessControlIndexedSetter(
4312 uint32_t, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004313 return value;
4314}
4315
4316
4317THREADED_TEST(AccessControlInterceptorIC) {
4318 named_access_count = 0;
4319 indexed_access_count = 0;
4320
4321 v8::HandleScope handle_scope;
4322
4323 // Create an environment.
4324 v8::Persistent<Context> context0 = Context::New();
4325 context0->Enter();
4326
4327 // Create an object that requires access-check functions to be
4328 // called for cross-domain access. The object also has interceptors
4329 // interceptor.
4330 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4331 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4332 IndexedAccessCounter);
4333 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
4334 AccessControlNamedSetter);
4335 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
4336 AccessControlIndexedSetter);
4337 Local<v8::Object> object = object_template->NewInstance();
4338
4339 v8::HandleScope scope1;
4340
4341 // Create another environment.
4342 v8::Persistent<Context> context1 = Context::New();
4343 context1->Enter();
4344
4345 // Make easy access to the object from the other environment.
4346 v8::Handle<v8::Object> global1 = context1->Global();
4347 global1->Set(v8_str("obj"), object);
4348
4349 v8::Handle<Value> value;
4350
4351 // Check that the named access-control function is called every time
4352 // eventhough there is an interceptor on the object.
4353 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
4354 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
4355 "obj.x")->Run();
4356 CHECK(value->IsNumber());
4357 CHECK_EQ(42, value->Int32Value());
4358 CHECK_EQ(21, named_access_count);
4359
4360 value = v8_compile("var p = 'x';")->Run();
4361 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
4362 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
4363 "obj[p]")->Run();
4364 CHECK(value->IsNumber());
4365 CHECK_EQ(42, value->Int32Value());
4366 CHECK_EQ(42, named_access_count);
4367
4368 // Check that the indexed access-control function is called every
4369 // time eventhough there is an interceptor on the object.
4370 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
4371 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
4372 "obj[0]")->Run();
4373 CHECK(value->IsNumber());
4374 CHECK_EQ(42, value->Int32Value());
4375 CHECK_EQ(21, indexed_access_count);
4376
4377 context1->Exit();
4378 context0->Exit();
4379 context1.Dispose();
4380 context0.Dispose();
4381}
4382
4383
4384THREADED_TEST(Version) {
4385 v8::V8::GetVersion();
4386}
4387
4388
4389static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
4390 ApiTestFuzzer::Fuzz();
4391 return v8_num(12);
4392}
4393
4394
4395THREADED_TEST(InstanceProperties) {
4396 v8::HandleScope handle_scope;
4397 LocalContext context;
4398
4399 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4400 Local<ObjectTemplate> instance = t->InstanceTemplate();
4401
4402 instance->Set(v8_str("x"), v8_num(42));
4403 instance->Set(v8_str("f"),
4404 v8::FunctionTemplate::New(InstanceFunctionCallback));
4405
4406 Local<Value> o = t->GetFunction()->NewInstance();
4407
4408 context->Global()->Set(v8_str("i"), o);
4409 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
4410 CHECK_EQ(42, value->Int32Value());
4411
4412 value = Script::Compile(v8_str("i.f()"))->Run();
4413 CHECK_EQ(12, value->Int32Value());
4414}
4415
4416
4417static v8::Handle<Value>
4418GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
4419 ApiTestFuzzer::Fuzz();
4420 return v8::Handle<Value>();
4421}
4422
4423
4424THREADED_TEST(GlobalObjectInstanceProperties) {
4425 v8::HandleScope handle_scope;
4426
4427 Local<Value> global_object;
4428
4429 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4430 t->InstanceTemplate()->SetNamedPropertyHandler(
4431 GlobalObjectInstancePropertiesGet);
4432 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4433 instance_template->Set(v8_str("x"), v8_num(42));
4434 instance_template->Set(v8_str("f"),
4435 v8::FunctionTemplate::New(InstanceFunctionCallback));
4436
4437 {
4438 LocalContext env(NULL, instance_template);
4439 // Hold on to the global object so it can be used again in another
4440 // environment initialization.
4441 global_object = env->Global();
4442
4443 Local<Value> value = Script::Compile(v8_str("x"))->Run();
4444 CHECK_EQ(42, value->Int32Value());
4445 value = Script::Compile(v8_str("f()"))->Run();
4446 CHECK_EQ(12, value->Int32Value());
4447 }
4448
4449 {
4450 // Create new environment reusing the global object.
4451 LocalContext env(NULL, instance_template, global_object);
4452 Local<Value> value = Script::Compile(v8_str("x"))->Run();
4453 CHECK_EQ(42, value->Int32Value());
4454 value = Script::Compile(v8_str("f()"))->Run();
4455 CHECK_EQ(12, value->Int32Value());
4456 }
4457}
4458
4459
4460static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
4461 ApiTestFuzzer::Fuzz();
4462 return v8_num(42);
4463}
4464
4465
4466static int shadow_y;
4467static int shadow_y_setter_call_count;
4468static int shadow_y_getter_call_count;
4469
4470
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004471static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 shadow_y_setter_call_count++;
4473 shadow_y = 42;
4474}
4475
4476
4477static v8::Handle<Value> ShadowYGetter(Local<String> name,
4478 const AccessorInfo& info) {
4479 ApiTestFuzzer::Fuzz();
4480 shadow_y_getter_call_count++;
4481 return v8_num(shadow_y);
4482}
4483
4484
4485static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
4486 const AccessorInfo& info) {
4487 return v8::Handle<Value>();
4488}
4489
4490
4491static v8::Handle<Value> ShadowNamedGet(Local<String> key,
4492 const AccessorInfo&) {
4493 return v8::Handle<Value>();
4494}
4495
4496
4497THREADED_TEST(ShadowObject) {
4498 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
4499 v8::HandleScope handle_scope;
4500
4501 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
4502 LocalContext context(NULL, global_template);
4503
4504 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4505 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
4506 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
4507 Local<ObjectTemplate> proto = t->PrototypeTemplate();
4508 Local<ObjectTemplate> instance = t->InstanceTemplate();
4509
4510 // Only allow calls of f on instances of t.
4511 Local<v8::Signature> signature = v8::Signature::New(t);
4512 proto->Set(v8_str("f"),
4513 v8::FunctionTemplate::New(ShadowFunctionCallback,
4514 Local<Value>(),
4515 signature));
4516 proto->Set(v8_str("x"), v8_num(12));
4517
4518 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
4519
4520 Local<Value> o = t->GetFunction()->NewInstance();
4521 context->Global()->Set(v8_str("__proto__"), o);
4522
4523 Local<Value> value =
4524 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
4525 CHECK(value->IsBoolean());
4526 CHECK(!value->BooleanValue());
4527
4528 value = Script::Compile(v8_str("x"))->Run();
4529 CHECK_EQ(12, value->Int32Value());
4530
4531 value = Script::Compile(v8_str("f()"))->Run();
4532 CHECK_EQ(42, value->Int32Value());
4533
4534 Script::Compile(v8_str("y = 42"))->Run();
4535 CHECK_EQ(1, shadow_y_setter_call_count);
4536 value = Script::Compile(v8_str("y"))->Run();
4537 CHECK_EQ(1, shadow_y_getter_call_count);
4538 CHECK_EQ(42, value->Int32Value());
4539}
4540
4541
4542THREADED_TEST(HiddenPrototype) {
4543 v8::HandleScope handle_scope;
4544 LocalContext context;
4545
4546 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4547 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
4548 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4549 t1->SetHiddenPrototype(true);
4550 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
4551 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4552 t2->SetHiddenPrototype(true);
4553 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
4554 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4555 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
4556
4557 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
4558 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
4559 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
4560 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
4561
4562 // Setting the prototype on an object skips hidden prototypes.
4563 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4564 o0->Set(v8_str("__proto__"), o1);
4565 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4566 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4567 o0->Set(v8_str("__proto__"), o2);
4568 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4569 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4570 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4571 o0->Set(v8_str("__proto__"), o3);
4572 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4573 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4574 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4575 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
4576
4577 // Getting the prototype of o0 should get the first visible one
4578 // which is o3. Therefore, z should not be defined on the prototype
4579 // object.
4580 Local<Value> proto = o0->Get(v8_str("__proto__"));
4581 CHECK(proto->IsObject());
4582 CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
4583}
4584
4585
4586THREADED_TEST(GetterSetterExceptions) {
4587 v8::HandleScope handle_scope;
4588 LocalContext context;
4589 CompileRun(
4590 "function Foo() { };"
4591 "function Throw() { throw 5; };"
4592 "var x = { };"
4593 "x.__defineSetter__('set', Throw);"
4594 "x.__defineGetter__('get', Throw);");
4595 Local<v8::Object> x =
4596 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
4597 v8::TryCatch try_catch;
4598 x->Set(v8_str("set"), v8::Integer::New(8));
4599 x->Get(v8_str("get"));
4600 x->Set(v8_str("set"), v8::Integer::New(8));
4601 x->Get(v8_str("get"));
4602 x->Set(v8_str("set"), v8::Integer::New(8));
4603 x->Get(v8_str("get"));
4604 x->Set(v8_str("set"), v8::Integer::New(8));
4605 x->Get(v8_str("get"));
4606}
4607
4608
4609THREADED_TEST(Constructor) {
4610 v8::HandleScope handle_scope;
4611 LocalContext context;
4612 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4613 templ->SetClassName(v8_str("Fun"));
4614 Local<Function> cons = templ->GetFunction();
4615 context->Global()->Set(v8_str("Fun"), cons);
4616 Local<v8::Object> inst = cons->NewInstance();
4617 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
4618 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
4619 CHECK(value->BooleanValue());
4620}
4621
4622THREADED_TEST(FunctionDescriptorException) {
4623 v8::HandleScope handle_scope;
4624 LocalContext context;
4625 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4626 templ->SetClassName(v8_str("Fun"));
4627 Local<Function> cons = templ->GetFunction();
4628 context->Global()->Set(v8_str("Fun"), cons);
4629 Local<Value> value = CompileRun(
4630 "function test() {"
4631 " try {"
4632 " (new Fun()).blah()"
4633 " } catch (e) {"
4634 " var str = String(e);"
4635 " if (str.indexOf('TypeError') == -1) return 1;"
4636 " if (str.indexOf('[object Fun]') != -1) return 2;"
4637 " if (str.indexOf('#<a Fun>') == -1) return 3;"
4638 " return 0;"
4639 " }"
4640 " return 4;"
4641 "}"
4642 "test();");
4643 CHECK_EQ(0, value->Int32Value());
4644}
4645
4646
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004647THREADED_TEST(EvalAliasedDynamic) {
4648 v8::HandleScope scope;
4649 LocalContext current;
4650
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004651 // Tests where aliased eval can only be resolved dynamically.
4652 Local<Script> script =
4653 Script::Compile(v8_str("function f(x) { "
4654 " var foo = 2;"
4655 " with (x) { return eval('foo'); }"
4656 "}"
4657 "foo = 0;"
4658 "result1 = f(new Object());"
ager@chromium.orge2902be2009-06-08 12:21:35 +00004659 "result2 = f(this);"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004660 "var x = new Object();"
4661 "x.eval = function(x) { return 1; };"
4662 "result3 = f(x);"));
4663 script->Run();
4664 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
4665 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
4666 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
4667
4668 v8::TryCatch try_catch;
4669 script =
4670 Script::Compile(v8_str("function f(x) { "
4671 " var bar = 2;"
4672 " with (x) { return eval('bar'); }"
4673 "}"
ager@chromium.orge2902be2009-06-08 12:21:35 +00004674 "f(this)"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004675 script->Run();
4676 CHECK(try_catch.HasCaught());
4677 try_catch.Reset();
4678}
4679
4680
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004681THREADED_TEST(CrossEval) {
4682 v8::HandleScope scope;
4683 LocalContext other;
4684 LocalContext current;
4685
4686 Local<String> token = v8_str("<security token>");
4687 other->SetSecurityToken(token);
4688 current->SetSecurityToken(token);
4689
4690 // Setup reference from current to other.
4691 current->Global()->Set(v8_str("other"), other->Global());
4692
4693 // Check that new variables are introduced in other context.
4694 Local<Script> script =
4695 Script::Compile(v8_str("other.eval('var foo = 1234')"));
4696 script->Run();
4697 Local<Value> foo = other->Global()->Get(v8_str("foo"));
4698 CHECK_EQ(1234, foo->Int32Value());
4699 CHECK(!current->Global()->Has(v8_str("foo")));
4700
4701 // Check that writing to non-existing properties introduces them in
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004702 // the other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004703 script =
4704 Script::Compile(v8_str("other.eval('na = 1234')"));
4705 script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004706 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
4707 CHECK(!current->Global()->Has(v8_str("na")));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004708
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004709 // Check that global variables in current context are not visible in other
4710 // context.
4711 v8::TryCatch try_catch;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004712 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004713 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004714 Local<Value> result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004715 CHECK(try_catch.HasCaught());
4716 try_catch.Reset();
4717
4718 // Check that local variables in current context are not visible in other
4719 // context.
4720 script =
4721 Script::Compile(v8_str("(function() { "
4722 " var baz = 87;"
4723 " return other.eval('baz');"
4724 "})();"));
4725 result = script->Run();
4726 CHECK(try_catch.HasCaught());
4727 try_catch.Reset();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004728
4729 // Check that global variables in the other environment are visible
4730 // when evaluting code.
4731 other->Global()->Set(v8_str("bis"), v8_num(1234));
4732 script = Script::Compile(v8_str("other.eval('bis')"));
4733 CHECK_EQ(1234, script->Run()->Int32Value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004734 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004735
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004736 // Check that the 'this' pointer points to the global object evaluating
4737 // code.
4738 other->Global()->Set(v8_str("t"), other->Global());
4739 script = Script::Compile(v8_str("other.eval('this == t')"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004740 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004741 CHECK(result->IsTrue());
4742 CHECK(!try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004743
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004744 // Check that variables introduced in with-statement are not visible in
4745 // other context.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004746 script =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004747 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004748 result = script->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004749 CHECK(try_catch.HasCaught());
4750 try_catch.Reset();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004751
4752 // Check that you cannot use 'eval.call' with another object than the
4753 // current global object.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004754 script =
4755 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
4756 result = script->Run();
4757 CHECK(try_catch.HasCaught());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004758}
4759
4760
ager@chromium.orge2902be2009-06-08 12:21:35 +00004761// Test that calling eval in a context which has been detached from
4762// its global throws an exception. This behavior is consistent with
4763// other JavaScript implementations.
4764THREADED_TEST(EvalInDetachedGlobal) {
4765 v8::HandleScope scope;
4766
4767 v8::Persistent<Context> context0 = Context::New();
4768 v8::Persistent<Context> context1 = Context::New();
4769
4770 // Setup function in context0 that uses eval from context0.
4771 context0->Enter();
4772 v8::Handle<v8::Value> fun =
4773 CompileRun("var x = 42;"
4774 "(function() {"
4775 " var e = eval;"
4776 " return function(s) { return e(s); }"
4777 "})()");
4778 context0->Exit();
4779
4780 // Put the function into context1 and call it before and after
4781 // detaching the global. Before detaching, the call succeeds and
4782 // after detaching and exception is thrown.
4783 context1->Enter();
4784 context1->Global()->Set(v8_str("fun"), fun);
4785 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
4786 CHECK_EQ(42, x_value->Int32Value());
4787 context0->DetachGlobal();
4788 v8::TryCatch catcher;
4789 x_value = CompileRun("fun('x')");
4790 CHECK(x_value.IsEmpty());
4791 CHECK(catcher.HasCaught());
4792 context1->Exit();
4793
4794 context1.Dispose();
4795 context0.Dispose();
4796}
4797
4798
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004799THREADED_TEST(CrossLazyLoad) {
4800 v8::HandleScope scope;
4801 LocalContext other;
4802 LocalContext current;
4803
4804 Local<String> token = v8_str("<security token>");
4805 other->SetSecurityToken(token);
4806 current->SetSecurityToken(token);
4807
4808 // Setup reference from current to other.
4809 current->Global()->Set(v8_str("other"), other->Global());
4810
4811 // Trigger lazy loading in other context.
4812 Local<Script> script =
4813 Script::Compile(v8_str("other.eval('new Date(42)')"));
4814 Local<Value> value = script->Run();
4815 CHECK_EQ(42.0, value->NumberValue());
4816}
4817
4818
4819static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
4820 ApiTestFuzzer::Fuzz();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00004821 if (args.IsConstructCall()) {
4822 if (args[0]->IsInt32()) {
4823 return v8_num(-args[0]->Int32Value());
4824 }
4825 }
4826
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004827 return args[0];
4828}
4829
4830
4831// Test that a call handler can be set for objects which will allow
4832// non-function objects created through the API to be called as
4833// functions.
4834THREADED_TEST(CallAsFunction) {
4835 v8::HandleScope scope;
4836 LocalContext context;
4837
4838 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4839 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4840 instance_template->SetCallAsFunctionHandler(call_as_function);
4841 Local<v8::Object> instance = t->GetFunction()->NewInstance();
4842 context->Global()->Set(v8_str("obj"), instance);
4843 v8::TryCatch try_catch;
4844 Local<Value> value;
4845 CHECK(!try_catch.HasCaught());
4846
ager@chromium.org9085a012009-05-11 19:22:57 +00004847 value = CompileRun("obj(42)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004848 CHECK(!try_catch.HasCaught());
4849 CHECK_EQ(42, value->Int32Value());
4850
ager@chromium.org9085a012009-05-11 19:22:57 +00004851 value = CompileRun("(function(o){return o(49)})(obj)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004852 CHECK(!try_catch.HasCaught());
4853 CHECK_EQ(49, value->Int32Value());
4854
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004855 // test special case of call as function
ager@chromium.org9085a012009-05-11 19:22:57 +00004856 value = CompileRun("[obj]['0'](45)");
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004857 CHECK(!try_catch.HasCaught());
4858 CHECK_EQ(45, value->Int32Value());
4859
ager@chromium.org9085a012009-05-11 19:22:57 +00004860 value = CompileRun("obj.call = Function.prototype.call;"
4861 "obj.call(null, 87)");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004862 CHECK(!try_catch.HasCaught());
4863 CHECK_EQ(87, value->Int32Value());
4864
4865 // Regression tests for bug #1116356: Calling call through call/apply
4866 // must work for non-function receivers.
4867 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
ager@chromium.org9085a012009-05-11 19:22:57 +00004868 value = CompileRun(apply_99);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004869 CHECK(!try_catch.HasCaught());
4870 CHECK_EQ(99, value->Int32Value());
4871
4872 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
ager@chromium.org9085a012009-05-11 19:22:57 +00004873 value = CompileRun(call_17);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004874 CHECK(!try_catch.HasCaught());
4875 CHECK_EQ(17, value->Int32Value());
ager@chromium.org9085a012009-05-11 19:22:57 +00004876
4877 // Check that the call-as-function handler can be called through
4878 // new. Currently, there is no way to check in the call-as-function
4879 // handler if it has been called through new or not.
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00004880 value = CompileRun("new obj(43)");
ager@chromium.org9085a012009-05-11 19:22:57 +00004881 CHECK(!try_catch.HasCaught());
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00004882 CHECK_EQ(-43, value->Int32Value());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004883}
4884
4885
4886static int CountHandles() {
4887 return v8::HandleScope::NumberOfHandles();
4888}
4889
4890
4891static int Recurse(int depth, int iterations) {
4892 v8::HandleScope scope;
4893 if (depth == 0) return CountHandles();
4894 for (int i = 0; i < iterations; i++) {
4895 Local<v8::Number> n = v8::Integer::New(42);
4896 }
4897 return Recurse(depth - 1, iterations);
4898}
4899
4900
4901THREADED_TEST(HandleIteration) {
4902 static const int kIterations = 500;
4903 static const int kNesting = 200;
4904 CHECK_EQ(0, CountHandles());
4905 {
4906 v8::HandleScope scope1;
4907 CHECK_EQ(0, CountHandles());
4908 for (int i = 0; i < kIterations; i++) {
4909 Local<v8::Number> n = v8::Integer::New(42);
4910 CHECK_EQ(i + 1, CountHandles());
4911 }
4912
4913 CHECK_EQ(kIterations, CountHandles());
4914 {
4915 v8::HandleScope scope2;
4916 for (int j = 0; j < kIterations; j++) {
4917 Local<v8::Number> n = v8::Integer::New(42);
4918 CHECK_EQ(j + 1 + kIterations, CountHandles());
4919 }
4920 }
4921 CHECK_EQ(kIterations, CountHandles());
4922 }
4923 CHECK_EQ(0, CountHandles());
4924 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
4925}
4926
4927
4928static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
4929 Local<String> name,
4930 const AccessorInfo& info) {
4931 ApiTestFuzzer::Fuzz();
4932 return v8::Handle<Value>();
4933}
4934
4935
4936THREADED_TEST(InterceptorHasOwnProperty) {
4937 v8::HandleScope scope;
4938 LocalContext context;
4939 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4940 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
4941 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
4942 Local<Function> function = fun_templ->GetFunction();
4943 context->Global()->Set(v8_str("constructor"), function);
4944 v8::Handle<Value> value = CompileRun(
4945 "var o = new constructor();"
4946 "o.hasOwnProperty('ostehaps');");
4947 CHECK_EQ(false, value->BooleanValue());
4948 value = CompileRun(
4949 "o.ostehaps = 42;"
4950 "o.hasOwnProperty('ostehaps');");
4951 CHECK_EQ(true, value->BooleanValue());
4952 value = CompileRun(
4953 "var p = new constructor();"
4954 "p.hasOwnProperty('ostehaps');");
4955 CHECK_EQ(false, value->BooleanValue());
4956}
4957
4958
ager@chromium.org9085a012009-05-11 19:22:57 +00004959static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
4960 Local<String> name,
4961 const AccessorInfo& info) {
4962 ApiTestFuzzer::Fuzz();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00004963 i::Heap::CollectAllGarbage(false);
ager@chromium.org9085a012009-05-11 19:22:57 +00004964 return v8::Handle<Value>();
4965}
4966
4967
4968THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
4969 v8::HandleScope scope;
4970 LocalContext context;
4971 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4972 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
4973 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
4974 Local<Function> function = fun_templ->GetFunction();
4975 context->Global()->Set(v8_str("constructor"), function);
4976 // Let's first make some stuff so we can be sure to get a good GC.
4977 CompileRun(
4978 "function makestr(size) {"
4979 " switch (size) {"
4980 " case 1: return 'f';"
4981 " case 2: return 'fo';"
4982 " case 3: return 'foo';"
4983 " }"
4984 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
4985 "}"
4986 "var x = makestr(12345);"
4987 "x = makestr(31415);"
4988 "x = makestr(23456);");
4989 v8::Handle<Value> value = CompileRun(
4990 "var o = new constructor();"
4991 "o.__proto__ = new String(x);"
4992 "o.hasOwnProperty('ostehaps');");
4993 CHECK_EQ(false, value->BooleanValue());
4994}
4995
4996
ager@chromium.orge2902be2009-06-08 12:21:35 +00004997typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
4998 const AccessorInfo& info);
4999
5000
5001static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5002 const char* source,
5003 int expected) {
5004 v8::HandleScope scope;
5005 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5006 templ->SetNamedPropertyHandler(getter);
5007 LocalContext context;
5008 context->Global()->Set(v8_str("o"), templ->NewInstance());
5009 v8::Handle<Value> value = CompileRun(source);
5010 CHECK_EQ(expected, value->Int32Value());
5011}
5012
5013
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005014static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5015 const AccessorInfo& info) {
5016 ApiTestFuzzer::Fuzz();
5017 CHECK(v8_str("x")->Equals(name));
5018 return v8::Integer::New(42);
5019}
5020
5021
5022// This test should hit the load IC for the interceptor case.
5023THREADED_TEST(InterceptorLoadIC) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00005024 CheckInterceptorLoadIC(InterceptorLoadICGetter,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005025 "var result = 0;"
5026 "for (var i = 0; i < 1000; i++) {"
5027 " result = o.x;"
ager@chromium.orge2902be2009-06-08 12:21:35 +00005028 "}",
5029 42);
5030}
5031
5032
5033// Below go several tests which verify that JITing for various
5034// configurations of interceptor and explicit fields works fine
5035// (those cases are special cased to get better performance).
5036
5037static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5038 const AccessorInfo& info) {
5039 ApiTestFuzzer::Fuzz();
5040 return v8_str("x")->Equals(name)
5041 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5042}
5043
5044
5045THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5046 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5047 "var result = 0;"
5048 "o.y = 239;"
5049 "for (var i = 0; i < 1000; i++) {"
5050 " result = o.y;"
5051 "}",
5052 239);
5053}
5054
5055
5056THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5057 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5058 "var result = 0;"
5059 "o.__proto__ = { 'y': 239 };"
5060 "for (var i = 0; i < 1000; i++) {"
5061 " result = o.y + o.x;"
5062 "}",
5063 239 + 42);
5064}
5065
5066
5067THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5068 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5069 "var result = 0;"
5070 "o.__proto__.y = 239;"
5071 "for (var i = 0; i < 1000; i++) {"
5072 " result = o.y + o.x;"
5073 "}",
5074 239 + 42);
5075}
5076
5077
5078THREADED_TEST(InterceptorLoadICUndefined) {
5079 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5080 "var result = 0;"
5081 "for (var i = 0; i < 1000; i++) {"
5082 " result = (o.y == undefined) ? 239 : 42;"
5083 "}",
5084 239);
5085}
5086
5087
5088THREADED_TEST(InterceptorLoadICWithOverride) {
5089 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5090 "fst = new Object(); fst.__proto__ = o;"
5091 "snd = new Object(); snd.__proto__ = fst;"
5092 "var result1 = 0;"
5093 "for (var i = 0; i < 1000; i++) {"
5094 " result1 = snd.x;"
5095 "}"
5096 "fst.x = 239;"
5097 "var result = 0;"
5098 "for (var i = 0; i < 1000; i++) {"
5099 " result = snd.x;"
5100 "}"
5101 "result + result1",
5102 239 + 42);
5103}
5104
5105
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005106// Test the case when we stored field into
5107// a stub, but interceptor produced value on its own.
5108THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5109 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5110 "proto = new Object();"
5111 "o.__proto__ = proto;"
5112 "proto.x = 239;"
5113 "for (var i = 0; i < 1000; i++) {"
5114 " o.x;"
5115 // Now it should be ICed and keep a reference to x defined on proto
5116 "}"
5117 "var result = 0;"
5118 "for (var i = 0; i < 1000; i++) {"
5119 " result += o.x;"
5120 "}"
5121 "result;",
5122 42 * 1000);
5123}
5124
5125
5126// Test the case when we stored field into
5127// a stub, but it got invalidated later on.
5128THREADED_TEST(InterceptorLoadICInvalidatedField) {
5129 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5130 "proto1 = new Object();"
5131 "proto2 = new Object();"
5132 "o.__proto__ = proto1;"
5133 "proto1.__proto__ = proto2;"
5134 "proto2.y = 239;"
5135 "for (var i = 0; i < 1000; i++) {"
5136 " o.y;"
5137 // Now it should be ICed and keep a reference to y defined on proto2
5138 "}"
5139 "proto1.y = 42;"
5140 "var result = 0;"
5141 "for (var i = 0; i < 1000; i++) {"
5142 " result += o.y;"
5143 "}"
5144 "result;",
5145 42 * 1000);
5146}
5147
5148
5149// Test the case when we stored field into
5150// a stub, but it got invalidated later on due to override on
5151// global object which is between interceptor and fields' holders.
5152THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
5153 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5154 "o.__proto__ = this;" // set a global to be a proto of o.
5155 "this.__proto__.y = 239;"
5156 "for (var i = 0; i < 10; i++) {"
5157 " if (o.y != 239) throw 'oops: ' + o.y;"
5158 // Now it should be ICed and keep a reference to y defined on field_holder.
5159 "}"
5160 "this.y = 42;" // Assign on a global.
5161 "var result = 0;"
5162 "for (var i = 0; i < 10; i++) {"
5163 " result += o.y;"
5164 "}"
5165 "result;",
5166 42 * 10);
5167}
5168
5169
5170static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
5171 ApiTestFuzzer::Fuzz();
5172 return v8_num(239);
5173}
5174
5175
5176static void SetOnThis(Local<String> name,
5177 Local<Value> value,
5178 const AccessorInfo& info) {
5179 info.This()->ForceSet(name, value);
5180}
5181
5182
5183THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
5184 v8::HandleScope scope;
5185 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5186 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5187 templ->SetAccessor(v8_str("y"), Return239);
5188 LocalContext context;
5189 context->Global()->Set(v8_str("o"), templ->NewInstance());
5190 v8::Handle<Value> value = CompileRun(
5191 "var result = 0;"
5192 "for (var i = 0; i < 7; i++) {"
5193 " result = o.y;"
5194 "}");
5195 CHECK_EQ(239, value->Int32Value());
5196}
5197
5198
5199THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
5200 v8::HandleScope scope;
5201 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5202 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5203 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5204 templ_p->SetAccessor(v8_str("y"), Return239);
5205
5206 LocalContext context;
5207 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5208 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5209
5210 v8::Handle<Value> value = CompileRun(
5211 "o.__proto__ = p;"
5212 "var result = 0;"
5213 "for (var i = 0; i < 7; i++) {"
5214 " result = o.x + o.y;"
5215 "}");
5216 CHECK_EQ(239 + 42, value->Int32Value());
5217}
5218
5219
5220THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
5221 v8::HandleScope scope;
5222 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5223 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5224 templ->SetAccessor(v8_str("y"), Return239);
5225
5226 LocalContext context;
5227 context->Global()->Set(v8_str("o"), templ->NewInstance());
5228
5229 v8::Handle<Value> value = CompileRun(
5230 "fst = new Object(); fst.__proto__ = o;"
5231 "snd = new Object(); snd.__proto__ = fst;"
5232 "var result1 = 0;"
5233 "for (var i = 0; i < 7; i++) {"
5234 " result1 = snd.x;"
5235 "}"
5236 "fst.x = 239;"
5237 "var result = 0;"
5238 "for (var i = 0; i < 7; i++) {"
5239 " result = snd.x;"
5240 "}"
5241 "result + result1");
5242 CHECK_EQ(239 + 42, value->Int32Value());
5243}
5244
5245
5246// Test the case when we stored callback into
5247// a stub, but interceptor produced value on its own.
5248THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
5249 v8::HandleScope scope;
5250 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5251 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5252 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5253 templ_p->SetAccessor(v8_str("y"), Return239);
5254
5255 LocalContext context;
5256 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5257 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5258
5259 v8::Handle<Value> value = CompileRun(
5260 "o.__proto__ = p;"
5261 "for (var i = 0; i < 7; i++) {"
5262 " o.x;"
5263 // Now it should be ICed and keep a reference to x defined on p
5264 "}"
5265 "var result = 0;"
5266 "for (var i = 0; i < 7; i++) {"
5267 " result += o.x;"
5268 "}"
5269 "result");
5270 CHECK_EQ(42 * 7, value->Int32Value());
5271}
5272
5273
5274// Test the case when we stored callback into
5275// a stub, but it got invalidated later on.
5276THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
5277 v8::HandleScope scope;
5278 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5279 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5280 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5281 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5282
5283 LocalContext context;
5284 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5285 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5286
5287 v8::Handle<Value> value = CompileRun(
5288 "inbetween = new Object();"
5289 "o.__proto__ = inbetween;"
5290 "inbetween.__proto__ = p;"
5291 "for (var i = 0; i < 10; i++) {"
5292 " o.y;"
5293 // Now it should be ICed and keep a reference to y defined on p
5294 "}"
5295 "inbetween.y = 42;"
5296 "var result = 0;"
5297 "for (var i = 0; i < 10; i++) {"
5298 " result += o.y;"
5299 "}"
5300 "result");
5301 CHECK_EQ(42 * 10, value->Int32Value());
5302}
5303
5304
5305// Test the case when we stored callback into
5306// a stub, but it got invalidated later on due to override on
5307// global object which is between interceptor and callbacks' holders.
5308THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
5309 v8::HandleScope scope;
5310 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5311 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5312 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5313 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5314
5315 LocalContext context;
5316 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5317 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5318
5319 v8::Handle<Value> value = CompileRun(
5320 "o.__proto__ = this;"
5321 "this.__proto__ = p;"
5322 "for (var i = 0; i < 10; i++) {"
5323 " if (o.y != 239) throw 'oops: ' + o.y;"
5324 // Now it should be ICed and keep a reference to y defined on p
5325 "}"
5326 "this.y = 42;"
5327 "var result = 0;"
5328 "for (var i = 0; i < 10; i++) {"
5329 " result += o.y;"
5330 "}"
5331 "result");
5332 CHECK_EQ(42 * 10, value->Int32Value());
5333}
5334
5335
ager@chromium.orge2902be2009-06-08 12:21:35 +00005336static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
5337 const AccessorInfo& info) {
5338 ApiTestFuzzer::Fuzz();
5339 CHECK(v8_str("x")->Equals(name));
5340 return v8::Integer::New(0);
5341}
5342
5343
5344THREADED_TEST(InterceptorReturningZero) {
5345 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
5346 "o.x == undefined ? 1 : 0",
5347 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005348}
5349
5350
5351static v8::Handle<Value> InterceptorStoreICSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005352 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005353 CHECK(v8_str("x")->Equals(key));
5354 CHECK_EQ(42, value->Int32Value());
5355 return value;
5356}
5357
5358
5359// This test should hit the store IC for the interceptor case.
5360THREADED_TEST(InterceptorStoreIC) {
5361 v8::HandleScope scope;
5362 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5363 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
5364 InterceptorStoreICSetter);
5365 LocalContext context;
5366 context->Global()->Set(v8_str("o"), templ->NewInstance());
5367 v8::Handle<Value> value = CompileRun(
5368 "for (var i = 0; i < 1000; i++) {"
5369 " o.x = 42;"
5370 "}");
5371}
5372
5373
ager@chromium.orgeadaf222009-06-16 09:43:10 +00005374THREADED_TEST(InterceptorStoreICWithNoSetter) {
5375 v8::HandleScope scope;
5376 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5377 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5378 LocalContext context;
5379 context->Global()->Set(v8_str("o"), templ->NewInstance());
5380 v8::Handle<Value> value = CompileRun(
5381 "for (var i = 0; i < 1000; i++) {"
5382 " o.y = 239;"
5383 "}"
5384 "42 + o.y");
5385 CHECK_EQ(239 + 42, value->Int32Value());
5386}
5387
5388
5389
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005390
5391v8::Handle<Value> call_ic_function;
5392v8::Handle<Value> call_ic_function2;
5393v8::Handle<Value> call_ic_function3;
5394
5395static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
5396 const AccessorInfo& info) {
5397 ApiTestFuzzer::Fuzz();
5398 CHECK(v8_str("x")->Equals(name));
5399 return call_ic_function;
5400}
5401
5402
5403// This test should hit the call IC for the interceptor case.
5404THREADED_TEST(InterceptorCallIC) {
5405 v8::HandleScope scope;
5406 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5407 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
5408 LocalContext context;
5409 context->Global()->Set(v8_str("o"), templ->NewInstance());
5410 call_ic_function =
5411 v8_compile("function f(x) { return x + 1; }; f")->Run();
5412 v8::Handle<Value> value = CompileRun(
5413 "var result = 0;"
5414 "for (var i = 0; i < 1000; i++) {"
5415 " result = o.x(41);"
5416 "}");
5417 CHECK_EQ(42, value->Int32Value());
5418}
5419
kasperl@chromium.orge959c182009-07-27 08:59:04 +00005420
5421// This test checks that if interceptor doesn't provide
5422// a value, we can fetch regular value.
5423THREADED_TEST(InterceptorCallICSeesOthers) {
5424 v8::HandleScope scope;
5425 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5426 templ->SetNamedPropertyHandler(NoBlockGetterX);
5427 LocalContext context;
5428 context->Global()->Set(v8_str("o"), templ->NewInstance());
5429 v8::Handle<Value> value = CompileRun(
5430 "o.x = function f(x) { return x + 1; };"
5431 "var result = 0;"
5432 "for (var i = 0; i < 7; i++) {"
5433 " result = o.x(41);"
5434 "}");
5435 CHECK_EQ(42, value->Int32Value());
5436}
5437
5438
5439static v8::Handle<Value> call_ic_function4;
5440static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
5441 const AccessorInfo& info) {
5442 ApiTestFuzzer::Fuzz();
5443 CHECK(v8_str("x")->Equals(name));
5444 return call_ic_function4;
5445}
5446
5447
5448// This test checks that if interceptor provides a function,
5449// even if we cached shadowed variant, interceptor's function
5450// is invoked
5451THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
5452 v8::HandleScope scope;
5453 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5454 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
5455 LocalContext context;
5456 context->Global()->Set(v8_str("o"), templ->NewInstance());
5457 call_ic_function4 =
5458 v8_compile("function f(x) { return x - 1; }; f")->Run();
5459 v8::Handle<Value> value = CompileRun(
5460 "o.__proto__.x = function(x) { return x + 1; };"
5461 "var result = 0;"
5462 "for (var i = 0; i < 1000; i++) {"
5463 " result = o.x(42);"
5464 "}");
5465 CHECK_EQ(41, value->Int32Value());
5466}
5467
5468
5469// Test the case when we stored cacheable lookup into
5470// a stub, but it got invalidated later on
5471THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
5472 v8::HandleScope scope;
5473 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5474 templ->SetNamedPropertyHandler(NoBlockGetterX);
5475 LocalContext context;
5476 context->Global()->Set(v8_str("o"), templ->NewInstance());
5477 v8::Handle<Value> value = CompileRun(
5478 "proto1 = new Object();"
5479 "proto2 = new Object();"
5480 "o.__proto__ = proto1;"
5481 "proto1.__proto__ = proto2;"
5482 "proto2.y = function(x) { return x + 1; };"
5483 // Invoke it many times to compile a stub
5484 "for (var i = 0; i < 7; i++) {"
5485 " o.y(42);"
5486 "}"
5487 "proto1.y = function(x) { return x - 1; };"
5488 "var result = 0;"
5489 "for (var i = 0; i < 7; i++) {"
5490 " result += o.y(42);"
5491 "}");
5492 CHECK_EQ(41 * 7, value->Int32Value());
5493}
5494
5495
5496static v8::Handle<Value> call_ic_function5;
5497static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
5498 const AccessorInfo& info) {
5499 ApiTestFuzzer::Fuzz();
5500 if (v8_str("x")->Equals(name))
5501 return call_ic_function5;
5502 else
5503 return Local<Value>();
5504}
5505
5506
5507// This test checks that if interceptor doesn't provide a function,
5508// cached constant function is used
5509THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
5510 v8::HandleScope scope;
5511 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5512 templ->SetNamedPropertyHandler(NoBlockGetterX);
5513 LocalContext context;
5514 context->Global()->Set(v8_str("o"), templ->NewInstance());
5515 v8::Handle<Value> value = CompileRun(
5516 "function inc(x) { return x + 1; };"
5517 "inc(1);"
5518 "o.x = inc;"
5519 "var result = 0;"
5520 "for (var i = 0; i < 1000; i++) {"
5521 " result = o.x(42);"
5522 "}");
5523 CHECK_EQ(43, value->Int32Value());
5524}
5525
5526
5527// This test checks that if interceptor provides a function,
5528// even if we cached constant function, interceptor's function
5529// is invoked
5530THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
5531 v8::HandleScope scope;
5532 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5533 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
5534 LocalContext context;
5535 context->Global()->Set(v8_str("o"), templ->NewInstance());
5536 call_ic_function5 =
5537 v8_compile("function f(x) { return x - 1; }; f")->Run();
5538 v8::Handle<Value> value = CompileRun(
5539 "function inc(x) { return x + 1; };"
5540 "inc(1);"
5541 "o.x = inc;"
5542 "var result = 0;"
5543 "for (var i = 0; i < 1000; i++) {"
5544 " result = o.x(42);"
5545 "}");
5546 CHECK_EQ(41, value->Int32Value());
5547}
5548
5549
5550// Test the case when we stored constant function into
5551// a stub, but it got invalidated later on
5552THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
5553 v8::HandleScope scope;
5554 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5555 templ->SetNamedPropertyHandler(NoBlockGetterX);
5556 LocalContext context;
5557 context->Global()->Set(v8_str("o"), templ->NewInstance());
5558 v8::Handle<Value> value = CompileRun(
5559 "function inc(x) { return x + 1; };"
5560 "inc(1);"
5561 "proto1 = new Object();"
5562 "proto2 = new Object();"
5563 "o.__proto__ = proto1;"
5564 "proto1.__proto__ = proto2;"
5565 "proto2.y = inc;"
5566 // Invoke it many times to compile a stub
5567 "for (var i = 0; i < 7; i++) {"
5568 " o.y(42);"
5569 "}"
5570 "proto1.y = function(x) { return x - 1; };"
5571 "var result = 0;"
5572 "for (var i = 0; i < 7; i++) {"
5573 " result += o.y(42);"
5574 "}");
5575 CHECK_EQ(41 * 7, value->Int32Value());
5576}
5577
5578
5579// Test the case when we stored constant function into
5580// a stub, but it got invalidated later on due to override on
5581// global object which is between interceptor and constant function' holders.
5582THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
5583 v8::HandleScope scope;
5584 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5585 templ->SetNamedPropertyHandler(NoBlockGetterX);
5586 LocalContext context;
5587 context->Global()->Set(v8_str("o"), templ->NewInstance());
5588 v8::Handle<Value> value = CompileRun(
5589 "function inc(x) { return x + 1; };"
5590 "inc(1);"
5591 "o.__proto__ = this;"
5592 "this.__proto__.y = inc;"
5593 // Invoke it many times to compile a stub
5594 "for (var i = 0; i < 7; i++) {"
5595 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
5596 "}"
5597 "this.y = function(x) { return x - 1; };"
5598 "var result = 0;"
5599 "for (var i = 0; i < 7; i++) {"
5600 " result += o.y(42);"
5601 "}");
5602 CHECK_EQ(41 * 7, value->Int32Value());
5603}
5604
5605
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005606static int interceptor_call_count = 0;
5607
5608static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
5609 const AccessorInfo& info) {
5610 ApiTestFuzzer::Fuzz();
5611 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
5612 return call_ic_function2;
5613 }
5614 return v8::Handle<Value>();
5615}
5616
5617
5618// This test should hit load and call ICs for the interceptor case.
5619// Once in a while, the interceptor will reply that a property was not
5620// found in which case we should get a reference error.
5621THREADED_TEST(InterceptorICReferenceErrors) {
5622 v8::HandleScope scope;
5623 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5624 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
5625 LocalContext context(0, templ, v8::Handle<Value>());
5626 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
5627 v8::Handle<Value> value = CompileRun(
5628 "function f() {"
5629 " for (var i = 0; i < 1000; i++) {"
5630 " try { x; } catch(e) { return true; }"
5631 " }"
5632 " return false;"
5633 "};"
5634 "f();");
5635 CHECK_EQ(true, value->BooleanValue());
5636 interceptor_call_count = 0;
5637 value = CompileRun(
5638 "function g() {"
5639 " for (var i = 0; i < 1000; i++) {"
5640 " try { x(42); } catch(e) { return true; }"
5641 " }"
5642 " return false;"
5643 "};"
5644 "g();");
5645 CHECK_EQ(true, value->BooleanValue());
5646}
5647
5648
5649static int interceptor_ic_exception_get_count = 0;
5650
5651static v8::Handle<Value> InterceptorICExceptionGetter(
5652 Local<String> name,
5653 const AccessorInfo& info) {
5654 ApiTestFuzzer::Fuzz();
5655 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
5656 return call_ic_function3;
5657 }
5658 if (interceptor_ic_exception_get_count == 20) {
5659 return v8::ThrowException(v8_num(42));
5660 }
5661 // Do not handle get for properties other than x.
5662 return v8::Handle<Value>();
5663}
5664
5665// Test interceptor load/call IC where the interceptor throws an
5666// exception once in a while.
5667THREADED_TEST(InterceptorICGetterExceptions) {
5668 interceptor_ic_exception_get_count = 0;
5669 v8::HandleScope scope;
5670 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5671 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
5672 LocalContext context(0, templ, v8::Handle<Value>());
5673 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
5674 v8::Handle<Value> value = CompileRun(
5675 "function f() {"
5676 " for (var i = 0; i < 100; i++) {"
5677 " try { x; } catch(e) { return true; }"
5678 " }"
5679 " return false;"
5680 "};"
5681 "f();");
5682 CHECK_EQ(true, value->BooleanValue());
5683 interceptor_ic_exception_get_count = 0;
5684 value = CompileRun(
5685 "function f() {"
5686 " for (var i = 0; i < 100; i++) {"
5687 " try { x(42); } catch(e) { return true; }"
5688 " }"
5689 " return false;"
5690 "};"
5691 "f();");
5692 CHECK_EQ(true, value->BooleanValue());
5693}
5694
5695
5696static int interceptor_ic_exception_set_count = 0;
5697
5698static v8::Handle<Value> InterceptorICExceptionSetter(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005699 Local<String> key, Local<Value> value, const AccessorInfo&) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005700 ApiTestFuzzer::Fuzz();
5701 if (++interceptor_ic_exception_set_count > 20) {
5702 return v8::ThrowException(v8_num(42));
5703 }
5704 // Do not actually handle setting.
5705 return v8::Handle<Value>();
5706}
5707
5708// Test interceptor store IC where the interceptor throws an exception
5709// once in a while.
5710THREADED_TEST(InterceptorICSetterExceptions) {
5711 interceptor_ic_exception_set_count = 0;
5712 v8::HandleScope scope;
5713 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5714 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
5715 LocalContext context(0, templ, v8::Handle<Value>());
5716 v8::Handle<Value> value = CompileRun(
5717 "function f() {"
5718 " for (var i = 0; i < 100; i++) {"
5719 " try { x = 42; } catch(e) { return true; }"
5720 " }"
5721 " return false;"
5722 "};"
5723 "f();");
5724 CHECK_EQ(true, value->BooleanValue());
5725}
5726
5727
5728// Test that we ignore null interceptors.
5729THREADED_TEST(NullNamedInterceptor) {
5730 v8::HandleScope scope;
5731 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5732 templ->SetNamedPropertyHandler(0);
5733 LocalContext context;
5734 templ->Set("x", v8_num(42));
5735 v8::Handle<v8::Object> obj = templ->NewInstance();
5736 context->Global()->Set(v8_str("obj"), obj);
5737 v8::Handle<Value> value = CompileRun("obj.x");
5738 CHECK(value->IsInt32());
5739 CHECK_EQ(42, value->Int32Value());
5740}
5741
5742
5743// Test that we ignore null interceptors.
5744THREADED_TEST(NullIndexedInterceptor) {
5745 v8::HandleScope scope;
5746 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5747 templ->SetIndexedPropertyHandler(0);
5748 LocalContext context;
5749 templ->Set("42", v8_num(42));
5750 v8::Handle<v8::Object> obj = templ->NewInstance();
5751 context->Global()->Set(v8_str("obj"), obj);
5752 v8::Handle<Value> value = CompileRun("obj[42]");
5753 CHECK(value->IsInt32());
5754 CHECK_EQ(42, value->Int32Value());
5755}
5756
5757
5758static v8::Handle<Value> ParentGetter(Local<String> name,
5759 const AccessorInfo& info) {
5760 ApiTestFuzzer::Fuzz();
5761 return v8_num(1);
5762}
5763
5764
5765static v8::Handle<Value> ChildGetter(Local<String> name,
5766 const AccessorInfo& info) {
5767 ApiTestFuzzer::Fuzz();
5768 return v8_num(42);
5769}
5770
5771
5772THREADED_TEST(Overriding) {
5773 v8::HandleScope scope;
5774 LocalContext context;
5775
5776 // Parent template.
5777 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
5778 Local<ObjectTemplate> parent_instance_templ =
5779 parent_templ->InstanceTemplate();
5780 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
5781
5782 // Template that inherits from the parent template.
5783 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
5784 Local<ObjectTemplate> child_instance_templ =
5785 child_templ->InstanceTemplate();
5786 child_templ->Inherit(parent_templ);
5787 // Override 'f'. The child version of 'f' should get called for child
5788 // instances.
5789 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
5790 // Add 'g' twice. The 'g' added last should get called for instances.
5791 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
5792 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
5793
5794 // Add 'h' as an accessor to the proto template with ReadOnly attributes
5795 // so 'h' can be shadowed on the instance object.
5796 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
5797 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
5798 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5799
5800 // Add 'i' as an accessor to the instance template with ReadOnly attributes
5801 // but the attribute does not have effect because it is duplicated with
5802 // NULL setter.
5803 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
5804 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5805
5806
5807
5808 // Instantiate the child template.
5809 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
5810
5811 // Check that the child function overrides the parent one.
5812 context->Global()->Set(v8_str("o"), instance);
5813 Local<Value> value = v8_compile("o.f")->Run();
5814 // Check that the 'g' that was added last is hit.
5815 CHECK_EQ(42, value->Int32Value());
5816 value = v8_compile("o.g")->Run();
5817 CHECK_EQ(42, value->Int32Value());
5818
5819 // Check 'h' can be shadowed.
5820 value = v8_compile("o.h = 3; o.h")->Run();
5821 CHECK_EQ(3, value->Int32Value());
5822
5823 // Check 'i' is cannot be shadowed or changed.
5824 value = v8_compile("o.i = 3; o.i")->Run();
5825 CHECK_EQ(42, value->Int32Value());
5826}
5827
5828
5829static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
5830 ApiTestFuzzer::Fuzz();
5831 if (args.IsConstructCall()) {
5832 return v8::Boolean::New(true);
5833 }
5834 return v8::Boolean::New(false);
5835}
5836
5837
5838THREADED_TEST(IsConstructCall) {
5839 v8::HandleScope scope;
5840
5841 // Function template with call handler.
5842 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5843 templ->SetCallHandler(IsConstructHandler);
5844
5845 LocalContext context;
5846
5847 context->Global()->Set(v8_str("f"), templ->GetFunction());
5848 Local<Value> value = v8_compile("f()")->Run();
5849 CHECK(!value->BooleanValue());
5850 value = v8_compile("new f()")->Run();
5851 CHECK(value->BooleanValue());
5852}
5853
5854
5855THREADED_TEST(ObjectProtoToString) {
5856 v8::HandleScope scope;
5857 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5858 templ->SetClassName(v8_str("MyClass"));
5859
5860 LocalContext context;
5861
5862 Local<String> customized_tostring = v8_str("customized toString");
5863
5864 // Replace Object.prototype.toString
5865 v8_compile("Object.prototype.toString = function() {"
5866 " return 'customized toString';"
5867 "}")->Run();
5868
5869 // Normal ToString call should call replaced Object.prototype.toString
5870 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
5871 Local<String> value = instance->ToString();
5872 CHECK(value->IsString() && value->Equals(customized_tostring));
5873
5874 // ObjectProtoToString should not call replace toString function.
5875 value = instance->ObjectProtoToString();
5876 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
5877
5878 // Check global
5879 value = context->Global()->ObjectProtoToString();
5880 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
5881
5882 // Check ordinary object
5883 Local<Value> object = v8_compile("new Object()")->Run();
5884 value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
5885 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
5886}
5887
5888
5889bool ApiTestFuzzer::fuzzing_ = false;
5890v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
5891 v8::internal::OS::CreateSemaphore(0);
5892int ApiTestFuzzer::active_tests_;
5893int ApiTestFuzzer::tests_being_run_;
5894int ApiTestFuzzer::current_;
5895
5896
5897// We are in a callback and want to switch to another thread (if we
5898// are currently running the thread fuzzing test).
5899void ApiTestFuzzer::Fuzz() {
5900 if (!fuzzing_) return;
5901 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
5902 test->ContextSwitch();
5903}
5904
5905
5906// Let the next thread go. Since it is also waiting on the V8 lock it may
5907// not start immediately.
5908bool ApiTestFuzzer::NextThread() {
5909 int test_position = GetNextTestNumber();
5910 int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
5911 if (test_position == current_) {
5912 printf("Stay with %d\n", test_number);
5913 return false;
5914 }
5915 printf("Switch from %d to %d\n",
5916 current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
5917 current_ = test_position;
5918 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
5919 return true;
5920}
5921
5922
5923void ApiTestFuzzer::Run() {
5924 // When it is our turn...
5925 gate_->Wait();
5926 {
5927 // ... get the V8 lock and start running the test.
5928 v8::Locker locker;
5929 CallTest();
5930 }
5931 // This test finished.
5932 active_ = false;
5933 active_tests_--;
5934 // If it was the last then signal that fact.
5935 if (active_tests_ == 0) {
5936 all_tests_done_->Signal();
5937 } else {
5938 // Otherwise select a new test and start that.
5939 NextThread();
5940 }
5941}
5942
5943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005944static unsigned linear_congruential_generator;
5945
5946
5947void ApiTestFuzzer::Setup(PartOfTest part) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005948 linear_congruential_generator = i::FLAG_testing_prng_seed;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005949 fuzzing_ = true;
5950 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
5951 int end = (part == FIRST_PART)
5952 ? (RegisterThreadedTest::count() >> 1)
5953 : RegisterThreadedTest::count();
5954 active_tests_ = tests_being_run_ = end - start;
5955 for (int i = 0; i < tests_being_run_; i++) {
5956 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
5957 }
5958 for (int i = 0; i < active_tests_; i++) {
5959 RegisterThreadedTest::nth(i)->fuzzer_->Start();
5960 }
5961}
5962
5963
5964static void CallTestNumber(int test_number) {
5965 (RegisterThreadedTest::nth(test_number)->callback())();
5966}
5967
5968
5969void ApiTestFuzzer::RunAllTests() {
5970 // Set off the first test.
5971 current_ = -1;
5972 NextThread();
5973 // Wait till they are all done.
5974 all_tests_done_->Wait();
5975}
5976
5977
5978int ApiTestFuzzer::GetNextTestNumber() {
5979 int next_test;
5980 do {
5981 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
5982 linear_congruential_generator *= 1664525u;
5983 linear_congruential_generator += 1013904223u;
5984 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
5985 return next_test;
5986}
5987
5988
5989void ApiTestFuzzer::ContextSwitch() {
5990 // If the new thread is the same as the current thread there is nothing to do.
5991 if (NextThread()) {
5992 // Now it can start.
5993 v8::Unlocker unlocker;
5994 // Wait till someone starts us again.
5995 gate_->Wait();
5996 // And we're off.
5997 }
5998}
5999
6000
6001void ApiTestFuzzer::TearDown() {
6002 fuzzing_ = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00006003 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
6004 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
6005 if (fuzzer != NULL) fuzzer->Join();
6006 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006007}
6008
6009
6010// Lets not be needlessly self-referential.
6011TEST(Threading) {
6012 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
6013 ApiTestFuzzer::RunAllTests();
6014 ApiTestFuzzer::TearDown();
6015}
6016
6017TEST(Threading2) {
6018 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
6019 ApiTestFuzzer::RunAllTests();
6020 ApiTestFuzzer::TearDown();
6021}
6022
6023
6024void ApiTestFuzzer::CallTest() {
6025 printf("Start test %d\n", test_number_);
6026 CallTestNumber(test_number_);
6027 printf("End test %d\n", test_number_);
6028}
6029
6030
6031static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006032 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006033 ApiTestFuzzer::Fuzz();
6034 v8::Unlocker unlocker;
6035 const char* code = "throw 7;";
6036 {
6037 v8::Locker nested_locker;
6038 v8::HandleScope scope;
6039 v8::Handle<Value> exception;
6040 { v8::TryCatch try_catch;
6041 v8::Handle<Value> value = CompileRun(code);
6042 CHECK(value.IsEmpty());
6043 CHECK(try_catch.HasCaught());
6044 // Make sure to wrap the exception in a new handle because
6045 // the handle returned from the TryCatch is destroyed
6046 // when the TryCatch is destroyed.
6047 exception = Local<Value>::New(try_catch.Exception());
6048 }
6049 return v8::ThrowException(exception);
6050 }
6051}
6052
6053
6054static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006055 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006056 ApiTestFuzzer::Fuzz();
6057 v8::Unlocker unlocker;
6058 const char* code = "throw 7;";
6059 {
6060 v8::Locker nested_locker;
6061 v8::HandleScope scope;
6062 v8::Handle<Value> value = CompileRun(code);
6063 CHECK(value.IsEmpty());
6064 return v8_str("foo");
6065 }
6066}
6067
6068
6069// These are locking tests that don't need to be run again
6070// as part of the locking aggregation tests.
6071TEST(NestedLockers) {
6072 v8::Locker locker;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006073 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006074 v8::HandleScope scope;
6075 LocalContext env;
6076 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
6077 Local<Function> fun = fun_templ->GetFunction();
6078 env->Global()->Set(v8_str("throw_in_js"), fun);
6079 Local<Script> script = v8_compile("(function () {"
6080 " try {"
6081 " throw_in_js();"
6082 " return 42;"
6083 " } catch (e) {"
6084 " return e * 13;"
6085 " }"
6086 "})();");
6087 CHECK_EQ(91, script->Run()->Int32Value());
6088}
6089
6090
6091// These are locking tests that don't need to be run again
6092// as part of the locking aggregation tests.
6093TEST(NestedLockersNoTryCatch) {
6094 v8::Locker locker;
6095 v8::HandleScope scope;
6096 LocalContext env;
6097 Local<v8::FunctionTemplate> fun_templ =
6098 v8::FunctionTemplate::New(ThrowInJSNoCatch);
6099 Local<Function> fun = fun_templ->GetFunction();
6100 env->Global()->Set(v8_str("throw_in_js"), fun);
6101 Local<Script> script = v8_compile("(function () {"
6102 " try {"
6103 " throw_in_js();"
6104 " return 42;"
6105 " } catch (e) {"
6106 " return e * 13;"
6107 " }"
6108 "})();");
6109 CHECK_EQ(91, script->Run()->Int32Value());
6110}
6111
6112
6113THREADED_TEST(RecursiveLocking) {
6114 v8::Locker locker;
6115 {
6116 v8::Locker locker2;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006117 CHECK(v8::Locker::IsLocked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006118 }
6119}
6120
6121
6122static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
6123 ApiTestFuzzer::Fuzz();
6124 v8::Unlocker unlocker;
6125 return v8::Undefined();
6126}
6127
6128
6129THREADED_TEST(LockUnlockLock) {
6130 {
6131 v8::Locker locker;
6132 v8::HandleScope scope;
6133 LocalContext env;
6134 Local<v8::FunctionTemplate> fun_templ =
6135 v8::FunctionTemplate::New(UnlockForAMoment);
6136 Local<Function> fun = fun_templ->GetFunction();
6137 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6138 Local<Script> script = v8_compile("(function () {"
6139 " unlock_for_a_moment();"
6140 " return 42;"
6141 "})();");
6142 CHECK_EQ(42, script->Run()->Int32Value());
6143 }
6144 {
6145 v8::Locker locker;
6146 v8::HandleScope scope;
6147 LocalContext env;
6148 Local<v8::FunctionTemplate> fun_templ =
6149 v8::FunctionTemplate::New(UnlockForAMoment);
6150 Local<Function> fun = fun_templ->GetFunction();
6151 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6152 Local<Script> script = v8_compile("(function () {"
6153 " unlock_for_a_moment();"
6154 " return 42;"
6155 "})();");
6156 CHECK_EQ(42, script->Run()->Int32Value());
6157 }
6158}
6159
6160
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006161static int GetSurvivingGlobalObjectsCount() {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006162 int count = 0;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006163 // We need to collect all garbage twice to be sure that everything
6164 // has been collected. This is because inline caches are cleared in
6165 // the first garbage collection but some of the maps have already
6166 // been marked at that point. Therefore some of the maps are not
6167 // collected until the second garbage collection.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006168 v8::internal::Heap::CollectAllGarbage(false);
6169 v8::internal::Heap::CollectAllGarbage(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006170 v8::internal::HeapIterator it;
6171 while (it.has_next()) {
6172 v8::internal::HeapObject* object = it.next();
6173 if (object->IsJSGlobalObject()) {
6174 count++;
6175 }
6176 }
6177#ifdef DEBUG
6178 if (count > 0) v8::internal::Heap::TracePathToGlobal();
6179#endif
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006180 return count;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006181}
6182
6183
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006184TEST(DontLeakGlobalObjects) {
6185 // Regression test for issues 1139850 and 1174891.
6186
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006187 v8::V8::Initialize();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006188
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006189 int count = GetSurvivingGlobalObjectsCount();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006190
6191 for (int i = 0; i < 5; i++) {
6192 { v8::HandleScope scope;
6193 LocalContext context;
6194 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006195 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006196
6197 { v8::HandleScope scope;
6198 LocalContext context;
6199 v8_compile("Date")->Run();
6200 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006201 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006202
6203 { v8::HandleScope scope;
6204 LocalContext context;
6205 v8_compile("/aaa/")->Run();
6206 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006207 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006208
6209 { v8::HandleScope scope;
6210 const char* extension_list[] = { "v8/gc" };
6211 v8::ExtensionConfiguration extensions(1, extension_list);
6212 LocalContext context(&extensions);
6213 v8_compile("gc();")->Run();
6214 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006215 CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006216 }
6217}
6218
6219
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00006220v8::Persistent<v8::Object> some_object;
6221v8::Persistent<v8::Object> bad_handle;
6222
6223void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
6224 v8::HandleScope scope;
6225 bad_handle = v8::Persistent<v8::Object>::New(some_object);
6226}
6227
6228
6229THREADED_TEST(NewPersistentHandleFromWeakCallback) {
6230 LocalContext context;
6231
6232 v8::Persistent<v8::Object> handle1, handle2;
6233 {
6234 v8::HandleScope scope;
6235 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
6236 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6237 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6238 }
6239 // Note: order is implementation dependent alas: currently
6240 // global handle nodes are processed by PostGarbageCollectionProcessing
6241 // in reverse allocation order, so if second allocated handle is deleted,
6242 // weak callback of the first handle would be able to 'reallocate' it.
6243 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
6244 handle2.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006245 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00006246}
6247
6248
6249v8::Persistent<v8::Object> to_be_disposed;
6250
6251void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
6252 to_be_disposed.Dispose();
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006253 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00006254}
6255
6256
6257THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
6258 LocalContext context;
6259
6260 v8::Persistent<v8::Object> handle1, handle2;
6261 {
6262 v8::HandleScope scope;
6263 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6264 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6265 }
6266 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
6267 to_be_disposed = handle2;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006268 i::Heap::CollectAllGarbage(false);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00006269}
6270
6271
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006272THREADED_TEST(CheckForCrossContextObjectLiterals) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006273 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006274
6275 const int nof = 2;
6276 const char* sources[nof] = {
6277 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
6278 "Object()"
6279 };
6280
6281 for (int i = 0; i < nof; i++) {
6282 const char* source = sources[i];
6283 { v8::HandleScope scope;
6284 LocalContext context;
6285 CompileRun(source);
6286 }
6287 { v8::HandleScope scope;
6288 LocalContext context;
6289 CompileRun(source);
6290 }
6291 }
6292}
6293
6294
6295static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
6296 v8::HandleScope inner;
6297 env->Enter();
6298 v8::Handle<Value> three = v8_num(3);
6299 v8::Handle<Value> value = inner.Close(three);
6300 env->Exit();
6301 return value;
6302}
6303
6304
6305THREADED_TEST(NestedHandleScopeAndContexts) {
6306 v8::HandleScope outer;
6307 v8::Persistent<Context> env = Context::New();
6308 env->Enter();
6309 v8::Handle<Value> value = NestedScope(env);
6310 v8::Handle<String> str = value->ToString();
6311 env->Exit();
6312 env.Dispose();
6313}
6314
6315
6316THREADED_TEST(ExternalAllocatedMemory) {
6317 v8::HandleScope outer;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006318 v8::Persistent<Context> env = Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006319 const int kSize = 1024*1024;
6320 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
6321 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
6322}
6323
6324
6325THREADED_TEST(DisposeEnteredContext) {
6326 v8::HandleScope scope;
6327 LocalContext outer;
6328 { v8::Persistent<v8::Context> inner = v8::Context::New();
6329 inner->Enter();
6330 inner.Dispose();
6331 inner.Clear();
6332 inner->Exit();
6333 }
6334}
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006335
6336
6337// Regression test for issue 54, object templates with internal fields
6338// but no accessors or interceptors did not get their internal field
6339// count set on instances.
6340THREADED_TEST(Regress54) {
6341 v8::HandleScope outer;
6342 LocalContext context;
6343 static v8::Persistent<v8::ObjectTemplate> templ;
6344 if (templ.IsEmpty()) {
6345 v8::HandleScope inner;
6346 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
6347 local->SetInternalFieldCount(1);
6348 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
6349 }
6350 v8::Handle<v8::Object> result = templ->NewInstance();
6351 CHECK_EQ(1, result->InternalFieldCount());
6352}
6353
6354
6355// If part of the threaded tests, this test makes ThreadingTest fail
6356// on mac.
6357TEST(CatchStackOverflow) {
6358 v8::HandleScope scope;
6359 LocalContext context;
6360 v8::TryCatch try_catch;
6361 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
6362 "function f() {"
6363 " return f();"
6364 "}"
6365 ""
6366 "f();"));
6367 v8::Handle<v8::Value> result = script->Run();
6368 CHECK(result.IsEmpty());
6369}
6370
6371
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006372static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
6373 const char* resource_name,
6374 int line_offset) {
6375 v8::HandleScope scope;
6376 v8::TryCatch try_catch;
6377 v8::Handle<v8::Value> result = script->Run();
6378 CHECK(result.IsEmpty());
6379 CHECK(try_catch.HasCaught());
6380 v8::Handle<v8::Message> message = try_catch.Message();
6381 CHECK(!message.IsEmpty());
6382 CHECK_EQ(10 + line_offset, message->GetLineNumber());
6383 CHECK_EQ(91, message->GetStartPosition());
6384 CHECK_EQ(92, message->GetEndPosition());
6385 CHECK_EQ(2, message->GetStartColumn());
6386 CHECK_EQ(3, message->GetEndColumn());
6387 v8::String::AsciiValue line(message->GetSourceLine());
6388 CHECK_EQ(" throw 'nirk';", *line);
6389 v8::String::AsciiValue name(message->GetScriptResourceName());
6390 CHECK_EQ(resource_name, *name);
6391}
6392
6393
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006394THREADED_TEST(TryCatchSourceInfo) {
6395 v8::HandleScope scope;
6396 LocalContext context;
6397 v8::Handle<v8::String> source = v8::String::New(
6398 "function Foo() {\n"
6399 " return Bar();\n"
6400 "}\n"
6401 "\n"
6402 "function Bar() {\n"
6403 " return Baz();\n"
6404 "}\n"
6405 "\n"
6406 "function Baz() {\n"
6407 " throw 'nirk';\n"
6408 "}\n"
6409 "\n"
6410 "Foo();\n");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006411
6412 const char* resource_name;
6413 v8::Handle<v8::Script> script;
6414 resource_name = "test.js";
6415 script = v8::Script::Compile(source, v8::String::New(resource_name));
6416 CheckTryCatchSourceInfo(script, resource_name, 0);
6417
6418 resource_name = "test1.js";
6419 v8::ScriptOrigin origin1(v8::String::New(resource_name));
6420 script = v8::Script::Compile(source, &origin1);
6421 CheckTryCatchSourceInfo(script, resource_name, 0);
6422
6423 resource_name = "test2.js";
6424 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
6425 script = v8::Script::Compile(source, &origin2);
6426 CheckTryCatchSourceInfo(script, resource_name, 7);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006427}
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006428
6429
6430THREADED_TEST(CompilationCache) {
6431 v8::HandleScope scope;
6432 LocalContext context;
6433 v8::Handle<v8::String> source0 = v8::String::New("1234");
6434 v8::Handle<v8::String> source1 = v8::String::New("1234");
6435 v8::Handle<v8::Script> script0 =
6436 v8::Script::Compile(source0, v8::String::New("test.js"));
6437 v8::Handle<v8::Script> script1 =
6438 v8::Script::Compile(source1, v8::String::New("test.js"));
6439 v8::Handle<v8::Script> script2 =
6440 v8::Script::Compile(source0); // different origin
6441 CHECK_EQ(1234, script0->Run()->Int32Value());
6442 CHECK_EQ(1234, script1->Run()->Int32Value());
6443 CHECK_EQ(1234, script2->Run()->Int32Value());
6444}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006445
6446
6447static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
6448 ApiTestFuzzer::Fuzz();
6449 return v8_num(42);
6450}
6451
6452
6453THREADED_TEST(CallbackFunctionName) {
6454 v8::HandleScope scope;
6455 LocalContext context;
6456 Local<ObjectTemplate> t = ObjectTemplate::New();
6457 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
6458 context->Global()->Set(v8_str("obj"), t->NewInstance());
6459 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
6460 CHECK(value->IsString());
6461 v8::String::AsciiValue name(value);
6462 CHECK_EQ("asdf", *name);
6463}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006464
6465
6466THREADED_TEST(DateAccess) {
6467 v8::HandleScope scope;
6468 LocalContext context;
6469 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
6470 CHECK(date->IsDate());
6471 CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
6472}
6473
6474
6475void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
6476 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
6477 v8::Handle<v8::Array> props = obj->GetPropertyNames();
6478 CHECK_EQ(elmc, props->Length());
6479 for (int i = 0; i < elmc; i++) {
6480 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
6481 CHECK_EQ(elmv[i], *elm);
6482 }
6483}
6484
6485
6486THREADED_TEST(PropertyEnumeration) {
6487 v8::HandleScope scope;
6488 LocalContext context;
6489 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
6490 "var result = [];"
6491 "result[0] = {};"
6492 "result[1] = {a: 1, b: 2};"
6493 "result[2] = [1, 2, 3];"
6494 "var proto = {x: 1, y: 2, z: 3};"
6495 "var x = { __proto__: proto, w: 0, z: 1 };"
6496 "result[3] = x;"
6497 "result;"))->Run();
6498 v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
6499 CHECK_EQ(4, elms->Length());
6500 int elmc0 = 0;
6501 const char** elmv0 = NULL;
6502 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
6503 int elmc1 = 2;
6504 const char* elmv1[] = {"a", "b"};
6505 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
6506 int elmc2 = 3;
6507 const char* elmv2[] = {"0", "1", "2"};
6508 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
6509 int elmc3 = 4;
6510 const char* elmv3[] = {"w", "z", "x", "y"};
6511 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
6512}
ager@chromium.org870a0b62008-11-04 11:43:05 +00006513
6514
6515static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
6516 Local<String> name,
6517 const AccessorInfo& info) {
6518 ApiTestFuzzer::Fuzz();
6519 return v8::True();
6520}
6521
6522
6523THREADED_TEST(AccessorProhibitsOverwriting) {
6524 v8::HandleScope scope;
6525 LocalContext context;
6526 Local<ObjectTemplate> templ = ObjectTemplate::New();
6527 templ->SetAccessor(v8_str("x"),
6528 AccessorProhibitsOverwritingGetter,
6529 0,
6530 v8::Handle<Value>(),
6531 v8::PROHIBITS_OVERWRITING,
6532 v8::ReadOnly);
6533 Local<v8::Object> instance = templ->NewInstance();
6534 context->Global()->Set(v8_str("obj"), instance);
6535 Local<Value> value = CompileRun(
6536 "obj.__defineGetter__('x', function() { return false; });"
6537 "obj.x");
6538 CHECK(value->BooleanValue());
6539 value = CompileRun(
6540 "var setter_called = false;"
6541 "obj.__defineSetter__('x', function() { setter_called = true; });"
6542 "obj.x = 42;"
6543 "setter_called");
6544 CHECK(!value->BooleanValue());
6545 value = CompileRun(
6546 "obj2 = {};"
6547 "obj2.__proto__ = obj;"
6548 "obj2.__defineGetter__('x', function() { return false; });"
6549 "obj2.x");
6550 CHECK(value->BooleanValue());
6551 value = CompileRun(
6552 "var setter_called = false;"
6553 "obj2 = {};"
6554 "obj2.__proto__ = obj;"
6555 "obj2.__defineSetter__('x', function() { setter_called = true; });"
6556 "obj2.x = 42;"
6557 "setter_called");
6558 CHECK(!value->BooleanValue());
6559}
6560
6561
6562static bool NamedSetAccessBlocker(Local<v8::Object> obj,
6563 Local<Value> name,
6564 v8::AccessType type,
6565 Local<Value> data) {
6566 return type != v8::ACCESS_SET;
6567}
6568
6569
6570static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
6571 uint32_t key,
6572 v8::AccessType type,
6573 Local<Value> data) {
6574 return type != v8::ACCESS_SET;
6575}
6576
6577
6578THREADED_TEST(DisableAccessChecksWhileConfiguring) {
6579 v8::HandleScope scope;
6580 LocalContext context;
6581 Local<ObjectTemplate> templ = ObjectTemplate::New();
6582 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6583 IndexedSetAccessBlocker);
6584 templ->Set(v8_str("x"), v8::True());
6585 Local<v8::Object> instance = templ->NewInstance();
6586 context->Global()->Set(v8_str("obj"), instance);
6587 Local<Value> value = CompileRun("obj.x");
6588 CHECK(value->BooleanValue());
6589}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006590
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006591
ager@chromium.org32912102009-01-16 10:38:43 +00006592static bool NamedGetAccessBlocker(Local<v8::Object> obj,
6593 Local<Value> name,
6594 v8::AccessType type,
6595 Local<Value> data) {
6596 return false;
6597}
6598
6599
6600static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
6601 uint32_t key,
6602 v8::AccessType type,
6603 Local<Value> data) {
6604 return false;
6605}
6606
6607
6608
6609THREADED_TEST(AccessChecksReenabledCorrectly) {
6610 v8::HandleScope scope;
6611 LocalContext context;
6612 Local<ObjectTemplate> templ = ObjectTemplate::New();
6613 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6614 IndexedGetAccessBlocker);
6615 templ->Set(v8_str("a"), v8_str("a"));
6616 // Add more than 8 (see kMaxFastProperties) properties
6617 // so that the constructor will force copying map.
6618 // Cannot sprintf, gcc complains unsafety.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006619 char buf[4];
ager@chromium.org32912102009-01-16 10:38:43 +00006620 for (char i = '0'; i <= '9' ; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006621 buf[0] = i;
ager@chromium.org32912102009-01-16 10:38:43 +00006622 for (char j = '0'; j <= '9'; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006623 buf[1] = j;
ager@chromium.org32912102009-01-16 10:38:43 +00006624 for (char k = '0'; k <= '9'; k++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006625 buf[2] = k;
6626 buf[3] = 0;
ager@chromium.org32912102009-01-16 10:38:43 +00006627 templ->Set(v8_str(buf), v8::Number::New(k));
6628 }
6629 }
6630 }
6631
6632 Local<v8::Object> instance_1 = templ->NewInstance();
6633 context->Global()->Set(v8_str("obj_1"), instance_1);
6634
6635 Local<Value> value_1 = CompileRun("obj_1.a");
6636 CHECK(value_1->IsUndefined());
6637
6638 Local<v8::Object> instance_2 = templ->NewInstance();
6639 context->Global()->Set(v8_str("obj_2"), instance_2);
6640
6641 Local<Value> value_2 = CompileRun("obj_2.a");
6642 CHECK(value_2->IsUndefined());
6643}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006644
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006645
ager@chromium.org8bb60582008-12-11 12:02:20 +00006646// This tests that access check information remains on the global
6647// object template when creating contexts.
6648THREADED_TEST(AccessControlRepeatedContextCreation) {
6649 v8::HandleScope handle_scope;
6650 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6651 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6652 IndexedSetAccessBlocker);
6653 i::Handle<i::ObjectTemplateInfo> internal_template =
6654 v8::Utils::OpenHandle(*global_template);
6655 CHECK(!internal_template->constructor()->IsUndefined());
6656 i::Handle<i::FunctionTemplateInfo> constructor(
6657 i::FunctionTemplateInfo::cast(internal_template->constructor()));
6658 CHECK(!constructor->access_check_info()->IsUndefined());
6659 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6660 CHECK(!constructor->access_check_info()->IsUndefined());
6661}
6662
6663
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006664THREADED_TEST(TurnOnAccessCheck) {
6665 v8::HandleScope handle_scope;
6666
6667 // Create an environment with access check to the global object disabled by
6668 // default.
6669 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6670 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6671 IndexedGetAccessBlocker,
6672 v8::Handle<v8::Value>(),
6673 false);
6674 v8::Persistent<Context> context = Context::New(NULL, global_template);
6675 Context::Scope context_scope(context);
6676
6677 // Set up a property and a number of functions.
6678 context->Global()->Set(v8_str("a"), v8_num(1));
6679 CompileRun("function f1() {return a;}"
6680 "function f2() {return a;}"
6681 "function g1() {return h();}"
6682 "function g2() {return h();}"
6683 "function h() {return 1;}");
6684 Local<Function> f1 =
6685 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
6686 Local<Function> f2 =
6687 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
6688 Local<Function> g1 =
6689 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
6690 Local<Function> g2 =
6691 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
6692 Local<Function> h =
6693 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
6694
6695 // Get the global object.
6696 v8::Handle<v8::Object> global = context->Global();
6697
6698 // Call f1 one time and f2 a number of times. This will ensure that f1 still
6699 // uses the runtime system to retreive property a whereas f2 uses global load
6700 // inline cache.
6701 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
6702 for (int i = 0; i < 4; i++) {
6703 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
6704 }
6705
6706 // Same for g1 and g2.
6707 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
6708 for (int i = 0; i < 4; i++) {
6709 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
6710 }
6711
6712 // Detach the global and turn on access check.
6713 context->DetachGlobal();
6714 context->Global()->TurnOnAccessCheck();
6715
6716 // Failing access check to property get results in undefined.
6717 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
6718 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
6719
6720 // Failing access check to function call results in exception.
6721 CHECK(g1->Call(global, 0, NULL).IsEmpty());
6722 CHECK(g2->Call(global, 0, NULL).IsEmpty());
6723
6724 // No failing access check when just returning a constant.
6725 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
6726}
6727
6728
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006729// This test verifies that pre-compilation (aka preparsing) can be called
6730// without initializing the whole VM. Thus we cannot run this test in a
6731// multi-threaded setup.
6732TEST(PreCompile) {
6733 // TODO(155): This test would break without the initialization of V8. This is
6734 // a workaround for now to make this test not fail.
6735 v8::V8::Initialize();
6736 const char *script = "function foo(a) { return a+1; }";
6737 v8::ScriptData *sd = v8::ScriptData::PreCompile(script, strlen(script));
6738 CHECK_NE(sd->Length(), 0);
6739 CHECK_NE(sd->Data(), NULL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006740 delete sd;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006741}
6742
6743
6744// This tests that we do not allow dictionary load/call inline caches
6745// to use functions that have not yet been compiled. The potential
6746// problem of loading a function that has not yet been compiled can
6747// arise because we share code between contexts via the compilation
6748// cache.
6749THREADED_TEST(DictionaryICLoadedFunction) {
6750 v8::HandleScope scope;
6751 // Test LoadIC.
6752 for (int i = 0; i < 2; i++) {
6753 LocalContext context;
6754 context->Global()->Set(v8_str("tmp"), v8::True());
6755 context->Global()->Delete(v8_str("tmp"));
6756 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
6757 }
6758 // Test CallIC.
6759 for (int i = 0; i < 2; i++) {
6760 LocalContext context;
6761 context->Global()->Set(v8_str("tmp"), v8::True());
6762 context->Global()->Delete(v8_str("tmp"));
6763 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
6764 }
6765}
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006766
6767
6768// Test that cross-context new calls use the context of the callee to
6769// create the new JavaScript object.
6770THREADED_TEST(CrossContextNew) {
6771 v8::HandleScope scope;
6772 v8::Persistent<Context> context0 = Context::New();
6773 v8::Persistent<Context> context1 = Context::New();
6774
6775 // Allow cross-domain access.
6776 Local<String> token = v8_str("<security token>");
6777 context0->SetSecurityToken(token);
6778 context1->SetSecurityToken(token);
6779
6780 // Set an 'x' property on the Object prototype and define a
6781 // constructor function in context0.
6782 context0->Enter();
6783 CompileRun("Object.prototype.x = 42; function C() {};");
6784 context0->Exit();
6785
6786 // Call the constructor function from context0 and check that the
6787 // result has the 'x' property.
6788 context1->Enter();
6789 context1->Global()->Set(v8_str("other"), context0->Global());
6790 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
6791 CHECK(value->IsInt32());
6792 CHECK_EQ(42, value->Int32Value());
6793 context1->Exit();
6794
6795 // Dispose the contexts to allow them to be garbage collected.
6796 context0.Dispose();
6797 context1.Dispose();
6798}
ager@chromium.org381abbb2009-02-25 13:23:22 +00006799
6800
6801class RegExpInterruptTest {
6802 public:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006803 RegExpInterruptTest() : block_(NULL) {}
6804 ~RegExpInterruptTest() { delete block_; }
ager@chromium.org381abbb2009-02-25 13:23:22 +00006805 void RunTest() {
6806 block_ = i::OS::CreateSemaphore(0);
6807 gc_count_ = 0;
6808 gc_during_regexp_ = 0;
6809 regexp_success_ = false;
6810 gc_success_ = false;
6811 GCThread gc_thread(this);
6812 gc_thread.Start();
6813 v8::Locker::StartPreemption(1);
6814
6815 LongRunningRegExp();
6816 {
6817 v8::Unlocker unlock;
6818 gc_thread.Join();
6819 }
6820 v8::Locker::StopPreemption();
6821 CHECK(regexp_success_);
6822 CHECK(gc_success_);
6823 }
6824 private:
6825 // Number of garbage collections required.
6826 static const int kRequiredGCs = 5;
6827
6828 class GCThread : public i::Thread {
6829 public:
6830 explicit GCThread(RegExpInterruptTest* test)
6831 : test_(test) {}
6832 virtual void Run() {
6833 test_->CollectGarbage();
6834 }
6835 private:
6836 RegExpInterruptTest* test_;
6837 };
6838
6839 void CollectGarbage() {
6840 block_->Wait();
6841 while (gc_during_regexp_ < kRequiredGCs) {
6842 {
6843 v8::Locker lock;
6844 // TODO(lrn): Perhaps create some garbage before collecting.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006845 i::Heap::CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +00006846 gc_count_++;
6847 }
6848 i::OS::Sleep(1);
6849 }
6850 gc_success_ = true;
6851 }
6852
6853 void LongRunningRegExp() {
6854 block_->Signal(); // Enable garbage collection thread on next preemption.
6855 int rounds = 0;
6856 while (gc_during_regexp_ < kRequiredGCs) {
6857 int gc_before = gc_count_;
6858 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006859 // Match 15-30 "a"'s against 14 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00006860 const char* c_source =
6861 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6862 ".exec('aaaaaaaaaaaaaaab') === null";
6863 Local<String> source = String::New(c_source);
6864 Local<Script> script = Script::Compile(source);
6865 Local<Value> result = script->Run();
6866 if (!result->BooleanValue()) {
6867 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
6868 return;
6869 }
6870 }
6871 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006872 // Match 15-30 "a"'s against 15 and a "b".
ager@chromium.org381abbb2009-02-25 13:23:22 +00006873 const char* c_source =
6874 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6875 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
6876 Local<String> source = String::New(c_source);
6877 Local<Script> script = Script::Compile(source);
6878 Local<Value> result = script->Run();
6879 if (!result->BooleanValue()) {
6880 gc_during_regexp_ = kRequiredGCs;
6881 return;
6882 }
6883 }
6884 int gc_after = gc_count_;
6885 gc_during_regexp_ += gc_after - gc_before;
6886 rounds++;
6887 i::OS::Sleep(1);
6888 }
6889 regexp_success_ = true;
6890 }
6891
6892 i::Semaphore* block_;
6893 int gc_count_;
6894 int gc_during_regexp_;
6895 bool regexp_success_;
6896 bool gc_success_;
6897};
6898
6899
6900// Test that a regular expression execution can be interrupted and
6901// survive a garbage collection.
6902TEST(RegExpInterruption) {
6903 v8::Locker lock;
6904 v8::V8::Initialize();
6905 v8::HandleScope scope;
6906 Local<Context> local_env;
6907 {
6908 LocalContext env;
6909 local_env = env.local();
6910 }
6911
6912 // Local context should still be live.
6913 CHECK(!local_env.IsEmpty());
6914 local_env->Enter();
6915
6916 // Should complete without problems.
6917 RegExpInterruptTest().RunTest();
6918
6919 local_env->Exit();
6920}
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006921
6922
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006923class ApplyInterruptTest {
6924 public:
6925 ApplyInterruptTest() : block_(NULL) {}
6926 ~ApplyInterruptTest() { delete block_; }
6927 void RunTest() {
6928 block_ = i::OS::CreateSemaphore(0);
6929 gc_count_ = 0;
6930 gc_during_apply_ = 0;
6931 apply_success_ = false;
6932 gc_success_ = false;
6933 GCThread gc_thread(this);
6934 gc_thread.Start();
6935 v8::Locker::StartPreemption(1);
6936
6937 LongRunningApply();
6938 {
6939 v8::Unlocker unlock;
6940 gc_thread.Join();
6941 }
6942 v8::Locker::StopPreemption();
6943 CHECK(apply_success_);
6944 CHECK(gc_success_);
6945 }
6946 private:
6947 // Number of garbage collections required.
6948 static const int kRequiredGCs = 2;
6949
6950 class GCThread : public i::Thread {
6951 public:
6952 explicit GCThread(ApplyInterruptTest* test)
6953 : test_(test) {}
6954 virtual void Run() {
6955 test_->CollectGarbage();
6956 }
6957 private:
6958 ApplyInterruptTest* test_;
6959 };
6960
6961 void CollectGarbage() {
6962 block_->Wait();
6963 while (gc_during_apply_ < kRequiredGCs) {
6964 {
6965 v8::Locker lock;
ager@chromium.orgab99eea2009-08-25 07:05:41 +00006966 i::Heap::CollectAllGarbage(false);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006967 gc_count_++;
6968 }
6969 i::OS::Sleep(1);
6970 }
6971 gc_success_ = true;
6972 }
6973
6974 void LongRunningApply() {
6975 block_->Signal();
6976 int rounds = 0;
6977 while (gc_during_apply_ < kRequiredGCs) {
6978 int gc_before = gc_count_;
6979 {
6980 const char* c_source =
6981 "function do_very_little(bar) {"
6982 " this.foo = bar;"
6983 "}"
6984 "for (var i = 0; i < 100000; i++) {"
6985 " do_very_little.apply(this, ['bar']);"
6986 "}";
6987 Local<String> source = String::New(c_source);
6988 Local<Script> script = Script::Compile(source);
6989 Local<Value> result = script->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00006990 // Check that no exception was thrown.
6991 CHECK(!result.IsEmpty());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006992 }
6993 int gc_after = gc_count_;
6994 gc_during_apply_ += gc_after - gc_before;
6995 rounds++;
6996 }
6997 apply_success_ = true;
6998 }
6999
7000 i::Semaphore* block_;
7001 int gc_count_;
7002 int gc_during_apply_;
7003 bool apply_success_;
7004 bool gc_success_;
7005};
7006
7007
7008// Test that nothing bad happens if we get a preemption just when we were
7009// about to do an apply().
7010TEST(ApplyInterruption) {
7011 v8::Locker lock;
7012 v8::V8::Initialize();
7013 v8::HandleScope scope;
7014 Local<Context> local_env;
7015 {
7016 LocalContext env;
7017 local_env = env.local();
7018 }
7019
7020 // Local context should still be live.
7021 CHECK(!local_env.IsEmpty());
7022 local_env->Enter();
7023
7024 // Should complete without problems.
7025 ApplyInterruptTest().RunTest();
7026
7027 local_env->Exit();
7028}
7029
7030
ager@chromium.org3b45ab52009-03-19 22:21:34 +00007031// Verify that we can clone an object
7032TEST(ObjectClone) {
7033 v8::HandleScope scope;
7034 LocalContext env;
7035
7036 const char* sample =
7037 "var rv = {};" \
7038 "rv.alpha = 'hello';" \
7039 "rv.beta = 123;" \
7040 "rv;";
7041
7042 // Create an object, verify basics.
7043 Local<Value> val = CompileRun(sample);
7044 CHECK(val->IsObject());
7045 Local<v8::Object> obj = Local<v8::Object>::Cast(val);
7046 obj->Set(v8_str("gamma"), v8_str("cloneme"));
7047
7048 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
7049 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7050 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
7051
7052 // Clone it.
7053 Local<v8::Object> clone = obj->Clone();
7054 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
7055 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
7056 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
7057
7058 // Set a property on the clone, verify each object.
7059 clone->Set(v8_str("beta"), v8::Integer::New(456));
7060 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7061 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
7062}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007063
7064
ager@chromium.org5ec48922009-05-05 07:25:34 +00007065class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
7066 public:
7067 explicit AsciiVectorResource(i::Vector<const char> vector)
7068 : data_(vector) {}
7069 virtual ~AsciiVectorResource() {}
7070 virtual size_t length() const { return data_.length(); }
7071 virtual const char* data() const { return data_.start(); }
7072 private:
7073 i::Vector<const char> data_;
7074};
7075
7076
7077class UC16VectorResource : public v8::String::ExternalStringResource {
7078 public:
7079 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
7080 : data_(vector) {}
7081 virtual ~UC16VectorResource() {}
7082 virtual size_t length() const { return data_.length(); }
7083 virtual const i::uc16* data() const { return data_.start(); }
7084 private:
7085 i::Vector<const i::uc16> data_;
7086};
7087
7088
7089static void MorphAString(i::String* string,
7090 AsciiVectorResource* ascii_resource,
7091 UC16VectorResource* uc16_resource) {
7092 CHECK(i::StringShape(string).IsExternal());
7093 if (string->IsAsciiRepresentation()) {
7094 // Check old map is not symbol or long.
7095 CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
7096 string->map() == i::Heap::medium_external_ascii_string_map());
7097 // Morph external string to be TwoByte string.
7098 if (string->length() <= i::String::kMaxShortStringSize) {
7099 string->set_map(i::Heap::short_external_string_map());
7100 } else {
7101 string->set_map(i::Heap::medium_external_string_map());
7102 }
7103 i::ExternalTwoByteString* morphed =
7104 i::ExternalTwoByteString::cast(string);
7105 morphed->set_resource(uc16_resource);
7106 } else {
7107 // Check old map is not symbol or long.
7108 CHECK(string->map() == i::Heap::short_external_string_map() ||
7109 string->map() == i::Heap::medium_external_string_map());
7110 // Morph external string to be ASCII string.
7111 if (string->length() <= i::String::kMaxShortStringSize) {
7112 string->set_map(i::Heap::short_external_ascii_string_map());
7113 } else {
7114 string->set_map(i::Heap::medium_external_ascii_string_map());
7115 }
7116 i::ExternalAsciiString* morphed =
7117 i::ExternalAsciiString::cast(string);
7118 morphed->set_resource(ascii_resource);
7119 }
7120}
7121
7122
7123// Test that we can still flatten a string if the components it is built up
7124// from have been turned into 16 bit strings in the mean time.
7125THREADED_TEST(MorphCompositeStringTest) {
7126 const char* c_string = "Now is the time for all good men"
7127 " to come to the aid of the party";
7128 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
7129 {
7130 v8::HandleScope scope;
7131 LocalContext env;
7132 AsciiVectorResource ascii_resource(
7133 i::Vector<const char>(c_string, strlen(c_string)));
7134 UC16VectorResource uc16_resource(
7135 i::Vector<const uint16_t>(two_byte_string, strlen(c_string)));
7136
7137 Local<String> lhs(v8::Utils::ToLocal(
7138 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7139 Local<String> rhs(v8::Utils::ToLocal(
7140 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7141
7142 env->Global()->Set(v8_str("lhs"), lhs);
7143 env->Global()->Set(v8_str("rhs"), rhs);
7144
7145 CompileRun(
7146 "var cons = lhs + rhs;"
7147 "var slice = lhs.substring(1, lhs.length - 1);"
7148 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
7149
7150 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
7151 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
7152
7153 // Now do some stuff to make sure the strings are flattened, etc.
7154 CompileRun(
7155 "/[^a-z]/.test(cons);"
7156 "/[^a-z]/.test(slice);"
7157 "/[^a-z]/.test(slice_on_cons);");
7158 const char* expected_cons =
7159 "Now is the time for all good men to come to the aid of the party"
7160 "Now is the time for all good men to come to the aid of the party";
7161 const char* expected_slice =
7162 "ow is the time for all good men to come to the aid of the part";
7163 const char* expected_slice_on_cons =
7164 "ow is the time for all good men to come to the aid of the party"
7165 "Now is the time for all good men to come to the aid of the part";
7166 CHECK_EQ(String::New(expected_cons),
7167 env->Global()->Get(v8_str("cons")));
7168 CHECK_EQ(String::New(expected_slice),
7169 env->Global()->Get(v8_str("slice")));
7170 CHECK_EQ(String::New(expected_slice_on_cons),
7171 env->Global()->Get(v8_str("slice_on_cons")));
7172 }
7173}
7174
7175
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00007176TEST(CompileExternalTwoByteSource) {
7177 v8::HandleScope scope;
7178 LocalContext context;
7179
7180 // This is a very short list of sources, which currently is to check for a
7181 // regression caused by r2703.
7182 const char* ascii_sources[] = {
7183 "0.5",
7184 "-0.5", // This mainly testes PushBack in the Scanner.
7185 "--0.5", // This mainly testes PushBack in the Scanner.
7186 NULL
7187 };
7188
7189 // Compile the sources as external two byte strings.
7190 for (int i = 0; ascii_sources[i] != NULL; i++) {
7191 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
7192 UC16VectorResource uc16_resource(
7193 i::Vector<const uint16_t>(two_byte_string, strlen(ascii_sources[i])));
7194 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
7195 v8::Script::Compile(source);
7196 }
7197}
7198
7199
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007200class RegExpStringModificationTest {
7201 public:
7202 RegExpStringModificationTest()
7203 : block_(i::OS::CreateSemaphore(0)),
7204 morphs_(0),
7205 morphs_during_regexp_(0),
7206 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
7207 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
7208 ~RegExpStringModificationTest() { delete block_; }
7209 void RunTest() {
7210 regexp_success_ = false;
7211 morph_success_ = false;
7212
7213 // Initialize the contents of two_byte_content_ to be a uc16 representation
7214 // of "aaaaaaaaaaaaaab".
7215 for (int i = 0; i < 14; i++) {
7216 two_byte_content_[i] = 'a';
7217 }
7218 two_byte_content_[14] = 'b';
7219
7220 // Create the input string for the regexp - the one we are going to change
7221 // properties of.
7222 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
7223
7224 // Inject the input as a global variable.
7225 i::Handle<i::String> input_name =
7226 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
7227 i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
7228
7229
7230 MorphThread morph_thread(this);
7231 morph_thread.Start();
7232 v8::Locker::StartPreemption(1);
7233 LongRunningRegExp();
7234 {
7235 v8::Unlocker unlock;
7236 morph_thread.Join();
7237 }
7238 v8::Locker::StopPreemption();
7239 CHECK(regexp_success_);
7240 CHECK(morph_success_);
7241 }
7242 private:
7243
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007244 // Number of string modifications required.
7245 static const int kRequiredModifications = 5;
7246 static const int kMaxModifications = 100;
7247
7248 class MorphThread : public i::Thread {
7249 public:
7250 explicit MorphThread(RegExpStringModificationTest* test)
7251 : test_(test) {}
7252 virtual void Run() {
7253 test_->MorphString();
7254 }
7255 private:
7256 RegExpStringModificationTest* test_;
7257 };
7258
7259 void MorphString() {
7260 block_->Wait();
7261 while (morphs_during_regexp_ < kRequiredModifications &&
7262 morphs_ < kMaxModifications) {
7263 {
7264 v8::Locker lock;
7265 // Swap string between ascii and two-byte representation.
7266 i::String* string = *input_;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007267 MorphAString(string, &ascii_resource_, &uc16_resource_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007268 morphs_++;
7269 }
7270 i::OS::Sleep(1);
7271 }
7272 morph_success_ = true;
7273 }
7274
7275 void LongRunningRegExp() {
7276 block_->Signal(); // Enable morphing thread on next preemption.
7277 while (morphs_during_regexp_ < kRequiredModifications &&
7278 morphs_ < kMaxModifications) {
7279 int morphs_before = morphs_;
7280 {
7281 // Match 15-30 "a"'s against 14 and a "b".
7282 const char* c_source =
7283 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7284 ".exec(input) === null";
7285 Local<String> source = String::New(c_source);
7286 Local<Script> script = Script::Compile(source);
7287 Local<Value> result = script->Run();
7288 CHECK(result->IsTrue());
7289 }
7290 int morphs_after = morphs_;
7291 morphs_during_regexp_ += morphs_after - morphs_before;
7292 }
7293 regexp_success_ = true;
7294 }
7295
7296 i::uc16 two_byte_content_[15];
7297 i::Semaphore* block_;
7298 int morphs_;
7299 int morphs_during_regexp_;
7300 bool regexp_success_;
7301 bool morph_success_;
7302 i::Handle<i::String> input_;
7303 AsciiVectorResource ascii_resource_;
7304 UC16VectorResource uc16_resource_;
7305};
7306
7307
7308// Test that a regular expression execution can be interrupted and
7309// the string changed without failing.
7310TEST(RegExpStringModification) {
7311 v8::Locker lock;
7312 v8::V8::Initialize();
7313 v8::HandleScope scope;
7314 Local<Context> local_env;
7315 {
7316 LocalContext env;
7317 local_env = env.local();
7318 }
7319
7320 // Local context should still be live.
7321 CHECK(!local_env.IsEmpty());
7322 local_env->Enter();
7323
7324 // Should complete without problems.
7325 RegExpStringModificationTest().RunTest();
7326
7327 local_env->Exit();
7328}
7329
7330
7331// Test that we can set a property on the global object even if there
7332// is a read-only property in the prototype chain.
7333TEST(ReadOnlyPropertyInGlobalProto) {
7334 v8::HandleScope scope;
7335 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7336 LocalContext context(0, templ);
7337 v8::Handle<v8::Object> global = context->Global();
7338 v8::Handle<v8::Object> global_proto =
7339 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
7340 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
7341 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
7342 // Check without 'eval' or 'with'.
7343 v8::Handle<v8::Value> res =
7344 CompileRun("function f() { x = 42; return x; }; f()");
7345 // Check with 'eval'.
7346 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
7347 CHECK_EQ(v8::Integer::New(42), res);
7348 // Check with 'with'.
7349 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
7350 CHECK_EQ(v8::Integer::New(42), res);
7351}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007352
7353static int force_set_set_count = 0;
7354static int force_set_get_count = 0;
7355bool pass_on_get = false;
7356
7357static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
7358 const v8::AccessorInfo& info) {
7359 force_set_get_count++;
7360 if (pass_on_get) {
7361 return v8::Handle<v8::Value>();
7362 } else {
7363 return v8::Int32::New(3);
7364 }
7365}
7366
7367static void ForceSetSetter(v8::Local<v8::String> name,
7368 v8::Local<v8::Value> value,
7369 const v8::AccessorInfo& info) {
7370 force_set_set_count++;
7371}
7372
7373static v8::Handle<v8::Value> ForceSetInterceptSetter(
7374 v8::Local<v8::String> name,
7375 v8::Local<v8::Value> value,
7376 const v8::AccessorInfo& info) {
7377 force_set_set_count++;
7378 return v8::Undefined();
7379}
7380
7381TEST(ForceSet) {
7382 force_set_get_count = 0;
7383 force_set_set_count = 0;
7384 pass_on_get = false;
7385
7386 v8::HandleScope scope;
7387 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7388 v8::Handle<v8::String> access_property = v8::String::New("a");
7389 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
7390 LocalContext context(NULL, templ);
7391 v8::Handle<v8::Object> global = context->Global();
7392
7393 // Ordinary properties
7394 v8::Handle<v8::String> simple_property = v8::String::New("p");
7395 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
7396 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7397 // This should fail because the property is read-only
7398 global->Set(simple_property, v8::Int32::New(5));
7399 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7400 // This should succeed even though the property is read-only
7401 global->ForceSet(simple_property, v8::Int32::New(6));
7402 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
7403
7404 // Accessors
7405 CHECK_EQ(0, force_set_set_count);
7406 CHECK_EQ(0, force_set_get_count);
7407 CHECK_EQ(3, global->Get(access_property)->Int32Value());
7408 // CHECK_EQ the property shouldn't override it, just call the setter
7409 // which in this case does nothing.
7410 global->Set(access_property, v8::Int32::New(7));
7411 CHECK_EQ(3, global->Get(access_property)->Int32Value());
7412 CHECK_EQ(1, force_set_set_count);
7413 CHECK_EQ(2, force_set_get_count);
7414 // Forcing the property to be set should override the accessor without
7415 // calling it
7416 global->ForceSet(access_property, v8::Int32::New(8));
7417 CHECK_EQ(8, global->Get(access_property)->Int32Value());
7418 CHECK_EQ(1, force_set_set_count);
7419 CHECK_EQ(2, force_set_get_count);
7420}
7421
7422TEST(ForceSetWithInterceptor) {
7423 force_set_get_count = 0;
7424 force_set_set_count = 0;
7425 pass_on_get = false;
7426
7427 v8::HandleScope scope;
7428 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7429 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
7430 LocalContext context(NULL, templ);
7431 v8::Handle<v8::Object> global = context->Global();
7432
7433 v8::Handle<v8::String> some_property = v8::String::New("a");
7434 CHECK_EQ(0, force_set_set_count);
7435 CHECK_EQ(0, force_set_get_count);
7436 CHECK_EQ(3, global->Get(some_property)->Int32Value());
7437 // Setting the property shouldn't override it, just call the setter
7438 // which in this case does nothing.
7439 global->Set(some_property, v8::Int32::New(7));
7440 CHECK_EQ(3, global->Get(some_property)->Int32Value());
7441 CHECK_EQ(1, force_set_set_count);
7442 CHECK_EQ(2, force_set_get_count);
7443 // Getting the property when the interceptor returns an empty handle
7444 // should yield undefined, since the property isn't present on the
7445 // object itself yet.
7446 pass_on_get = true;
7447 CHECK(global->Get(some_property)->IsUndefined());
7448 CHECK_EQ(1, force_set_set_count);
7449 CHECK_EQ(3, force_set_get_count);
7450 // Forcing the property to be set should cause the value to be
7451 // set locally without calling the interceptor.
7452 global->ForceSet(some_property, v8::Int32::New(8));
7453 CHECK_EQ(8, global->Get(some_property)->Int32Value());
7454 CHECK_EQ(1, force_set_set_count);
7455 CHECK_EQ(4, force_set_get_count);
7456 // Reenabling the interceptor should cause it to take precedence over
7457 // the property
7458 pass_on_get = false;
7459 CHECK_EQ(3, global->Get(some_property)->Int32Value());
7460 CHECK_EQ(1, force_set_set_count);
7461 CHECK_EQ(5, force_set_get_count);
7462 // The interceptor should also work for other properties
7463 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
7464 CHECK_EQ(1, force_set_set_count);
7465 CHECK_EQ(6, force_set_get_count);
7466}
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00007467
7468
ager@chromium.orge2902be2009-06-08 12:21:35 +00007469THREADED_TEST(ForceDelete) {
7470 v8::HandleScope scope;
7471 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7472 LocalContext context(NULL, templ);
7473 v8::Handle<v8::Object> global = context->Global();
7474
7475 // Ordinary properties
7476 v8::Handle<v8::String> simple_property = v8::String::New("p");
7477 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
7478 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7479 // This should fail because the property is dont-delete.
7480 CHECK(!global->Delete(simple_property));
7481 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7482 // This should succeed even though the property is dont-delete.
7483 CHECK(global->ForceDelete(simple_property));
7484 CHECK(global->Get(simple_property)->IsUndefined());
7485}
7486
7487
7488static int force_delete_interceptor_count = 0;
7489static bool pass_on_delete = false;
7490
7491
7492static v8::Handle<v8::Boolean> ForceDeleteDeleter(
7493 v8::Local<v8::String> name,
7494 const v8::AccessorInfo& info) {
7495 force_delete_interceptor_count++;
7496 if (pass_on_delete) {
7497 return v8::Handle<v8::Boolean>();
7498 } else {
7499 return v8::True();
7500 }
7501}
7502
7503
7504THREADED_TEST(ForceDeleteWithInterceptor) {
7505 force_delete_interceptor_count = 0;
7506 pass_on_delete = false;
7507
7508 v8::HandleScope scope;
7509 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7510 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
7511 LocalContext context(NULL, templ);
7512 v8::Handle<v8::Object> global = context->Global();
7513
7514 v8::Handle<v8::String> some_property = v8::String::New("a");
7515 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
7516
7517 // Deleting a property should get intercepted and nothing should
7518 // happen.
7519 CHECK_EQ(0, force_delete_interceptor_count);
7520 CHECK(global->Delete(some_property));
7521 CHECK_EQ(1, force_delete_interceptor_count);
7522 CHECK_EQ(42, global->Get(some_property)->Int32Value());
7523 // Deleting the property when the interceptor returns an empty
7524 // handle should not delete the property since it is DontDelete.
7525 pass_on_delete = true;
7526 CHECK(!global->Delete(some_property));
7527 CHECK_EQ(2, force_delete_interceptor_count);
7528 CHECK_EQ(42, global->Get(some_property)->Int32Value());
7529 // Forcing the property to be deleted should delete the value
7530 // without calling the interceptor.
7531 CHECK(global->ForceDelete(some_property));
7532 CHECK(global->Get(some_property)->IsUndefined());
7533 CHECK_EQ(2, force_delete_interceptor_count);
7534}
7535
7536
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00007537// Make sure that forcing a delete invalidates any IC stubs, so we
7538// don't read the hole value.
7539THREADED_TEST(ForceDeleteIC) {
7540 v8::HandleScope scope;
7541 LocalContext context;
7542 // Create a DontDelete variable on the global object.
7543 CompileRun("this.__proto__ = { foo: 'horse' };"
7544 "var foo = 'fish';"
7545 "function f() { return foo.length; }");
7546 // Initialize the IC for foo in f.
7547 CompileRun("for (var i = 0; i < 4; i++) f();");
7548 // Make sure the value of foo is correct before the deletion.
7549 CHECK_EQ(4, CompileRun("f()")->Int32Value());
7550 // Force the deletion of foo.
7551 CHECK(context->Global()->ForceDelete(v8_str("foo")));
7552 // Make sure the value for foo is read from the prototype, and that
7553 // we don't get in trouble with reading the deleted cell value
7554 // sentinel.
7555 CHECK_EQ(5, CompileRun("f()")->Int32Value());
7556}
7557
7558
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00007559v8::Persistent<Context> calling_context0;
7560v8::Persistent<Context> calling_context1;
7561v8::Persistent<Context> calling_context2;
7562
7563
7564// Check that the call to the callback is initiated in
7565// calling_context2, the directly calling context is calling_context1
7566// and the callback itself is in calling_context0.
7567static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
7568 ApiTestFuzzer::Fuzz();
7569 CHECK(Context::GetCurrent() == calling_context0);
7570 CHECK(Context::GetCalling() == calling_context1);
7571 CHECK(Context::GetEntered() == calling_context2);
7572 return v8::Integer::New(42);
7573}
7574
7575
7576THREADED_TEST(GetCallingContext) {
7577 v8::HandleScope scope;
7578
7579 calling_context0 = Context::New();
7580 calling_context1 = Context::New();
7581 calling_context2 = Context::New();
7582
7583 // Allow cross-domain access.
7584 Local<String> token = v8_str("<security token>");
7585 calling_context0->SetSecurityToken(token);
7586 calling_context1->SetSecurityToken(token);
7587 calling_context2->SetSecurityToken(token);
7588
7589 // Create an object with a C++ callback in context0.
7590 calling_context0->Enter();
7591 Local<v8::FunctionTemplate> callback_templ =
7592 v8::FunctionTemplate::New(GetCallingContextCallback);
7593 calling_context0->Global()->Set(v8_str("callback"),
7594 callback_templ->GetFunction());
7595 calling_context0->Exit();
7596
7597 // Expose context0 in context1 and setup a function that calls the
7598 // callback function.
7599 calling_context1->Enter();
7600 calling_context1->Global()->Set(v8_str("context0"),
7601 calling_context0->Global());
7602 CompileRun("function f() { context0.callback() }");
7603 calling_context1->Exit();
7604
7605 // Expose context1 in context2 and call the callback function in
7606 // context0 indirectly through f in context1.
7607 calling_context2->Enter();
7608 calling_context2->Global()->Set(v8_str("context1"),
7609 calling_context1->Global());
7610 CompileRun("context1.f()");
7611 calling_context2->Exit();
7612
7613 // Dispose the contexts to allow them to be garbage collected.
7614 calling_context0.Dispose();
7615 calling_context1.Dispose();
7616 calling_context2.Dispose();
7617 calling_context0.Clear();
7618 calling_context1.Clear();
7619 calling_context2.Clear();
7620}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007621
7622
7623// Check that a variable declaration with no explicit initialization
7624// value does not shadow an existing property in the prototype chain.
7625//
7626// This is consistent with Firefox and Safari.
7627//
7628// See http://crbug.com/12548.
7629THREADED_TEST(InitGlobalVarInProtoChain) {
7630 v8::HandleScope scope;
7631 LocalContext context;
7632 // Introduce a variable in the prototype chain.
7633 CompileRun("__proto__.x = 42");
7634 v8::Handle<v8::Value> result = CompileRun("var x; x");
7635 CHECK(!result->IsUndefined());
7636 CHECK_EQ(42, result->Int32Value());
7637}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00007638
7639
7640// Regression test for issue 398.
7641// If a function is added to an object, creating a constant function
7642// field, and the result is cloned, replacing the constant function on the
7643// original should not affect the clone.
7644// See http://code.google.com/p/v8/issues/detail?id=398
7645THREADED_TEST(ReplaceConstantFunction) {
7646 v8::HandleScope scope;
7647 LocalContext context;
7648 v8::Handle<v8::Object> obj = v8::Object::New();
7649 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
7650 v8::Handle<v8::String> foo_string = v8::String::New("foo");
7651 obj->Set(foo_string, func_templ->GetFunction());
7652 v8::Handle<v8::Object> obj_clone = obj->Clone();
7653 obj_clone->Set(foo_string, v8::String::New("Hello"));
7654 CHECK(!obj->Get(foo_string)->IsUndefined());
7655}
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007656
7657
7658// Regression test for http://crbug.com/16276.
7659THREADED_TEST(Regress16276) {
7660 v8::HandleScope scope;
7661 LocalContext context;
7662 // Force the IC in f to be a dictionary load IC.
7663 CompileRun("function f(obj) { return obj.x; }\n"
7664 "var obj = { x: { foo: 42 }, y: 87 };\n"
7665 "var x = obj.x;\n"
7666 "delete obj.y;\n"
7667 "for (var i = 0; i < 5; i++) f(obj);");
7668 // Detach the global object to make 'this' refer directly to the
7669 // global object (not the proxy), and make sure that the dictionary
7670 // load IC doesn't mess up loading directly from the global object.
7671 context->DetachGlobal();
7672 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
7673}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007674
7675
7676THREADED_TEST(PixelArray) {
7677 v8::HandleScope scope;
7678 LocalContext context;
7679 const int kElementCount = 40;
7680 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
7681 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
7682 pixel_data);
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007683 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007684 for (int i = 0; i < kElementCount; i++) {
7685 pixels->set(i, i);
7686 }
ager@chromium.orgab99eea2009-08-25 07:05:41 +00007687 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007688 for (int i = 0; i < kElementCount; i++) {
7689 CHECK_EQ(i, pixels->get(i));
7690 CHECK_EQ(i, pixel_data[i]);
7691 }
7692
7693 v8::Handle<v8::Object> obj = v8::Object::New();
7694 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
7695 // Set the elements to be the pixels.
7696 // jsobj->set_elements(*pixels);
7697 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
7698 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7699 obj->Set(v8_str("field"), v8::Int32::New(1503));
7700 context->Global()->Set(v8_str("pixels"), obj);
7701 v8::Handle<v8::Value> result = CompileRun("pixels.field");
7702 CHECK_EQ(1503, result->Int32Value());
7703 result = CompileRun("pixels[1]");
7704 CHECK_EQ(1, result->Int32Value());
7705 result = CompileRun("var sum = 0;"
7706 "for (var i = 0; i < 8; i++) {"
7707 " sum += pixels[i];"
7708 "}"
7709 "sum;");
7710 CHECK_EQ(28, result->Int32Value());
7711
7712 i::Handle<i::Smi> value(i::Smi::FromInt(2));
7713 i::SetElement(jsobj, 1, value);
7714 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
7715 *value.location() = i::Smi::FromInt(256);
7716 i::SetElement(jsobj, 1, value);
7717 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
7718 *value.location() = i::Smi::FromInt(-1);
7719 i::SetElement(jsobj, 1, value);
7720 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7721
7722 result = CompileRun("for (var i = 0; i < 8; i++) {"
7723 " pixels[i] = (i * 65) - 109;"
7724 "}"
7725 "pixels[1] + pixels[6];");
7726 CHECK_EQ(255, result->Int32Value());
7727 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7728 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7729 CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
7730 CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
7731 CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
7732 CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
7733 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
7734 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
7735 result = CompileRun("var sum = 0;"
7736 "for (var i = 0; i < 8; i++) {"
7737 " sum += pixels[i];"
7738 "}"
7739 "sum;");
7740 CHECK_EQ(984, result->Int32Value());
7741
7742 result = CompileRun("for (var i = 0; i < 8; i++) {"
7743 " pixels[i] = (i * 1.1);"
7744 "}"
7745 "pixels[1] + pixels[6];");
7746 CHECK_EQ(8, result->Int32Value());
7747 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7748 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7749 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
7750 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
7751 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
7752 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
7753 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
7754 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
7755
7756 result = CompileRun("for (var i = 0; i < 8; i++) {"
7757 " pixels[7] = undefined;"
7758 "}"
7759 "pixels[7];");
7760 CHECK_EQ(0, result->Int32Value());
7761 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
7762
7763 result = CompileRun("for (var i = 0; i < 8; i++) {"
7764 " pixels[6] = '2.3';"
7765 "}"
7766 "pixels[6];");
7767 CHECK_EQ(2, result->Int32Value());
7768 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
7769
7770 result = CompileRun("for (var i = 0; i < 8; i++) {"
7771 " pixels[5] = NaN;"
7772 "}"
7773 "pixels[5];");
7774 CHECK_EQ(0, result->Int32Value());
7775 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
7776
7777 result = CompileRun("for (var i = 0; i < 8; i++) {"
7778 " pixels[8] = Infinity;"
7779 "}"
7780 "pixels[8];");
7781 CHECK_EQ(255, result->Int32Value());
7782 CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
7783
7784 result = CompileRun("for (var i = 0; i < 8; i++) {"
7785 " pixels[9] = -Infinity;"
7786 "}"
7787 "pixels[9];");
7788 CHECK_EQ(0, result->Int32Value());
7789 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
7790
7791 result = CompileRun("pixels[3] = 33;"
7792 "delete pixels[3];"
7793 "pixels[3];");
7794 CHECK_EQ(33, result->Int32Value());
7795
7796 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
7797 "pixels[2] = 12; pixels[3] = 13;"
7798 "pixels.__defineGetter__('2',"
7799 "function() { return 120; });"
7800 "pixels[2];");
7801 CHECK_EQ(12, result->Int32Value());
7802
7803 result = CompileRun("var js_array = new Array(40);"
7804 "js_array[0] = 77;"
7805 "js_array;");
7806 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7807
7808 result = CompileRun("pixels[1] = 23;"
7809 "pixels.__proto__ = [];"
7810 "js_array.__proto__ = pixels;"
7811 "js_array.concat(pixels);");
7812 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7813 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
7814
7815 free(pixel_data);
7816}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007817
ager@chromium.org96c75b52009-08-26 09:13:16 +00007818
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007819THREADED_TEST(ScriptContextDependence) {
7820 v8::HandleScope scope;
7821 LocalContext c1;
7822 const char *source = "foo";
7823 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
7824 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
7825 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
7826 CHECK_EQ(dep->Run()->Int32Value(), 100);
7827 CHECK_EQ(indep->Run()->Int32Value(), 100);
7828 LocalContext c2;
7829 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
7830 CHECK_EQ(dep->Run()->Int32Value(), 100);
7831 CHECK_EQ(indep->Run()->Int32Value(), 101);
7832}
7833
ager@chromium.org96c75b52009-08-26 09:13:16 +00007834
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007835THREADED_TEST(StackTrace) {
7836 v8::HandleScope scope;
7837 LocalContext context;
7838 v8::TryCatch try_catch;
7839 const char *source = "function foo() { FAIL.FAIL; }; foo();";
7840 v8::Handle<v8::String> src = v8::String::New(source);
7841 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
7842 v8::Script::New(src, origin)->Run();
7843 CHECK(try_catch.HasCaught());
7844 v8::String::Utf8Value stack(try_catch.StackTrace());
7845 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
7846}
ager@chromium.org96c75b52009-08-26 09:13:16 +00007847
7848
7849// Test that idle notification can be handled when V8 has not yet been
7850// set up.
7851THREADED_TEST(IdleNotification) {
7852 for (int i = 0; i < 100; i++) v8::V8::IdleNotification(true);
7853 for (int i = 0; i < 100; i++) v8::V8::IdleNotification(false);
7854}