blob: 9539973693b10cb0fd5e0e5546c41e762737ba7a [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2007-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
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
Steve Block3ce2e202009-11-05 08:53:23 +000028#include <limits.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000029
30#include "v8.h"
31
32#include "api.h"
33#include "compilation-cache.h"
34#include "execution.h"
35#include "snapshot.h"
36#include "platform.h"
37#include "top.h"
Steve Block3ce2e202009-11-05 08:53:23 +000038#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "cctest.h"
Iain Merrick9ac36c92010-09-13 15:29:50 +010040#include "parser.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080041#include "unicode-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042
Andrei Popescu31002712010-02-23 13:46:05 +000043static const bool kLogThreading = true;
Steve Blockd0582a62009-12-15 09:54:21 +000044
Steve Blocka7e24c12009-10-30 11:49:00 +000045static bool IsNaN(double x) {
46#ifdef WIN32
47 return _isnan(x);
48#else
49 return isnan(x);
50#endif
51}
52
53using ::v8::ObjectTemplate;
54using ::v8::Value;
55using ::v8::Context;
56using ::v8::Local;
57using ::v8::String;
58using ::v8::Script;
59using ::v8::Function;
60using ::v8::AccessorInfo;
61using ::v8::Extension;
62
Steve Block8defd9f2010-07-08 12:39:36 +010063namespace i = ::i;
Steve Blocka7e24c12009-10-30 11:49:00 +000064
Steve Blocka7e24c12009-10-30 11:49:00 +000065
Leon Clarked91b9f72010-01-27 17:25:45 +000066static void ExpectString(const char* code, const char* expected) {
67 Local<Value> result = CompileRun(code);
68 CHECK(result->IsString());
69 String::AsciiValue ascii(result);
70 CHECK_EQ(expected, *ascii);
71}
72
73
74static void ExpectBoolean(const char* code, bool expected) {
75 Local<Value> result = CompileRun(code);
76 CHECK(result->IsBoolean());
77 CHECK_EQ(expected, result->BooleanValue());
78}
79
80
Leon Clarkef7060e22010-06-03 12:02:55 +010081static void ExpectTrue(const char* code) {
82 ExpectBoolean(code, true);
83}
84
85
Iain Merrick75681382010-08-19 15:07:18 +010086static void ExpectFalse(const char* code) {
87 ExpectBoolean(code, false);
88}
89
90
Leon Clarked91b9f72010-01-27 17:25:45 +000091static void ExpectObject(const char* code, Local<Value> expected) {
92 Local<Value> result = CompileRun(code);
93 CHECK(result->Equals(expected));
94}
95
96
Iain Merrick75681382010-08-19 15:07:18 +010097static void ExpectUndefined(const char* code) {
98 Local<Value> result = CompileRun(code);
99 CHECK(result->IsUndefined());
100}
101
102
Steve Blocka7e24c12009-10-30 11:49:00 +0000103static int signature_callback_count;
104static v8::Handle<Value> IncrementingSignatureCallback(
105 const v8::Arguments& args) {
106 ApiTestFuzzer::Fuzz();
107 signature_callback_count++;
108 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
109 for (int i = 0; i < args.Length(); i++)
110 result->Set(v8::Integer::New(i), args[i]);
111 return result;
112}
113
114
115static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
116 ApiTestFuzzer::Fuzz();
117 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
118 for (int i = 0; i < args.Length(); i++) {
119 result->Set(v8::Integer::New(i), args[i]);
120 }
121 return result;
122}
123
124
125THREADED_TEST(Handles) {
126 v8::HandleScope scope;
127 Local<Context> local_env;
128 {
129 LocalContext env;
130 local_env = env.local();
131 }
132
133 // Local context should still be live.
134 CHECK(!local_env.IsEmpty());
135 local_env->Enter();
136
137 v8::Handle<v8::Primitive> undef = v8::Undefined();
138 CHECK(!undef.IsEmpty());
139 CHECK(undef->IsUndefined());
140
141 const char* c_source = "1 + 2 + 3";
142 Local<String> source = String::New(c_source);
143 Local<Script> script = Script::Compile(source);
144 CHECK_EQ(6, script->Run()->Int32Value());
145
146 local_env->Exit();
147}
148
149
Steve Blocka7e24c12009-10-30 11:49:00 +0000150THREADED_TEST(ReceiverSignature) {
151 v8::HandleScope scope;
152 LocalContext env;
153 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
154 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
155 fun->PrototypeTemplate()->Set(
156 v8_str("m"),
157 v8::FunctionTemplate::New(IncrementingSignatureCallback,
158 v8::Handle<Value>(),
159 sig));
160 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
161 signature_callback_count = 0;
162 CompileRun(
163 "var o = new Fun();"
164 "o.m();");
165 CHECK_EQ(1, signature_callback_count);
166 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
167 sub_fun->Inherit(fun);
168 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
169 CompileRun(
170 "var o = new SubFun();"
171 "o.m();");
172 CHECK_EQ(2, signature_callback_count);
173
174 v8::TryCatch try_catch;
175 CompileRun(
176 "var o = { };"
177 "o.m = Fun.prototype.m;"
178 "o.m();");
179 CHECK_EQ(2, signature_callback_count);
180 CHECK(try_catch.HasCaught());
181 try_catch.Reset();
182 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
183 sub_fun->Inherit(fun);
184 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
185 CompileRun(
186 "var o = new UnrelFun();"
187 "o.m = Fun.prototype.m;"
188 "o.m();");
189 CHECK_EQ(2, signature_callback_count);
190 CHECK(try_catch.HasCaught());
191}
192
193
194
195
196THREADED_TEST(ArgumentSignature) {
197 v8::HandleScope scope;
198 LocalContext env;
199 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
200 cons->SetClassName(v8_str("Cons"));
201 v8::Handle<v8::Signature> sig =
202 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
203 v8::Handle<v8::FunctionTemplate> fun =
204 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
205 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
206 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
207
208 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
209 CHECK(value1->IsTrue());
210
211 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
212 CHECK(value2->IsTrue());
213
214 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
215 CHECK(value3->IsTrue());
216
217 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
218 cons1->SetClassName(v8_str("Cons1"));
219 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
220 cons2->SetClassName(v8_str("Cons2"));
221 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
222 cons3->SetClassName(v8_str("Cons3"));
223
224 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
225 v8::Handle<v8::Signature> wsig =
226 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
227 v8::Handle<v8::FunctionTemplate> fun2 =
228 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
229
230 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
231 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
232 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
233 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
234 v8::Handle<Value> value4 = CompileRun(
235 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
236 "'[object Cons1],[object Cons2],[object Cons3]'");
237 CHECK(value4->IsTrue());
238
239 v8::Handle<Value> value5 = CompileRun(
240 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
241 CHECK(value5->IsTrue());
242
243 v8::Handle<Value> value6 = CompileRun(
244 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
245 CHECK(value6->IsTrue());
246
247 v8::Handle<Value> value7 = CompileRun(
248 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
249 "'[object Cons1],[object Cons2],[object Cons3],d';");
250 CHECK(value7->IsTrue());
251
252 v8::Handle<Value> value8 = CompileRun(
253 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
254 CHECK(value8->IsTrue());
255}
256
257
258THREADED_TEST(HulIgennem) {
259 v8::HandleScope scope;
260 LocalContext env;
261 v8::Handle<v8::Primitive> undef = v8::Undefined();
262 Local<String> undef_str = undef->ToString();
263 char* value = i::NewArray<char>(undef_str->Length() + 1);
264 undef_str->WriteAscii(value);
265 CHECK_EQ(0, strcmp(value, "undefined"));
266 i::DeleteArray(value);
267}
268
269
270THREADED_TEST(Access) {
271 v8::HandleScope scope;
272 LocalContext env;
273 Local<v8::Object> obj = v8::Object::New();
274 Local<Value> foo_before = obj->Get(v8_str("foo"));
275 CHECK(foo_before->IsUndefined());
276 Local<String> bar_str = v8_str("bar");
277 obj->Set(v8_str("foo"), bar_str);
278 Local<Value> foo_after = obj->Get(v8_str("foo"));
279 CHECK(!foo_after->IsUndefined());
280 CHECK(foo_after->IsString());
281 CHECK_EQ(bar_str, foo_after);
282}
283
284
Steve Block6ded16b2010-05-10 14:33:55 +0100285THREADED_TEST(AccessElement) {
286 v8::HandleScope scope;
287 LocalContext env;
288 Local<v8::Object> obj = v8::Object::New();
289 Local<Value> before = obj->Get(1);
290 CHECK(before->IsUndefined());
291 Local<String> bar_str = v8_str("bar");
292 obj->Set(1, bar_str);
293 Local<Value> after = obj->Get(1);
294 CHECK(!after->IsUndefined());
295 CHECK(after->IsString());
296 CHECK_EQ(bar_str, after);
297
298 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
299 CHECK_EQ(v8_str("a"), value->Get(0));
300 CHECK_EQ(v8_str("b"), value->Get(1));
301}
302
303
Steve Blocka7e24c12009-10-30 11:49:00 +0000304THREADED_TEST(Script) {
305 v8::HandleScope scope;
306 LocalContext env;
307 const char* c_source = "1 + 2 + 3";
308 Local<String> source = String::New(c_source);
309 Local<Script> script = Script::Compile(source);
310 CHECK_EQ(6, script->Run()->Int32Value());
311}
312
313
314static uint16_t* AsciiToTwoByteString(const char* source) {
Steve Blockd0582a62009-12-15 09:54:21 +0000315 int array_length = i::StrLength(source) + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 uint16_t* converted = i::NewArray<uint16_t>(array_length);
Steve Blockd0582a62009-12-15 09:54:21 +0000317 for (int i = 0; i < array_length; i++) converted[i] = source[i];
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 return converted;
319}
320
321
322class TestResource: public String::ExternalStringResource {
323 public:
324 static int dispose_count;
325
326 explicit TestResource(uint16_t* data)
327 : data_(data), length_(0) {
328 while (data[length_]) ++length_;
329 }
330
331 ~TestResource() {
332 i::DeleteArray(data_);
333 ++dispose_count;
334 }
335
336 const uint16_t* data() const {
337 return data_;
338 }
339
340 size_t length() const {
341 return length_;
342 }
343 private:
344 uint16_t* data_;
345 size_t length_;
346};
347
348
349int TestResource::dispose_count = 0;
350
351
352class TestAsciiResource: public String::ExternalAsciiStringResource {
353 public:
354 static int dispose_count;
355
356 explicit TestAsciiResource(const char* data)
357 : data_(data),
358 length_(strlen(data)) { }
359
360 ~TestAsciiResource() {
361 i::DeleteArray(data_);
362 ++dispose_count;
363 }
364
365 const char* data() const {
366 return data_;
367 }
368
369 size_t length() const {
370 return length_;
371 }
372 private:
373 const char* data_;
374 size_t length_;
375};
376
377
378int TestAsciiResource::dispose_count = 0;
379
380
381THREADED_TEST(ScriptUsingStringResource) {
382 TestResource::dispose_count = 0;
383 const char* c_source = "1 + 2 * 3";
384 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
385 {
386 v8::HandleScope scope;
387 LocalContext env;
388 TestResource* resource = new TestResource(two_byte_source);
389 Local<String> source = String::NewExternal(resource);
390 Local<Script> script = Script::Compile(source);
391 Local<Value> value = script->Run();
392 CHECK(value->IsNumber());
393 CHECK_EQ(7, value->Int32Value());
394 CHECK(source->IsExternal());
395 CHECK_EQ(resource,
396 static_cast<TestResource*>(source->GetExternalStringResource()));
Steve Block8defd9f2010-07-08 12:39:36 +0100397 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 CHECK_EQ(0, TestResource::dispose_count);
399 }
Steve Block8defd9f2010-07-08 12:39:36 +0100400 i::CompilationCache::Clear();
401 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 CHECK_EQ(1, TestResource::dispose_count);
403}
404
405
406THREADED_TEST(ScriptUsingAsciiStringResource) {
407 TestAsciiResource::dispose_count = 0;
408 const char* c_source = "1 + 2 * 3";
409 {
410 v8::HandleScope scope;
411 LocalContext env;
412 Local<String> source =
413 String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
414 Local<Script> script = Script::Compile(source);
415 Local<Value> value = script->Run();
416 CHECK(value->IsNumber());
417 CHECK_EQ(7, value->Int32Value());
Steve Block8defd9f2010-07-08 12:39:36 +0100418 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 CHECK_EQ(0, TestAsciiResource::dispose_count);
420 }
Steve Block8defd9f2010-07-08 12:39:36 +0100421 i::CompilationCache::Clear();
422 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 CHECK_EQ(1, TestAsciiResource::dispose_count);
424}
425
426
427THREADED_TEST(ScriptMakingExternalString) {
428 TestResource::dispose_count = 0;
429 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
430 {
431 v8::HandleScope scope;
432 LocalContext env;
433 Local<String> source = String::New(two_byte_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000434 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100435 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
436 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 bool success = source->MakeExternal(new TestResource(two_byte_source));
438 CHECK(success);
439 Local<Script> script = Script::Compile(source);
440 Local<Value> value = script->Run();
441 CHECK(value->IsNumber());
442 CHECK_EQ(7, value->Int32Value());
Steve Block8defd9f2010-07-08 12:39:36 +0100443 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 CHECK_EQ(0, TestResource::dispose_count);
445 }
Steve Block8defd9f2010-07-08 12:39:36 +0100446 i::CompilationCache::Clear();
447 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 CHECK_EQ(1, TestResource::dispose_count);
449}
450
451
452THREADED_TEST(ScriptMakingExternalAsciiString) {
453 TestAsciiResource::dispose_count = 0;
454 const char* c_source = "1 + 2 * 3";
455 {
456 v8::HandleScope scope;
457 LocalContext env;
458 Local<String> source = v8_str(c_source);
Andrei Popescu402d9372010-02-26 13:31:12 +0000459 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100460 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
461 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 bool success = source->MakeExternal(
463 new TestAsciiResource(i::StrDup(c_source)));
464 CHECK(success);
465 Local<Script> script = Script::Compile(source);
466 Local<Value> value = script->Run();
467 CHECK(value->IsNumber());
468 CHECK_EQ(7, value->Int32Value());
Steve Block8defd9f2010-07-08 12:39:36 +0100469 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 CHECK_EQ(0, TestAsciiResource::dispose_count);
471 }
Steve Block8defd9f2010-07-08 12:39:36 +0100472 i::CompilationCache::Clear();
473 i::Heap::CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 CHECK_EQ(1, TestAsciiResource::dispose_count);
475}
476
477
Andrei Popescu402d9372010-02-26 13:31:12 +0000478TEST(MakingExternalStringConditions) {
479 v8::HandleScope scope;
480 LocalContext env;
481
482 // Free some space in the new space so that we can check freshness.
Ben Murdochf87a2032010-10-22 12:50:53 +0100483 i::Heap::CollectGarbage(i::NEW_SPACE);
484 i::Heap::CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000485
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100486 uint16_t* two_byte_string = AsciiToTwoByteString("small");
487 Local<String> small_string = String::New(two_byte_string);
488 i::DeleteArray(two_byte_string);
489
Andrei Popescu402d9372010-02-26 13:31:12 +0000490 // We should refuse to externalize newly created small string.
491 CHECK(!small_string->CanMakeExternal());
492 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100493 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
494 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 // Old space strings should be accepted.
496 CHECK(small_string->CanMakeExternal());
497
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100498 two_byte_string = AsciiToTwoByteString("small 2");
499 small_string = String::New(two_byte_string);
500 i::DeleteArray(two_byte_string);
501
Andrei Popescu402d9372010-02-26 13:31:12 +0000502 // We should refuse externalizing newly created small string.
503 CHECK(!small_string->CanMakeExternal());
504 for (int i = 0; i < 100; i++) {
505 String::Value value(small_string);
506 }
507 // Frequently used strings should be accepted.
508 CHECK(small_string->CanMakeExternal());
509
510 const int buf_size = 10 * 1024;
511 char* buf = i::NewArray<char>(buf_size);
512 memset(buf, 'a', buf_size);
513 buf[buf_size - 1] = '\0';
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100514
515 two_byte_string = AsciiToTwoByteString(buf);
516 Local<String> large_string = String::New(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000517 i::DeleteArray(buf);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100518 i::DeleteArray(two_byte_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000519 // Large strings should be immediately accepted.
520 CHECK(large_string->CanMakeExternal());
521}
522
523
524TEST(MakingExternalAsciiStringConditions) {
525 v8::HandleScope scope;
526 LocalContext env;
527
528 // Free some space in the new space so that we can check freshness.
Ben Murdochf87a2032010-10-22 12:50:53 +0100529 i::Heap::CollectGarbage(i::NEW_SPACE);
530 i::Heap::CollectGarbage(i::NEW_SPACE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000531
532 Local<String> small_string = String::New("small");
533 // We should refuse to externalize newly created small string.
534 CHECK(!small_string->CanMakeExternal());
535 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100536 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
537 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Andrei Popescu402d9372010-02-26 13:31:12 +0000538 // Old space strings should be accepted.
539 CHECK(small_string->CanMakeExternal());
540
541 small_string = String::New("small 2");
542 // We should refuse externalizing newly created small string.
543 CHECK(!small_string->CanMakeExternal());
544 for (int i = 0; i < 100; i++) {
545 String::Value value(small_string);
546 }
547 // Frequently used strings should be accepted.
548 CHECK(small_string->CanMakeExternal());
549
550 const int buf_size = 10 * 1024;
551 char* buf = i::NewArray<char>(buf_size);
552 memset(buf, 'a', buf_size);
553 buf[buf_size - 1] = '\0';
554 Local<String> large_string = String::New(buf);
555 i::DeleteArray(buf);
556 // Large strings should be immediately accepted.
557 CHECK(large_string->CanMakeExternal());
558}
559
560
Steve Blocka7e24c12009-10-30 11:49:00 +0000561THREADED_TEST(UsingExternalString) {
562 {
563 v8::HandleScope scope;
564 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
565 Local<String> string =
566 String::NewExternal(new TestResource(two_byte_string));
567 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
568 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100569 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
570 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
572 CHECK(isymbol->IsSymbol());
573 }
574 i::Heap::CollectAllGarbage(false);
575 i::Heap::CollectAllGarbage(false);
576}
577
578
579THREADED_TEST(UsingExternalAsciiString) {
580 {
581 v8::HandleScope scope;
582 const char* one_byte_string = "test string";
583 Local<String> string = String::NewExternal(
584 new TestAsciiResource(i::StrDup(one_byte_string)));
585 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
586 // Trigger GCs so that the newly allocated string moves to old gen.
Ben Murdochf87a2032010-10-22 12:50:53 +0100587 i::Heap::CollectGarbage(i::NEW_SPACE); // in survivor space now
588 i::Heap::CollectGarbage(i::NEW_SPACE); // in old gen now
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
590 CHECK(isymbol->IsSymbol());
591 }
592 i::Heap::CollectAllGarbage(false);
593 i::Heap::CollectAllGarbage(false);
594}
595
596
Leon Clarkee46be812010-01-19 14:06:41 +0000597THREADED_TEST(ScavengeExternalString) {
598 TestResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100599 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000600 {
601 v8::HandleScope scope;
602 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
603 Local<String> string =
604 String::NewExternal(new TestResource(two_byte_string));
605 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochf87a2032010-10-22 12:50:53 +0100606 i::Heap::CollectGarbage(i::NEW_SPACE);
Steve Block6ded16b2010-05-10 14:33:55 +0100607 in_new_space = i::Heap::InNewSpace(*istring);
608 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000609 CHECK_EQ(0, TestResource::dispose_count);
610 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100611 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000612 CHECK_EQ(1, TestResource::dispose_count);
613}
614
615
616THREADED_TEST(ScavengeExternalAsciiString) {
617 TestAsciiResource::dispose_count = 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100618 bool in_new_space = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000619 {
620 v8::HandleScope scope;
621 const char* one_byte_string = "test string";
622 Local<String> string = String::NewExternal(
623 new TestAsciiResource(i::StrDup(one_byte_string)));
624 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
Ben Murdochf87a2032010-10-22 12:50:53 +0100625 i::Heap::CollectGarbage(i::NEW_SPACE);
Steve Block6ded16b2010-05-10 14:33:55 +0100626 in_new_space = i::Heap::InNewSpace(*istring);
627 CHECK(in_new_space || i::Heap::old_data_space()->Contains(*istring));
Leon Clarkee46be812010-01-19 14:06:41 +0000628 CHECK_EQ(0, TestAsciiResource::dispose_count);
629 }
Ben Murdochf87a2032010-10-22 12:50:53 +0100630 i::Heap::CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
Leon Clarkee46be812010-01-19 14:06:41 +0000631 CHECK_EQ(1, TestAsciiResource::dispose_count);
632}
633
634
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100635class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
636 public:
637 static int dispose_calls;
638
639 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
640 : TestAsciiResource(data),
641 dispose_(dispose) { }
642
643 void Dispose() {
644 ++dispose_calls;
645 if (dispose_) delete this;
646 }
647 private:
648 bool dispose_;
649};
650
651
652int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
653
654
655TEST(ExternalStringWithDisposeHandling) {
656 const char* c_source = "1 + 2 * 3";
657
658 // Use a stack allocated external string resource allocated object.
659 TestAsciiResource::dispose_count = 0;
660 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
661 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
662 {
663 v8::HandleScope scope;
664 LocalContext env;
665 Local<String> source = String::NewExternal(&res_stack);
666 Local<Script> script = Script::Compile(source);
667 Local<Value> value = script->Run();
668 CHECK(value->IsNumber());
669 CHECK_EQ(7, value->Int32Value());
Steve Block8defd9f2010-07-08 12:39:36 +0100670 i::Heap::CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100671 CHECK_EQ(0, TestAsciiResource::dispose_count);
672 }
Steve Block8defd9f2010-07-08 12:39:36 +0100673 i::CompilationCache::Clear();
674 i::Heap::CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100675 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
676 CHECK_EQ(0, TestAsciiResource::dispose_count);
677
678 // Use a heap allocated external string resource allocated object.
679 TestAsciiResource::dispose_count = 0;
680 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
681 TestAsciiResource* res_heap =
682 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
683 {
684 v8::HandleScope scope;
685 LocalContext env;
686 Local<String> source = String::NewExternal(res_heap);
687 Local<Script> script = Script::Compile(source);
688 Local<Value> value = script->Run();
689 CHECK(value->IsNumber());
690 CHECK_EQ(7, value->Int32Value());
Steve Block8defd9f2010-07-08 12:39:36 +0100691 i::Heap::CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100692 CHECK_EQ(0, TestAsciiResource::dispose_count);
693 }
Steve Block8defd9f2010-07-08 12:39:36 +0100694 i::CompilationCache::Clear();
695 i::Heap::CollectAllGarbage(false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100696 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
697 CHECK_EQ(1, TestAsciiResource::dispose_count);
698}
699
700
Steve Block3ce2e202009-11-05 08:53:23 +0000701THREADED_TEST(StringConcat) {
702 {
703 v8::HandleScope scope;
704 LocalContext env;
705 const char* one_byte_string_1 = "function a_times_t";
706 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
707 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
708 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
709 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
710 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
711 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
712 Local<String> left = v8_str(one_byte_string_1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100713
714 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
715 Local<String> right = String::New(two_byte_source);
716 i::DeleteArray(two_byte_source);
717
Steve Block3ce2e202009-11-05 08:53:23 +0000718 Local<String> source = String::Concat(left, right);
719 right = String::NewExternal(
720 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
721 source = String::Concat(source, right);
722 right = String::NewExternal(
723 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
724 source = String::Concat(source, right);
725 right = v8_str(one_byte_string_2);
726 source = String::Concat(source, right);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100727
728 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
729 right = String::New(two_byte_source);
730 i::DeleteArray(two_byte_source);
731
Steve Block3ce2e202009-11-05 08:53:23 +0000732 source = String::Concat(source, right);
733 right = String::NewExternal(
734 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
735 source = String::Concat(source, right);
736 Local<Script> script = Script::Compile(source);
737 Local<Value> value = script->Run();
738 CHECK(value->IsNumber());
739 CHECK_EQ(68, value->Int32Value());
740 }
Steve Block8defd9f2010-07-08 12:39:36 +0100741 i::CompilationCache::Clear();
Steve Block3ce2e202009-11-05 08:53:23 +0000742 i::Heap::CollectAllGarbage(false);
743 i::Heap::CollectAllGarbage(false);
744}
745
746
Steve Blocka7e24c12009-10-30 11:49:00 +0000747THREADED_TEST(GlobalProperties) {
748 v8::HandleScope scope;
749 LocalContext env;
750 v8::Handle<v8::Object> global = env->Global();
751 global->Set(v8_str("pi"), v8_num(3.1415926));
752 Local<Value> pi = global->Get(v8_str("pi"));
753 CHECK_EQ(3.1415926, pi->NumberValue());
754}
755
756
757static v8::Handle<Value> handle_call(const v8::Arguments& args) {
758 ApiTestFuzzer::Fuzz();
759 return v8_num(102);
760}
761
762
763static v8::Handle<Value> construct_call(const v8::Arguments& args) {
764 ApiTestFuzzer::Fuzz();
765 args.This()->Set(v8_str("x"), v8_num(1));
766 args.This()->Set(v8_str("y"), v8_num(2));
767 return args.This();
768}
769
Ben Murdochf87a2032010-10-22 12:50:53 +0100770static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
771 ApiTestFuzzer::Fuzz();
772 return v8_num(239);
773}
774
775
Steve Blocka7e24c12009-10-30 11:49:00 +0000776THREADED_TEST(FunctionTemplate) {
777 v8::HandleScope scope;
778 LocalContext env;
779 {
780 Local<v8::FunctionTemplate> fun_templ =
781 v8::FunctionTemplate::New(handle_call);
782 Local<Function> fun = fun_templ->GetFunction();
783 env->Global()->Set(v8_str("obj"), fun);
784 Local<Script> script = v8_compile("obj()");
785 CHECK_EQ(102, script->Run()->Int32Value());
786 }
787 // Use SetCallHandler to initialize a function template, should work like the
788 // previous one.
789 {
790 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
791 fun_templ->SetCallHandler(handle_call);
792 Local<Function> fun = fun_templ->GetFunction();
793 env->Global()->Set(v8_str("obj"), fun);
794 Local<Script> script = v8_compile("obj()");
795 CHECK_EQ(102, script->Run()->Int32Value());
796 }
797 // Test constructor calls.
798 {
799 Local<v8::FunctionTemplate> fun_templ =
800 v8::FunctionTemplate::New(construct_call);
801 fun_templ->SetClassName(v8_str("funky"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100802 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 Local<Function> fun = fun_templ->GetFunction();
804 env->Global()->Set(v8_str("obj"), fun);
805 Local<Script> script = v8_compile("var s = new obj(); s.x");
806 CHECK_EQ(1, script->Run()->Int32Value());
807
808 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
809 CHECK_EQ(v8_str("[object funky]"), result);
Ben Murdochf87a2032010-10-22 12:50:53 +0100810
811 result = v8_compile("(new obj()).m")->Run();
812 CHECK_EQ(239, result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 }
814}
815
816
817THREADED_TEST(FindInstanceInPrototypeChain) {
818 v8::HandleScope scope;
819 LocalContext env;
820
821 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
822 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
823 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
824 derived->Inherit(base);
825
826 Local<v8::Function> base_function = base->GetFunction();
827 Local<v8::Function> derived_function = derived->GetFunction();
828 Local<v8::Function> other_function = other->GetFunction();
829
830 Local<v8::Object> base_instance = base_function->NewInstance();
831 Local<v8::Object> derived_instance = derived_function->NewInstance();
832 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
833 Local<v8::Object> other_instance = other_function->NewInstance();
834 derived_instance2->Set(v8_str("__proto__"), derived_instance);
835 other_instance->Set(v8_str("__proto__"), derived_instance2);
836
837 // base_instance is only an instance of base.
838 CHECK_EQ(base_instance,
839 base_instance->FindInstanceInPrototypeChain(base));
840 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
841 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
842
843 // derived_instance is an instance of base and derived.
844 CHECK_EQ(derived_instance,
845 derived_instance->FindInstanceInPrototypeChain(base));
846 CHECK_EQ(derived_instance,
847 derived_instance->FindInstanceInPrototypeChain(derived));
848 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
849
850 // other_instance is an instance of other and its immediate
851 // prototype derived_instance2 is an instance of base and derived.
852 // Note, derived_instance is an instance of base and derived too,
853 // but it comes after derived_instance2 in the prototype chain of
854 // other_instance.
855 CHECK_EQ(derived_instance2,
856 other_instance->FindInstanceInPrototypeChain(base));
857 CHECK_EQ(derived_instance2,
858 other_instance->FindInstanceInPrototypeChain(derived));
859 CHECK_EQ(other_instance,
860 other_instance->FindInstanceInPrototypeChain(other));
861}
862
863
Steve Block3ce2e202009-11-05 08:53:23 +0000864THREADED_TEST(TinyInteger) {
865 v8::HandleScope scope;
866 LocalContext env;
867 int32_t value = 239;
868 Local<v8::Integer> value_obj = v8::Integer::New(value);
869 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
870}
871
872
873THREADED_TEST(BigSmiInteger) {
874 v8::HandleScope scope;
875 LocalContext env;
876 int32_t value = i::Smi::kMaxValue;
877 // We cannot add one to a Smi::kMaxValue without wrapping.
878 if (i::kSmiValueSize < 32) {
879 CHECK(i::Smi::IsValid(value));
880 CHECK(!i::Smi::IsValid(value + 1));
881 Local<v8::Integer> value_obj = v8::Integer::New(value);
882 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
883 }
884}
885
886
887THREADED_TEST(BigInteger) {
888 v8::HandleScope scope;
889 LocalContext env;
890 // We cannot add one to a Smi::kMaxValue without wrapping.
891 if (i::kSmiValueSize < 32) {
892 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
893 // The code will not be run in that case, due to the "if" guard.
894 int32_t value =
895 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
896 CHECK(value > i::Smi::kMaxValue);
897 CHECK(!i::Smi::IsValid(value));
898 Local<v8::Integer> value_obj = v8::Integer::New(value);
899 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
900 }
901}
902
903
904THREADED_TEST(TinyUnsignedInteger) {
905 v8::HandleScope scope;
906 LocalContext env;
907 uint32_t value = 239;
908 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
909 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
910}
911
912
913THREADED_TEST(BigUnsignedSmiInteger) {
914 v8::HandleScope scope;
915 LocalContext env;
916 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
917 CHECK(i::Smi::IsValid(value));
918 CHECK(!i::Smi::IsValid(value + 1));
919 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
920 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
921}
922
923
924THREADED_TEST(BigUnsignedInteger) {
925 v8::HandleScope scope;
926 LocalContext env;
927 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
928 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
929 CHECK(!i::Smi::IsValid(value));
930 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
931 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
932}
933
934
935THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
936 v8::HandleScope scope;
937 LocalContext env;
938 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
939 uint32_t value = INT32_MAX_AS_UINT + 1;
940 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
941 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
942 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
943}
944
945
Steve Blocka7e24c12009-10-30 11:49:00 +0000946THREADED_TEST(Number) {
947 v8::HandleScope scope;
948 LocalContext env;
949 double PI = 3.1415926;
950 Local<v8::Number> pi_obj = v8::Number::New(PI);
951 CHECK_EQ(PI, pi_obj->NumberValue());
952}
953
954
955THREADED_TEST(ToNumber) {
956 v8::HandleScope scope;
957 LocalContext env;
958 Local<String> str = v8_str("3.1415926");
959 CHECK_EQ(3.1415926, str->NumberValue());
960 v8::Handle<v8::Boolean> t = v8::True();
961 CHECK_EQ(1.0, t->NumberValue());
962 v8::Handle<v8::Boolean> f = v8::False();
963 CHECK_EQ(0.0, f->NumberValue());
964}
965
966
967THREADED_TEST(Date) {
968 v8::HandleScope scope;
969 LocalContext env;
970 double PI = 3.1415926;
971 Local<Value> date_obj = v8::Date::New(PI);
972 CHECK_EQ(3.0, date_obj->NumberValue());
973}
974
975
976THREADED_TEST(Boolean) {
977 v8::HandleScope scope;
978 LocalContext env;
979 v8::Handle<v8::Boolean> t = v8::True();
980 CHECK(t->Value());
981 v8::Handle<v8::Boolean> f = v8::False();
982 CHECK(!f->Value());
983 v8::Handle<v8::Primitive> u = v8::Undefined();
984 CHECK(!u->BooleanValue());
985 v8::Handle<v8::Primitive> n = v8::Null();
986 CHECK(!n->BooleanValue());
987 v8::Handle<String> str1 = v8_str("");
988 CHECK(!str1->BooleanValue());
989 v8::Handle<String> str2 = v8_str("x");
990 CHECK(str2->BooleanValue());
991 CHECK(!v8::Number::New(0)->BooleanValue());
992 CHECK(v8::Number::New(-1)->BooleanValue());
993 CHECK(v8::Number::New(1)->BooleanValue());
994 CHECK(v8::Number::New(42)->BooleanValue());
995 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
996}
997
998
999static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1000 ApiTestFuzzer::Fuzz();
1001 return v8_num(13.4);
1002}
1003
1004
1005static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1006 ApiTestFuzzer::Fuzz();
1007 return v8_num(876);
1008}
1009
1010
1011THREADED_TEST(GlobalPrototype) {
1012 v8::HandleScope scope;
1013 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1014 func_templ->PrototypeTemplate()->Set(
1015 "dummy",
1016 v8::FunctionTemplate::New(DummyCallHandler));
1017 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1018 templ->Set("x", v8_num(200));
1019 templ->SetAccessor(v8_str("m"), GetM);
1020 LocalContext env(0, templ);
1021 v8::Handle<v8::Object> obj = env->Global();
1022 v8::Handle<Script> script = v8_compile("dummy()");
1023 v8::Handle<Value> result = script->Run();
1024 CHECK_EQ(13.4, result->NumberValue());
1025 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1026 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1027}
1028
1029
Steve Blocka7e24c12009-10-30 11:49:00 +00001030THREADED_TEST(ObjectTemplate) {
1031 v8::HandleScope scope;
1032 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1033 templ1->Set("x", v8_num(10));
1034 templ1->Set("y", v8_num(13));
1035 LocalContext env;
1036 Local<v8::Object> instance1 = templ1->NewInstance();
1037 env->Global()->Set(v8_str("p"), instance1);
1038 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1039 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1040 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1041 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1042 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1043 templ2->Set("a", v8_num(12));
1044 templ2->Set("b", templ1);
1045 Local<v8::Object> instance2 = templ2->NewInstance();
1046 env->Global()->Set(v8_str("q"), instance2);
1047 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1048 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1049 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1050 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1051}
1052
1053
1054static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1055 ApiTestFuzzer::Fuzz();
1056 return v8_num(17.2);
1057}
1058
1059
1060static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1061 ApiTestFuzzer::Fuzz();
1062 return v8_num(15.2);
1063}
1064
1065
1066THREADED_TEST(DescriptorInheritance) {
1067 v8::HandleScope scope;
1068 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1069 super->PrototypeTemplate()->Set("flabby",
1070 v8::FunctionTemplate::New(GetFlabby));
1071 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1072
1073 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1074
1075 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1076 base1->Inherit(super);
1077 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1078
1079 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1080 base2->Inherit(super);
1081 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1082
1083 LocalContext env;
1084
1085 env->Global()->Set(v8_str("s"), super->GetFunction());
1086 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1087 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1088
1089 // Checks right __proto__ chain.
1090 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1091 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1092
1093 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1094
1095 // Instance accessor should not be visible on function object or its prototype
1096 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1097 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1098 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1099
1100 env->Global()->Set(v8_str("obj"),
1101 base1->GetFunction()->NewInstance());
1102 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1103 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1104 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1105 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1106 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1107
1108 env->Global()->Set(v8_str("obj2"),
1109 base2->GetFunction()->NewInstance());
1110 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1111 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1112 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1113 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1114 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1115
1116 // base1 and base2 cannot cross reference to each's prototype
1117 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1118 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1119}
1120
1121
1122int echo_named_call_count;
1123
1124
1125static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1126 const AccessorInfo& info) {
1127 ApiTestFuzzer::Fuzz();
1128 CHECK_EQ(v8_str("data"), info.Data());
1129 echo_named_call_count++;
1130 return name;
1131}
1132
1133
1134THREADED_TEST(NamedPropertyHandlerGetter) {
1135 echo_named_call_count = 0;
1136 v8::HandleScope scope;
1137 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1138 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1139 0, 0, 0, 0,
1140 v8_str("data"));
1141 LocalContext env;
1142 env->Global()->Set(v8_str("obj"),
1143 templ->GetFunction()->NewInstance());
1144 CHECK_EQ(echo_named_call_count, 0);
1145 v8_compile("obj.x")->Run();
1146 CHECK_EQ(echo_named_call_count, 1);
1147 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1148 v8::Handle<Value> str = CompileRun(code);
1149 String::AsciiValue value(str);
1150 CHECK_EQ(*value, "oddlepoddle");
1151 // Check default behavior
1152 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1153 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1154 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1155}
1156
1157
1158int echo_indexed_call_count = 0;
1159
1160
1161static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1162 const AccessorInfo& info) {
1163 ApiTestFuzzer::Fuzz();
1164 CHECK_EQ(v8_num(637), info.Data());
1165 echo_indexed_call_count++;
1166 return v8_num(index);
1167}
1168
1169
1170THREADED_TEST(IndexedPropertyHandlerGetter) {
1171 v8::HandleScope scope;
1172 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1173 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1174 0, 0, 0, 0,
1175 v8_num(637));
1176 LocalContext env;
1177 env->Global()->Set(v8_str("obj"),
1178 templ->GetFunction()->NewInstance());
1179 Local<Script> script = v8_compile("obj[900]");
1180 CHECK_EQ(script->Run()->Int32Value(), 900);
1181}
1182
1183
1184v8::Handle<v8::Object> bottom;
1185
1186static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1187 uint32_t index,
1188 const AccessorInfo& info) {
1189 ApiTestFuzzer::Fuzz();
1190 CHECK(info.This()->Equals(bottom));
1191 return v8::Handle<Value>();
1192}
1193
1194static v8::Handle<Value> CheckThisNamedPropertyHandler(
1195 Local<String> name,
1196 const AccessorInfo& info) {
1197 ApiTestFuzzer::Fuzz();
1198 CHECK(info.This()->Equals(bottom));
1199 return v8::Handle<Value>();
1200}
1201
1202
1203v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1204 Local<Value> value,
1205 const AccessorInfo& info) {
1206 ApiTestFuzzer::Fuzz();
1207 CHECK(info.This()->Equals(bottom));
1208 return v8::Handle<Value>();
1209}
1210
1211
1212v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1213 Local<Value> value,
1214 const AccessorInfo& info) {
1215 ApiTestFuzzer::Fuzz();
1216 CHECK(info.This()->Equals(bottom));
1217 return v8::Handle<Value>();
1218}
1219
Iain Merrick75681382010-08-19 15:07:18 +01001220v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 uint32_t index,
1222 const AccessorInfo& info) {
1223 ApiTestFuzzer::Fuzz();
1224 CHECK(info.This()->Equals(bottom));
Iain Merrick75681382010-08-19 15:07:18 +01001225 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001226}
1227
1228
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001229v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
Steve Blocka7e24c12009-10-30 11:49:00 +00001230 const AccessorInfo& info) {
1231 ApiTestFuzzer::Fuzz();
1232 CHECK(info.This()->Equals(bottom));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001233 return v8::Handle<v8::Integer>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001234}
1235
1236
1237v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1238 uint32_t index,
1239 const AccessorInfo& info) {
1240 ApiTestFuzzer::Fuzz();
1241 CHECK(info.This()->Equals(bottom));
1242 return v8::Handle<v8::Boolean>();
1243}
1244
1245
1246v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1247 Local<String> property,
1248 const AccessorInfo& info) {
1249 ApiTestFuzzer::Fuzz();
1250 CHECK(info.This()->Equals(bottom));
1251 return v8::Handle<v8::Boolean>();
1252}
1253
1254
1255v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1256 const AccessorInfo& info) {
1257 ApiTestFuzzer::Fuzz();
1258 CHECK(info.This()->Equals(bottom));
1259 return v8::Handle<v8::Array>();
1260}
1261
1262
1263v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1264 const AccessorInfo& info) {
1265 ApiTestFuzzer::Fuzz();
1266 CHECK(info.This()->Equals(bottom));
1267 return v8::Handle<v8::Array>();
1268}
1269
1270
1271THREADED_TEST(PropertyHandlerInPrototype) {
1272 v8::HandleScope scope;
1273 LocalContext env;
1274
1275 // Set up a prototype chain with three interceptors.
1276 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1277 templ->InstanceTemplate()->SetIndexedPropertyHandler(
1278 CheckThisIndexedPropertyHandler,
1279 CheckThisIndexedPropertySetter,
1280 CheckThisIndexedPropertyQuery,
1281 CheckThisIndexedPropertyDeleter,
1282 CheckThisIndexedPropertyEnumerator);
1283
1284 templ->InstanceTemplate()->SetNamedPropertyHandler(
1285 CheckThisNamedPropertyHandler,
1286 CheckThisNamedPropertySetter,
1287 CheckThisNamedPropertyQuery,
1288 CheckThisNamedPropertyDeleter,
1289 CheckThisNamedPropertyEnumerator);
1290
1291 bottom = templ->GetFunction()->NewInstance();
1292 Local<v8::Object> top = templ->GetFunction()->NewInstance();
1293 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1294
1295 bottom->Set(v8_str("__proto__"), middle);
1296 middle->Set(v8_str("__proto__"), top);
1297 env->Global()->Set(v8_str("obj"), bottom);
1298
1299 // Indexed and named get.
1300 Script::Compile(v8_str("obj[0]"))->Run();
1301 Script::Compile(v8_str("obj.x"))->Run();
1302
1303 // Indexed and named set.
1304 Script::Compile(v8_str("obj[1] = 42"))->Run();
1305 Script::Compile(v8_str("obj.y = 42"))->Run();
1306
1307 // Indexed and named query.
1308 Script::Compile(v8_str("0 in obj"))->Run();
1309 Script::Compile(v8_str("'x' in obj"))->Run();
1310
1311 // Indexed and named deleter.
1312 Script::Compile(v8_str("delete obj[0]"))->Run();
1313 Script::Compile(v8_str("delete obj.x"))->Run();
1314
1315 // Enumerators.
1316 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1317}
1318
1319
1320static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1321 const AccessorInfo& info) {
1322 ApiTestFuzzer::Fuzz();
1323 if (v8_str("pre")->Equals(key)) {
1324 return v8_str("PrePropertyHandler: pre");
1325 }
1326 return v8::Handle<String>();
1327}
1328
1329
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001330static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1331 const AccessorInfo&) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001332 if (v8_str("pre")->Equals(key)) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001333 return v8::Integer::New(v8::None);
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 }
1335
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001336 return v8::Handle<v8::Integer>(); // do not intercept the call
Steve Blocka7e24c12009-10-30 11:49:00 +00001337}
1338
1339
1340THREADED_TEST(PrePropertyHandler) {
1341 v8::HandleScope scope;
1342 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1343 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1344 0,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001345 PrePropertyHandlerQuery);
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 LocalContext env(NULL, desc->InstanceTemplate());
1347 Script::Compile(v8_str(
1348 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1349 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1350 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1351 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1352 CHECK_EQ(v8_str("Object: on"), result_on);
1353 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1354 CHECK(result_post.IsEmpty());
1355}
1356
1357
1358THREADED_TEST(UndefinedIsNotEnumerable) {
1359 v8::HandleScope scope;
1360 LocalContext env;
1361 v8::Handle<Value> result = Script::Compile(v8_str(
1362 "this.propertyIsEnumerable(undefined)"))->Run();
1363 CHECK(result->IsFalse());
1364}
1365
1366
1367v8::Handle<Script> call_recursively_script;
Leon Clarke4515c472010-02-03 11:58:03 +00001368static const int kTargetRecursionDepth = 200; // near maximum
Steve Blocka7e24c12009-10-30 11:49:00 +00001369
1370
1371static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1372 ApiTestFuzzer::Fuzz();
1373 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1374 if (depth == kTargetRecursionDepth) return v8::Undefined();
1375 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1376 return call_recursively_script->Run();
1377}
1378
1379
1380static v8::Handle<Value> CallFunctionRecursivelyCall(
1381 const v8::Arguments& args) {
1382 ApiTestFuzzer::Fuzz();
1383 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1384 if (depth == kTargetRecursionDepth) {
1385 printf("[depth = %d]\n", depth);
1386 return v8::Undefined();
1387 }
1388 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1389 v8::Handle<Value> function =
1390 args.This()->Get(v8_str("callFunctionRecursively"));
Steve Block6ded16b2010-05-10 14:33:55 +01001391 return function.As<Function>()->Call(args.This(), 0, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001392}
1393
1394
1395THREADED_TEST(DeepCrossLanguageRecursion) {
1396 v8::HandleScope scope;
1397 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1398 global->Set(v8_str("callScriptRecursively"),
1399 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1400 global->Set(v8_str("callFunctionRecursively"),
1401 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1402 LocalContext env(NULL, global);
1403
1404 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1405 call_recursively_script = v8_compile("callScriptRecursively()");
1406 v8::Handle<Value> result = call_recursively_script->Run();
1407 call_recursively_script = v8::Handle<Script>();
1408
1409 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1410 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1411}
1412
1413
1414static v8::Handle<Value>
1415 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1416 ApiTestFuzzer::Fuzz();
1417 return v8::ThrowException(key);
1418}
1419
1420
1421static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1422 Local<Value>,
1423 const AccessorInfo&) {
1424 v8::ThrowException(key);
1425 return v8::Undefined(); // not the same as v8::Handle<v8::Value>()
1426}
1427
1428
1429THREADED_TEST(CallbackExceptionRegression) {
1430 v8::HandleScope scope;
1431 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1432 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1433 ThrowingPropertyHandlerSet);
1434 LocalContext env;
1435 env->Global()->Set(v8_str("obj"), obj->NewInstance());
1436 v8::Handle<Value> otto = Script::Compile(v8_str(
1437 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1438 CHECK_EQ(v8_str("otto"), otto);
1439 v8::Handle<Value> netto = Script::Compile(v8_str(
1440 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1441 CHECK_EQ(v8_str("netto"), netto);
1442}
1443
1444
Steve Blocka7e24c12009-10-30 11:49:00 +00001445THREADED_TEST(FunctionPrototype) {
1446 v8::HandleScope scope;
1447 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1448 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1449 LocalContext env;
1450 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1451 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1452 CHECK_EQ(script->Run()->Int32Value(), 321);
1453}
1454
1455
1456THREADED_TEST(InternalFields) {
1457 v8::HandleScope scope;
1458 LocalContext env;
1459
1460 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1461 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1462 instance_templ->SetInternalFieldCount(1);
1463 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1464 CHECK_EQ(1, obj->InternalFieldCount());
1465 CHECK(obj->GetInternalField(0)->IsUndefined());
1466 obj->SetInternalField(0, v8_num(17));
1467 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1468}
1469
1470
Steve Block6ded16b2010-05-10 14:33:55 +01001471THREADED_TEST(GlobalObjectInternalFields) {
1472 v8::HandleScope scope;
1473 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1474 global_template->SetInternalFieldCount(1);
1475 LocalContext env(NULL, global_template);
1476 v8::Handle<v8::Object> global_proxy = env->Global();
1477 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1478 CHECK_EQ(1, global->InternalFieldCount());
1479 CHECK(global->GetInternalField(0)->IsUndefined());
1480 global->SetInternalField(0, v8_num(17));
1481 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1482}
1483
1484
Steve Blocka7e24c12009-10-30 11:49:00 +00001485THREADED_TEST(InternalFieldsNativePointers) {
1486 v8::HandleScope scope;
1487 LocalContext env;
1488
1489 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1490 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1491 instance_templ->SetInternalFieldCount(1);
1492 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1493 CHECK_EQ(1, obj->InternalFieldCount());
1494 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1495
1496 char* data = new char[100];
1497
1498 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001499 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001501 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Blocka7e24c12009-10-30 11:49:00 +00001502
1503 // Check reading and writing aligned pointers.
1504 obj->SetPointerInInternalField(0, aligned);
1505 i::Heap::CollectAllGarbage(false);
1506 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1507
1508 // Check reading and writing unaligned pointers.
1509 obj->SetPointerInInternalField(0, unaligned);
1510 i::Heap::CollectAllGarbage(false);
1511 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1512
1513 delete[] data;
1514}
1515
1516
Steve Block3ce2e202009-11-05 08:53:23 +00001517THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1518 v8::HandleScope scope;
1519 LocalContext env;
1520
1521 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1522 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1523 instance_templ->SetInternalFieldCount(1);
1524 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1525 CHECK_EQ(1, obj->InternalFieldCount());
1526 CHECK(obj->GetPointerFromInternalField(0) == NULL);
1527
1528 char* data = new char[100];
1529
1530 void* aligned = data;
Ben Murdochf87a2032010-10-22 12:50:53 +01001531 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001532 void* unaligned = data + 1;
Ben Murdochf87a2032010-10-22 12:50:53 +01001533 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
Steve Block3ce2e202009-11-05 08:53:23 +00001534
1535 obj->SetPointerInInternalField(0, aligned);
1536 i::Heap::CollectAllGarbage(false);
1537 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1538
1539 obj->SetPointerInInternalField(0, unaligned);
1540 i::Heap::CollectAllGarbage(false);
1541 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1542
1543 obj->SetInternalField(0, v8::External::Wrap(aligned));
1544 i::Heap::CollectAllGarbage(false);
1545 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1546
1547 obj->SetInternalField(0, v8::External::Wrap(unaligned));
1548 i::Heap::CollectAllGarbage(false);
1549 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1550
1551 delete[] data;
1552}
1553
1554
Steve Blocka7e24c12009-10-30 11:49:00 +00001555THREADED_TEST(IdentityHash) {
1556 v8::HandleScope scope;
1557 LocalContext env;
1558
1559 // Ensure that the test starts with an fresh heap to test whether the hash
1560 // code is based on the address.
1561 i::Heap::CollectAllGarbage(false);
1562 Local<v8::Object> obj = v8::Object::New();
1563 int hash = obj->GetIdentityHash();
1564 int hash1 = obj->GetIdentityHash();
1565 CHECK_EQ(hash, hash1);
1566 int hash2 = v8::Object::New()->GetIdentityHash();
1567 // Since the identity hash is essentially a random number two consecutive
1568 // objects should not be assigned the same hash code. If the test below fails
1569 // the random number generator should be evaluated.
1570 CHECK_NE(hash, hash2);
1571 i::Heap::CollectAllGarbage(false);
1572 int hash3 = v8::Object::New()->GetIdentityHash();
1573 // Make sure that the identity hash is not based on the initial address of
1574 // the object alone. If the test below fails the random number generator
1575 // should be evaluated.
1576 CHECK_NE(hash, hash3);
1577 int hash4 = obj->GetIdentityHash();
1578 CHECK_EQ(hash, hash4);
1579}
1580
1581
1582THREADED_TEST(HiddenProperties) {
1583 v8::HandleScope scope;
1584 LocalContext env;
1585
1586 v8::Local<v8::Object> obj = v8::Object::New();
1587 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1588 v8::Local<v8::String> empty = v8_str("");
1589 v8::Local<v8::String> prop_name = v8_str("prop_name");
1590
1591 i::Heap::CollectAllGarbage(false);
1592
1593 // Make sure delete of a non-existent hidden value works
1594 CHECK(obj->DeleteHiddenValue(key));
1595
1596 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1597 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1598 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1599 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1600
1601 i::Heap::CollectAllGarbage(false);
1602
1603 // Make sure we do not find the hidden property.
1604 CHECK(!obj->Has(empty));
1605 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1606 CHECK(obj->Get(empty)->IsUndefined());
1607 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1608 CHECK(obj->Set(empty, v8::Integer::New(2003)));
1609 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1610 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1611
1612 i::Heap::CollectAllGarbage(false);
1613
1614 // Add another property and delete it afterwards to force the object in
1615 // slow case.
1616 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1617 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1618 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1619 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1620 CHECK(obj->Delete(prop_name));
1621 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1622
1623 i::Heap::CollectAllGarbage(false);
1624
1625 CHECK(obj->DeleteHiddenValue(key));
1626 CHECK(obj->GetHiddenValue(key).IsEmpty());
1627}
1628
1629
Steve Blockd0582a62009-12-15 09:54:21 +00001630static bool interceptor_for_hidden_properties_called;
Steve Blocka7e24c12009-10-30 11:49:00 +00001631static v8::Handle<Value> InterceptorForHiddenProperties(
1632 Local<String> name, const AccessorInfo& info) {
Steve Blockd0582a62009-12-15 09:54:21 +00001633 interceptor_for_hidden_properties_called = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 return v8::Handle<Value>();
1635}
1636
1637
1638THREADED_TEST(HiddenPropertiesWithInterceptors) {
1639 v8::HandleScope scope;
1640 LocalContext context;
1641
Steve Blockd0582a62009-12-15 09:54:21 +00001642 interceptor_for_hidden_properties_called = false;
1643
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1645
1646 // Associate an interceptor with an object and start setting hidden values.
1647 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1648 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1649 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1650 Local<v8::Function> function = fun_templ->GetFunction();
1651 Local<v8::Object> obj = function->NewInstance();
1652 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1653 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
Steve Blockd0582a62009-12-15 09:54:21 +00001654 CHECK(!interceptor_for_hidden_properties_called);
Steve Blocka7e24c12009-10-30 11:49:00 +00001655}
1656
1657
1658THREADED_TEST(External) {
1659 v8::HandleScope scope;
1660 int x = 3;
1661 Local<v8::External> ext = v8::External::New(&x);
1662 LocalContext env;
1663 env->Global()->Set(v8_str("ext"), ext);
1664 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001665 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001666 int* ptr = static_cast<int*>(reext->Value());
1667 CHECK_EQ(x, 3);
1668 *ptr = 10;
1669 CHECK_EQ(x, 10);
1670
1671 // Make sure unaligned pointers are wrapped properly.
1672 char* data = i::StrDup("0123456789");
1673 Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1674 Local<v8::Value> one = v8::External::Wrap(&data[1]);
1675 Local<v8::Value> two = v8::External::Wrap(&data[2]);
1676 Local<v8::Value> three = v8::External::Wrap(&data[3]);
1677
1678 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1679 CHECK_EQ('0', *char_ptr);
1680 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1681 CHECK_EQ('1', *char_ptr);
1682 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1683 CHECK_EQ('2', *char_ptr);
1684 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1685 CHECK_EQ('3', *char_ptr);
1686 i::DeleteArray(data);
1687}
1688
1689
1690THREADED_TEST(GlobalHandle) {
1691 v8::Persistent<String> global;
1692 {
1693 v8::HandleScope scope;
1694 Local<String> str = v8_str("str");
1695 global = v8::Persistent<String>::New(str);
1696 }
1697 CHECK_EQ(global->Length(), 3);
1698 global.Dispose();
1699}
1700
1701
1702THREADED_TEST(ScriptException) {
1703 v8::HandleScope scope;
1704 LocalContext env;
1705 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1706 v8::TryCatch try_catch;
1707 Local<Value> result = script->Run();
1708 CHECK(result.IsEmpty());
1709 CHECK(try_catch.HasCaught());
1710 String::AsciiValue exception_value(try_catch.Exception());
1711 CHECK_EQ(*exception_value, "panama!");
1712}
1713
1714
1715bool message_received;
1716
1717
1718static void check_message(v8::Handle<v8::Message> message,
1719 v8::Handle<Value> data) {
1720 CHECK_EQ(5.76, data->NumberValue());
1721 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1722 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1723 message_received = true;
1724}
1725
1726
1727THREADED_TEST(MessageHandlerData) {
1728 message_received = false;
1729 v8::HandleScope scope;
1730 CHECK(!message_received);
1731 v8::V8::AddMessageListener(check_message, v8_num(5.76));
1732 LocalContext context;
1733 v8::ScriptOrigin origin =
1734 v8::ScriptOrigin(v8_str("6.75"));
1735 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1736 &origin);
1737 script->SetData(v8_str("7.56"));
1738 script->Run();
1739 CHECK(message_received);
1740 // clear out the message listener
1741 v8::V8::RemoveMessageListeners(check_message);
1742}
1743
1744
1745THREADED_TEST(GetSetProperty) {
1746 v8::HandleScope scope;
1747 LocalContext context;
1748 context->Global()->Set(v8_str("foo"), v8_num(14));
1749 context->Global()->Set(v8_str("12"), v8_num(92));
1750 context->Global()->Set(v8::Integer::New(16), v8_num(32));
1751 context->Global()->Set(v8_num(13), v8_num(56));
1752 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1753 CHECK_EQ(14, foo->Int32Value());
1754 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1755 CHECK_EQ(92, twelve->Int32Value());
1756 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1757 CHECK_EQ(32, sixteen->Int32Value());
1758 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1759 CHECK_EQ(56, thirteen->Int32Value());
1760 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1761 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1762 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1763 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1764 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1765 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1766 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1767 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1768 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1769}
1770
1771
1772THREADED_TEST(PropertyAttributes) {
1773 v8::HandleScope scope;
1774 LocalContext context;
1775 // read-only
1776 Local<String> prop = v8_str("read_only");
1777 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1778 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1779 Script::Compile(v8_str("read_only = 9"))->Run();
1780 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1781 context->Global()->Set(prop, v8_num(10));
1782 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1783 // dont-delete
1784 prop = v8_str("dont_delete");
1785 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1786 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1787 Script::Compile(v8_str("delete dont_delete"))->Run();
1788 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1789}
1790
1791
1792THREADED_TEST(Array) {
1793 v8::HandleScope scope;
1794 LocalContext context;
1795 Local<v8::Array> array = v8::Array::New();
1796 CHECK_EQ(0, array->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001797 CHECK(array->Get(0)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 CHECK(!array->Has(0));
Steve Block6ded16b2010-05-10 14:33:55 +01001799 CHECK(array->Get(100)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 CHECK(!array->Has(100));
Steve Block6ded16b2010-05-10 14:33:55 +01001801 array->Set(2, v8_num(7));
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 CHECK_EQ(3, array->Length());
1803 CHECK(!array->Has(0));
1804 CHECK(!array->Has(1));
1805 CHECK(array->Has(2));
Steve Block6ded16b2010-05-10 14:33:55 +01001806 CHECK_EQ(7, array->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001807 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01001808 Local<v8::Array> arr = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001809 CHECK_EQ(3, arr->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001810 CHECK_EQ(1, arr->Get(0)->Int32Value());
1811 CHECK_EQ(2, arr->Get(1)->Int32Value());
1812 CHECK_EQ(3, arr->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001813}
1814
1815
1816v8::Handle<Value> HandleF(const v8::Arguments& args) {
1817 v8::HandleScope scope;
1818 ApiTestFuzzer::Fuzz();
1819 Local<v8::Array> result = v8::Array::New(args.Length());
1820 for (int i = 0; i < args.Length(); i++)
Steve Block6ded16b2010-05-10 14:33:55 +01001821 result->Set(i, args[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001822 return scope.Close(result);
1823}
1824
1825
1826THREADED_TEST(Vector) {
1827 v8::HandleScope scope;
1828 Local<ObjectTemplate> global = ObjectTemplate::New();
1829 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1830 LocalContext context(0, global);
1831
1832 const char* fun = "f()";
Steve Block6ded16b2010-05-10 14:33:55 +01001833 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001834 CHECK_EQ(0, a0->Length());
1835
1836 const char* fun2 = "f(11)";
Steve Block6ded16b2010-05-10 14:33:55 +01001837 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 CHECK_EQ(1, a1->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001839 CHECK_EQ(11, a1->Get(0)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001840
1841 const char* fun3 = "f(12, 13)";
Steve Block6ded16b2010-05-10 14:33:55 +01001842 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001843 CHECK_EQ(2, a2->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001844 CHECK_EQ(12, a2->Get(0)->Int32Value());
1845 CHECK_EQ(13, a2->Get(1)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001846
1847 const char* fun4 = "f(14, 15, 16)";
Steve Block6ded16b2010-05-10 14:33:55 +01001848 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001849 CHECK_EQ(3, a3->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001850 CHECK_EQ(14, a3->Get(0)->Int32Value());
1851 CHECK_EQ(15, a3->Get(1)->Int32Value());
1852 CHECK_EQ(16, a3->Get(2)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001853
1854 const char* fun5 = "f(17, 18, 19, 20)";
Steve Block6ded16b2010-05-10 14:33:55 +01001855 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 CHECK_EQ(4, a4->Length());
Steve Block6ded16b2010-05-10 14:33:55 +01001857 CHECK_EQ(17, a4->Get(0)->Int32Value());
1858 CHECK_EQ(18, a4->Get(1)->Int32Value());
1859 CHECK_EQ(19, a4->Get(2)->Int32Value());
1860 CHECK_EQ(20, a4->Get(3)->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001861}
1862
1863
1864THREADED_TEST(FunctionCall) {
1865 v8::HandleScope scope;
1866 LocalContext context;
1867 CompileRun(
1868 "function Foo() {"
1869 " var result = [];"
1870 " for (var i = 0; i < arguments.length; i++) {"
1871 " result.push(arguments[i]);"
1872 " }"
1873 " return result;"
1874 "}");
1875 Local<Function> Foo =
1876 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1877
1878 v8::Handle<Value>* args0 = NULL;
1879 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1880 CHECK_EQ(0, a0->Length());
1881
1882 v8::Handle<Value> args1[] = { v8_num(1.1) };
1883 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1884 CHECK_EQ(1, a1->Length());
1885 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1886
1887 v8::Handle<Value> args2[] = { v8_num(2.2),
1888 v8_num(3.3) };
1889 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1890 CHECK_EQ(2, a2->Length());
1891 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1892 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1893
1894 v8::Handle<Value> args3[] = { v8_num(4.4),
1895 v8_num(5.5),
1896 v8_num(6.6) };
1897 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1898 CHECK_EQ(3, a3->Length());
1899 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1900 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1901 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1902
1903 v8::Handle<Value> args4[] = { v8_num(7.7),
1904 v8_num(8.8),
1905 v8_num(9.9),
1906 v8_num(10.11) };
1907 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1908 CHECK_EQ(4, a4->Length());
1909 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1910 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1911 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1912 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1913}
1914
1915
1916static const char* js_code_causing_out_of_memory =
1917 "var a = new Array(); while(true) a.push(a);";
1918
1919
1920// These tests run for a long time and prevent us from running tests
1921// that come after them so they cannot run in parallel.
1922TEST(OutOfMemory) {
1923 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01001924 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001925 // Set heap limits.
1926 static const int K = 1024;
1927 v8::ResourceConstraints constraints;
1928 constraints.set_max_young_space_size(256 * K);
1929 constraints.set_max_old_space_size(4 * K * K);
1930 v8::SetResourceConstraints(&constraints);
1931
1932 // Execute a script that causes out of memory.
1933 v8::HandleScope scope;
1934 LocalContext context;
1935 v8::V8::IgnoreOutOfMemoryException();
1936 Local<Script> script =
1937 Script::Compile(String::New(js_code_causing_out_of_memory));
1938 Local<Value> result = script->Run();
1939
1940 // Check for out of memory state.
1941 CHECK(result.IsEmpty());
1942 CHECK(context->HasOutOfMemoryException());
1943}
1944
1945
1946v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1947 ApiTestFuzzer::Fuzz();
1948
1949 v8::HandleScope scope;
1950 LocalContext context;
1951 Local<Script> script =
1952 Script::Compile(String::New(js_code_causing_out_of_memory));
1953 Local<Value> result = script->Run();
1954
1955 // Check for out of memory state.
1956 CHECK(result.IsEmpty());
1957 CHECK(context->HasOutOfMemoryException());
1958
1959 return result;
1960}
1961
1962
1963TEST(OutOfMemoryNested) {
1964 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01001965 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 // Set heap limits.
1967 static const int K = 1024;
1968 v8::ResourceConstraints constraints;
1969 constraints.set_max_young_space_size(256 * K);
1970 constraints.set_max_old_space_size(4 * K * K);
1971 v8::SetResourceConstraints(&constraints);
1972
1973 v8::HandleScope scope;
1974 Local<ObjectTemplate> templ = ObjectTemplate::New();
1975 templ->Set(v8_str("ProvokeOutOfMemory"),
1976 v8::FunctionTemplate::New(ProvokeOutOfMemory));
1977 LocalContext context(0, templ);
1978 v8::V8::IgnoreOutOfMemoryException();
1979 Local<Value> result = CompileRun(
1980 "var thrown = false;"
1981 "try {"
1982 " ProvokeOutOfMemory();"
1983 "} catch (e) {"
1984 " thrown = true;"
1985 "}");
1986 // Check for out of memory state.
1987 CHECK(result.IsEmpty());
1988 CHECK(context->HasOutOfMemoryException());
1989}
1990
1991
1992TEST(HugeConsStringOutOfMemory) {
1993 // It's not possible to read a snapshot into a heap with different dimensions.
Steve Block8defd9f2010-07-08 12:39:36 +01001994 if (i::Snapshot::IsEnabled()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001995 v8::HandleScope scope;
1996 LocalContext context;
1997 // Set heap limits.
1998 static const int K = 1024;
1999 v8::ResourceConstraints constraints;
2000 constraints.set_max_young_space_size(256 * K);
2001 constraints.set_max_old_space_size(2 * K * K);
2002 v8::SetResourceConstraints(&constraints);
2003
2004 // Execute a script that causes out of memory.
2005 v8::V8::IgnoreOutOfMemoryException();
2006
2007 // Build huge string. This should fail with out of memory exception.
2008 Local<Value> result = CompileRun(
2009 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
Steve Block3ce2e202009-11-05 08:53:23 +00002010 "for (var i = 0; i < 22; i++) { str = str + str; }");
Steve Blocka7e24c12009-10-30 11:49:00 +00002011
2012 // Check for out of memory state.
2013 CHECK(result.IsEmpty());
2014 CHECK(context->HasOutOfMemoryException());
2015}
2016
2017
2018THREADED_TEST(ConstructCall) {
2019 v8::HandleScope scope;
2020 LocalContext context;
2021 CompileRun(
2022 "function Foo() {"
2023 " var result = [];"
2024 " for (var i = 0; i < arguments.length; i++) {"
2025 " result.push(arguments[i]);"
2026 " }"
2027 " return result;"
2028 "}");
2029 Local<Function> Foo =
2030 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2031
2032 v8::Handle<Value>* args0 = NULL;
2033 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2034 CHECK_EQ(0, a0->Length());
2035
2036 v8::Handle<Value> args1[] = { v8_num(1.1) };
2037 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2038 CHECK_EQ(1, a1->Length());
2039 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2040
2041 v8::Handle<Value> args2[] = { v8_num(2.2),
2042 v8_num(3.3) };
2043 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2044 CHECK_EQ(2, a2->Length());
2045 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2046 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2047
2048 v8::Handle<Value> args3[] = { v8_num(4.4),
2049 v8_num(5.5),
2050 v8_num(6.6) };
2051 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2052 CHECK_EQ(3, a3->Length());
2053 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2054 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2055 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2056
2057 v8::Handle<Value> args4[] = { v8_num(7.7),
2058 v8_num(8.8),
2059 v8_num(9.9),
2060 v8_num(10.11) };
2061 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2062 CHECK_EQ(4, a4->Length());
2063 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2064 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2065 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2066 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2067}
2068
2069
2070static void CheckUncle(v8::TryCatch* try_catch) {
2071 CHECK(try_catch->HasCaught());
2072 String::AsciiValue str_value(try_catch->Exception());
2073 CHECK_EQ(*str_value, "uncle?");
2074 try_catch->Reset();
2075}
2076
2077
Steve Block6ded16b2010-05-10 14:33:55 +01002078THREADED_TEST(ConversionNumber) {
2079 v8::HandleScope scope;
2080 LocalContext env;
2081 // Very large number.
2082 CompileRun("var obj = Math.pow(2,32) * 1237;");
2083 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2084 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2085 CHECK_EQ(0, obj->ToInt32()->Value());
2086 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
2087 // Large number.
2088 CompileRun("var obj = -1234567890123;");
2089 obj = env->Global()->Get(v8_str("obj"));
2090 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2091 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2092 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
2093 // Small positive integer.
2094 CompileRun("var obj = 42;");
2095 obj = env->Global()->Get(v8_str("obj"));
2096 CHECK_EQ(42.0, obj->ToNumber()->Value());
2097 CHECK_EQ(42, obj->ToInt32()->Value());
2098 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2099 // Negative integer.
2100 CompileRun("var obj = -37;");
2101 obj = env->Global()->Get(v8_str("obj"));
2102 CHECK_EQ(-37.0, obj->ToNumber()->Value());
2103 CHECK_EQ(-37, obj->ToInt32()->Value());
2104 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
2105 // Positive non-int32 integer.
2106 CompileRun("var obj = 0x81234567;");
2107 obj = env->Global()->Get(v8_str("obj"));
2108 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2109 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2110 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
2111 // Fraction.
2112 CompileRun("var obj = 42.3;");
2113 obj = env->Global()->Get(v8_str("obj"));
2114 CHECK_EQ(42.3, obj->ToNumber()->Value());
2115 CHECK_EQ(42, obj->ToInt32()->Value());
2116 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
2117 // Large negative fraction.
2118 CompileRun("var obj = -5726623061.75;");
2119 obj = env->Global()->Get(v8_str("obj"));
2120 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2121 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2122 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
2123}
2124
2125
2126THREADED_TEST(isNumberType) {
2127 v8::HandleScope scope;
2128 LocalContext env;
2129 // Very large number.
2130 CompileRun("var obj = Math.pow(2,32) * 1237;");
2131 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2132 CHECK(!obj->IsInt32());
2133 CHECK(!obj->IsUint32());
2134 // Large negative number.
2135 CompileRun("var obj = -1234567890123;");
2136 obj = env->Global()->Get(v8_str("obj"));
2137 CHECK(!obj->IsInt32());
2138 CHECK(!obj->IsUint32());
2139 // Small positive integer.
2140 CompileRun("var obj = 42;");
2141 obj = env->Global()->Get(v8_str("obj"));
2142 CHECK(obj->IsInt32());
2143 CHECK(obj->IsUint32());
2144 // Negative integer.
2145 CompileRun("var obj = -37;");
2146 obj = env->Global()->Get(v8_str("obj"));
2147 CHECK(obj->IsInt32());
2148 CHECK(!obj->IsUint32());
2149 // Positive non-int32 integer.
2150 CompileRun("var obj = 0x81234567;");
2151 obj = env->Global()->Get(v8_str("obj"));
2152 CHECK(!obj->IsInt32());
2153 CHECK(obj->IsUint32());
2154 // Fraction.
2155 CompileRun("var obj = 42.3;");
2156 obj = env->Global()->Get(v8_str("obj"));
2157 CHECK(!obj->IsInt32());
2158 CHECK(!obj->IsUint32());
2159 // Large negative fraction.
2160 CompileRun("var obj = -5726623061.75;");
2161 obj = env->Global()->Get(v8_str("obj"));
2162 CHECK(!obj->IsInt32());
2163 CHECK(!obj->IsUint32());
2164}
2165
2166
Steve Blocka7e24c12009-10-30 11:49:00 +00002167THREADED_TEST(ConversionException) {
2168 v8::HandleScope scope;
2169 LocalContext env;
2170 CompileRun(
2171 "function TestClass() { };"
2172 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2173 "var obj = new TestClass();");
2174 Local<Value> obj = env->Global()->Get(v8_str("obj"));
2175
2176 v8::TryCatch try_catch;
2177
2178 Local<Value> to_string_result = obj->ToString();
2179 CHECK(to_string_result.IsEmpty());
2180 CheckUncle(&try_catch);
2181
2182 Local<Value> to_number_result = obj->ToNumber();
2183 CHECK(to_number_result.IsEmpty());
2184 CheckUncle(&try_catch);
2185
2186 Local<Value> to_integer_result = obj->ToInteger();
2187 CHECK(to_integer_result.IsEmpty());
2188 CheckUncle(&try_catch);
2189
2190 Local<Value> to_uint32_result = obj->ToUint32();
2191 CHECK(to_uint32_result.IsEmpty());
2192 CheckUncle(&try_catch);
2193
2194 Local<Value> to_int32_result = obj->ToInt32();
2195 CHECK(to_int32_result.IsEmpty());
2196 CheckUncle(&try_catch);
2197
2198 Local<Value> to_object_result = v8::Undefined()->ToObject();
2199 CHECK(to_object_result.IsEmpty());
2200 CHECK(try_catch.HasCaught());
2201 try_catch.Reset();
2202
2203 int32_t int32_value = obj->Int32Value();
2204 CHECK_EQ(0, int32_value);
2205 CheckUncle(&try_catch);
2206
2207 uint32_t uint32_value = obj->Uint32Value();
2208 CHECK_EQ(0, uint32_value);
2209 CheckUncle(&try_catch);
2210
2211 double number_value = obj->NumberValue();
2212 CHECK_NE(0, IsNaN(number_value));
2213 CheckUncle(&try_catch);
2214
2215 int64_t integer_value = obj->IntegerValue();
2216 CHECK_EQ(0.0, static_cast<double>(integer_value));
2217 CheckUncle(&try_catch);
2218}
2219
2220
2221v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2222 ApiTestFuzzer::Fuzz();
2223 return v8::ThrowException(v8_str("konto"));
2224}
2225
2226
2227v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2228 if (args.Length() < 1) return v8::Boolean::New(false);
2229 v8::HandleScope scope;
2230 v8::TryCatch try_catch;
2231 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2232 CHECK(!try_catch.HasCaught() || result.IsEmpty());
2233 return v8::Boolean::New(try_catch.HasCaught());
2234}
2235
2236
2237THREADED_TEST(APICatch) {
2238 v8::HandleScope scope;
2239 Local<ObjectTemplate> templ = ObjectTemplate::New();
2240 templ->Set(v8_str("ThrowFromC"),
2241 v8::FunctionTemplate::New(ThrowFromC));
2242 LocalContext context(0, templ);
2243 CompileRun(
2244 "var thrown = false;"
2245 "try {"
2246 " ThrowFromC();"
2247 "} catch (e) {"
2248 " thrown = true;"
2249 "}");
2250 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2251 CHECK(thrown->BooleanValue());
2252}
2253
2254
2255THREADED_TEST(APIThrowTryCatch) {
2256 v8::HandleScope scope;
2257 Local<ObjectTemplate> templ = ObjectTemplate::New();
2258 templ->Set(v8_str("ThrowFromC"),
2259 v8::FunctionTemplate::New(ThrowFromC));
2260 LocalContext context(0, templ);
2261 v8::TryCatch try_catch;
2262 CompileRun("ThrowFromC();");
2263 CHECK(try_catch.HasCaught());
2264}
2265
2266
2267// Test that a try-finally block doesn't shadow a try-catch block
2268// when setting up an external handler.
2269//
2270// BUG(271): Some of the exception propagation does not work on the
2271// ARM simulator because the simulator separates the C++ stack and the
2272// JS stack. This test therefore fails on the simulator. The test is
2273// not threaded to allow the threading tests to run on the simulator.
2274TEST(TryCatchInTryFinally) {
2275 v8::HandleScope scope;
2276 Local<ObjectTemplate> templ = ObjectTemplate::New();
2277 templ->Set(v8_str("CCatcher"),
2278 v8::FunctionTemplate::New(CCatcher));
2279 LocalContext context(0, templ);
2280 Local<Value> result = CompileRun("try {"
2281 " try {"
2282 " CCatcher('throw 7;');"
2283 " } finally {"
2284 " }"
2285 "} catch (e) {"
2286 "}");
2287 CHECK(result->IsTrue());
2288}
2289
2290
2291static void receive_message(v8::Handle<v8::Message> message,
2292 v8::Handle<v8::Value> data) {
2293 message->Get();
2294 message_received = true;
2295}
2296
2297
2298TEST(APIThrowMessage) {
2299 message_received = false;
2300 v8::HandleScope scope;
2301 v8::V8::AddMessageListener(receive_message);
2302 Local<ObjectTemplate> templ = ObjectTemplate::New();
2303 templ->Set(v8_str("ThrowFromC"),
2304 v8::FunctionTemplate::New(ThrowFromC));
2305 LocalContext context(0, templ);
2306 CompileRun("ThrowFromC();");
2307 CHECK(message_received);
2308 v8::V8::RemoveMessageListeners(check_message);
2309}
2310
2311
2312TEST(APIThrowMessageAndVerboseTryCatch) {
2313 message_received = false;
2314 v8::HandleScope scope;
2315 v8::V8::AddMessageListener(receive_message);
2316 Local<ObjectTemplate> templ = ObjectTemplate::New();
2317 templ->Set(v8_str("ThrowFromC"),
2318 v8::FunctionTemplate::New(ThrowFromC));
2319 LocalContext context(0, templ);
2320 v8::TryCatch try_catch;
2321 try_catch.SetVerbose(true);
2322 Local<Value> result = CompileRun("ThrowFromC();");
2323 CHECK(try_catch.HasCaught());
2324 CHECK(result.IsEmpty());
2325 CHECK(message_received);
2326 v8::V8::RemoveMessageListeners(check_message);
2327}
2328
2329
2330THREADED_TEST(ExternalScriptException) {
2331 v8::HandleScope scope;
2332 Local<ObjectTemplate> templ = ObjectTemplate::New();
2333 templ->Set(v8_str("ThrowFromC"),
2334 v8::FunctionTemplate::New(ThrowFromC));
2335 LocalContext context(0, templ);
2336
2337 v8::TryCatch try_catch;
2338 Local<Script> script
2339 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2340 Local<Value> result = script->Run();
2341 CHECK(result.IsEmpty());
2342 CHECK(try_catch.HasCaught());
2343 String::AsciiValue exception_value(try_catch.Exception());
2344 CHECK_EQ("konto", *exception_value);
2345}
2346
2347
2348
2349v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2350 ApiTestFuzzer::Fuzz();
2351 CHECK_EQ(4, args.Length());
2352 int count = args[0]->Int32Value();
2353 int cInterval = args[2]->Int32Value();
2354 if (count == 0) {
2355 return v8::ThrowException(v8_str("FromC"));
2356 } else {
2357 Local<v8::Object> global = Context::GetCurrent()->Global();
2358 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2359 v8::Handle<Value> argv[] = { v8_num(count - 1),
2360 args[1],
2361 args[2],
2362 args[3] };
2363 if (count % cInterval == 0) {
2364 v8::TryCatch try_catch;
Steve Block6ded16b2010-05-10 14:33:55 +01002365 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002366 int expected = args[3]->Int32Value();
2367 if (try_catch.HasCaught()) {
2368 CHECK_EQ(expected, count);
2369 CHECK(result.IsEmpty());
2370 CHECK(!i::Top::has_scheduled_exception());
2371 } else {
2372 CHECK_NE(expected, count);
2373 }
2374 return result;
2375 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002376 return fun.As<Function>()->Call(global, 4, argv);
Steve Blocka7e24c12009-10-30 11:49:00 +00002377 }
2378 }
2379}
2380
2381
2382v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2383 ApiTestFuzzer::Fuzz();
2384 CHECK_EQ(3, args.Length());
2385 bool equality = args[0]->BooleanValue();
2386 int count = args[1]->Int32Value();
2387 int expected = args[2]->Int32Value();
2388 if (equality) {
2389 CHECK_EQ(count, expected);
2390 } else {
2391 CHECK_NE(count, expected);
2392 }
2393 return v8::Undefined();
2394}
2395
2396
2397THREADED_TEST(EvalInTryFinally) {
2398 v8::HandleScope scope;
2399 LocalContext context;
2400 v8::TryCatch try_catch;
2401 CompileRun("(function() {"
2402 " try {"
2403 " eval('asldkf (*&^&*^');"
2404 " } finally {"
2405 " return;"
2406 " }"
2407 "})()");
2408 CHECK(!try_catch.HasCaught());
2409}
2410
2411
2412// This test works by making a stack of alternating JavaScript and C
2413// activations. These activations set up exception handlers with regular
2414// intervals, one interval for C activations and another for JavaScript
2415// activations. When enough activations have been created an exception is
2416// thrown and we check that the right activation catches the exception and that
2417// no other activations do. The right activation is always the topmost one with
2418// a handler, regardless of whether it is in JavaScript or C.
2419//
2420// The notation used to describe a test case looks like this:
2421//
2422// *JS[4] *C[3] @JS[2] C[1] JS[0]
2423//
2424// Each entry is an activation, either JS or C. The index is the count at that
2425// level. Stars identify activations with exception handlers, the @ identifies
2426// the exception handler that should catch the exception.
2427//
2428// BUG(271): Some of the exception propagation does not work on the
2429// ARM simulator because the simulator separates the C++ stack and the
2430// JS stack. This test therefore fails on the simulator. The test is
2431// not threaded to allow the threading tests to run on the simulator.
2432TEST(ExceptionOrder) {
2433 v8::HandleScope scope;
2434 Local<ObjectTemplate> templ = ObjectTemplate::New();
2435 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2436 templ->Set(v8_str("CThrowCountDown"),
2437 v8::FunctionTemplate::New(CThrowCountDown));
2438 LocalContext context(0, templ);
2439 CompileRun(
2440 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2441 " if (count == 0) throw 'FromJS';"
2442 " if (count % jsInterval == 0) {"
2443 " try {"
2444 " var value = CThrowCountDown(count - 1,"
2445 " jsInterval,"
2446 " cInterval,"
2447 " expected);"
2448 " check(false, count, expected);"
2449 " return value;"
2450 " } catch (e) {"
2451 " check(true, count, expected);"
2452 " }"
2453 " } else {"
2454 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2455 " }"
2456 "}");
2457 Local<Function> fun =
2458 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2459
2460 const int argc = 4;
2461 // count jsInterval cInterval expected
2462
2463 // *JS[4] *C[3] @JS[2] C[1] JS[0]
2464 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2465 fun->Call(fun, argc, a0);
2466
2467 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2468 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2469 fun->Call(fun, argc, a1);
2470
2471 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2472 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2473 fun->Call(fun, argc, a2);
2474
2475 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2476 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2477 fun->Call(fun, argc, a3);
2478
2479 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2480 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2481 fun->Call(fun, argc, a4);
2482
2483 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2484 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2485 fun->Call(fun, argc, a5);
2486}
2487
2488
2489v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2490 ApiTestFuzzer::Fuzz();
2491 CHECK_EQ(1, args.Length());
2492 return v8::ThrowException(args[0]);
2493}
2494
2495
2496THREADED_TEST(ThrowValues) {
2497 v8::HandleScope scope;
2498 Local<ObjectTemplate> templ = ObjectTemplate::New();
2499 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2500 LocalContext context(0, templ);
2501 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2502 "function Run(obj) {"
2503 " try {"
2504 " Throw(obj);"
2505 " } catch (e) {"
2506 " return e;"
2507 " }"
2508 " return 'no exception';"
2509 "}"
2510 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2511 CHECK_EQ(5, result->Length());
2512 CHECK(result->Get(v8::Integer::New(0))->IsString());
2513 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2514 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2515 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2516 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2517 CHECK(result->Get(v8::Integer::New(3))->IsNull());
2518 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2519}
2520
2521
2522THREADED_TEST(CatchZero) {
2523 v8::HandleScope scope;
2524 LocalContext context;
2525 v8::TryCatch try_catch;
2526 CHECK(!try_catch.HasCaught());
2527 Script::Compile(v8_str("throw 10"))->Run();
2528 CHECK(try_catch.HasCaught());
2529 CHECK_EQ(10, try_catch.Exception()->Int32Value());
2530 try_catch.Reset();
2531 CHECK(!try_catch.HasCaught());
2532 Script::Compile(v8_str("throw 0"))->Run();
2533 CHECK(try_catch.HasCaught());
2534 CHECK_EQ(0, try_catch.Exception()->Int32Value());
2535}
2536
2537
2538THREADED_TEST(CatchExceptionFromWith) {
2539 v8::HandleScope scope;
2540 LocalContext context;
2541 v8::TryCatch try_catch;
2542 CHECK(!try_catch.HasCaught());
2543 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2544 CHECK(try_catch.HasCaught());
2545}
2546
2547
2548THREADED_TEST(Equality) {
2549 v8::HandleScope scope;
2550 LocalContext context;
2551 // Check that equality works at all before relying on CHECK_EQ
2552 CHECK(v8_str("a")->Equals(v8_str("a")));
2553 CHECK(!v8_str("a")->Equals(v8_str("b")));
2554
2555 CHECK_EQ(v8_str("a"), v8_str("a"));
2556 CHECK_NE(v8_str("a"), v8_str("b"));
2557 CHECK_EQ(v8_num(1), v8_num(1));
2558 CHECK_EQ(v8_num(1.00), v8_num(1));
2559 CHECK_NE(v8_num(1), v8_num(2));
2560
2561 // Assume String is not symbol.
2562 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2563 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2564 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2565 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2566 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2567 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2568 Local<Value> not_a_number = v8_num(i::OS::nan_value());
2569 CHECK(!not_a_number->StrictEquals(not_a_number));
2570 CHECK(v8::False()->StrictEquals(v8::False()));
2571 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2572
2573 v8::Handle<v8::Object> obj = v8::Object::New();
2574 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2575 CHECK(alias->StrictEquals(obj));
2576 alias.Dispose();
2577}
2578
2579
2580THREADED_TEST(MultiRun) {
2581 v8::HandleScope scope;
2582 LocalContext context;
2583 Local<Script> script = Script::Compile(v8_str("x"));
2584 for (int i = 0; i < 10; i++)
2585 script->Run();
2586}
2587
2588
2589static v8::Handle<Value> GetXValue(Local<String> name,
2590 const AccessorInfo& info) {
2591 ApiTestFuzzer::Fuzz();
2592 CHECK_EQ(info.Data(), v8_str("donut"));
2593 CHECK_EQ(name, v8_str("x"));
2594 return name;
2595}
2596
2597
2598THREADED_TEST(SimplePropertyRead) {
2599 v8::HandleScope scope;
2600 Local<ObjectTemplate> templ = ObjectTemplate::New();
2601 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2602 LocalContext context;
2603 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2604 Local<Script> script = Script::Compile(v8_str("obj.x"));
2605 for (int i = 0; i < 10; i++) {
2606 Local<Value> result = script->Run();
2607 CHECK_EQ(result, v8_str("x"));
2608 }
2609}
2610
Andrei Popescu31002712010-02-23 13:46:05 +00002611THREADED_TEST(DefinePropertyOnAPIAccessor) {
2612 v8::HandleScope scope;
2613 Local<ObjectTemplate> templ = ObjectTemplate::New();
2614 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2615 LocalContext context;
2616 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2617
2618 // Uses getOwnPropertyDescriptor to check the configurable status
2619 Local<Script> script_desc
Leon Clarkef7060e22010-06-03 12:02:55 +01002620 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
Andrei Popescu31002712010-02-23 13:46:05 +00002621 "obj, 'x');"
2622 "prop.configurable;"));
2623 Local<Value> result = script_desc->Run();
2624 CHECK_EQ(result->BooleanValue(), true);
2625
2626 // Redefine get - but still configurable
2627 Local<Script> script_define
2628 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2629 " configurable: true };"
2630 "Object.defineProperty(obj, 'x', desc);"
2631 "obj.x"));
2632 result = script_define->Run();
2633 CHECK_EQ(result, v8_num(42));
2634
2635 // Check that the accessor is still configurable
2636 result = script_desc->Run();
2637 CHECK_EQ(result->BooleanValue(), true);
2638
2639 // Redefine to a non-configurable
2640 script_define
2641 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2642 " configurable: false };"
2643 "Object.defineProperty(obj, 'x', desc);"
2644 "obj.x"));
2645 result = script_define->Run();
2646 CHECK_EQ(result, v8_num(43));
2647 result = script_desc->Run();
2648 CHECK_EQ(result->BooleanValue(), false);
2649
2650 // Make sure that it is not possible to redefine again
2651 v8::TryCatch try_catch;
2652 result = script_define->Run();
2653 CHECK(try_catch.HasCaught());
2654 String::AsciiValue exception_value(try_catch.Exception());
2655 CHECK_EQ(*exception_value,
2656 "TypeError: Cannot redefine property: defineProperty");
2657}
2658
2659THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2660 v8::HandleScope scope;
2661 Local<ObjectTemplate> templ = ObjectTemplate::New();
2662 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2663 LocalContext context;
2664 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2665
2666 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2667 "Object.getOwnPropertyDescriptor( "
2668 "obj, 'x');"
2669 "prop.configurable;"));
2670 Local<Value> result = script_desc->Run();
2671 CHECK_EQ(result->BooleanValue(), true);
2672
2673 Local<Script> script_define =
2674 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2675 " configurable: true };"
2676 "Object.defineProperty(obj, 'x', desc);"
2677 "obj.x"));
2678 result = script_define->Run();
2679 CHECK_EQ(result, v8_num(42));
2680
2681
2682 result = script_desc->Run();
2683 CHECK_EQ(result->BooleanValue(), true);
2684
2685
2686 script_define =
2687 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2688 " configurable: false };"
2689 "Object.defineProperty(obj, 'x', desc);"
2690 "obj.x"));
2691 result = script_define->Run();
2692 CHECK_EQ(result, v8_num(43));
2693 result = script_desc->Run();
2694
2695 CHECK_EQ(result->BooleanValue(), false);
2696
2697 v8::TryCatch try_catch;
2698 result = script_define->Run();
2699 CHECK(try_catch.HasCaught());
2700 String::AsciiValue exception_value(try_catch.Exception());
2701 CHECK_EQ(*exception_value,
2702 "TypeError: Cannot redefine property: defineProperty");
2703}
2704
2705
Leon Clarkef7060e22010-06-03 12:02:55 +01002706static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
2707 char const* name) {
2708 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
2709}
Andrei Popescu31002712010-02-23 13:46:05 +00002710
2711
Leon Clarkef7060e22010-06-03 12:02:55 +01002712THREADED_TEST(DefineAPIAccessorOnObject) {
2713 v8::HandleScope scope;
2714 Local<ObjectTemplate> templ = ObjectTemplate::New();
2715 LocalContext context;
2716
2717 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2718 CompileRun("var obj2 = {};");
2719
2720 CHECK(CompileRun("obj1.x")->IsUndefined());
2721 CHECK(CompileRun("obj2.x")->IsUndefined());
2722
2723 CHECK(GetGlobalProperty(&context, "obj1")->
2724 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2725
2726 ExpectString("obj1.x", "x");
2727 CHECK(CompileRun("obj2.x")->IsUndefined());
2728
2729 CHECK(GetGlobalProperty(&context, "obj2")->
2730 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2731
2732 ExpectString("obj1.x", "x");
2733 ExpectString("obj2.x", "x");
2734
2735 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2736 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2737
2738 CompileRun("Object.defineProperty(obj1, 'x',"
2739 "{ get: function() { return 'y'; }, configurable: true })");
2740
2741 ExpectString("obj1.x", "y");
2742 ExpectString("obj2.x", "x");
2743
2744 CompileRun("Object.defineProperty(obj2, 'x',"
2745 "{ get: function() { return 'y'; }, configurable: true })");
2746
2747 ExpectString("obj1.x", "y");
2748 ExpectString("obj2.x", "y");
2749
2750 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2751 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2752
2753 CHECK(GetGlobalProperty(&context, "obj1")->
2754 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2755 CHECK(GetGlobalProperty(&context, "obj2")->
2756 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2757
2758 ExpectString("obj1.x", "x");
2759 ExpectString("obj2.x", "x");
2760
2761 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2762 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2763
2764 // Define getters/setters, but now make them not configurable.
2765 CompileRun("Object.defineProperty(obj1, 'x',"
2766 "{ get: function() { return 'z'; }, configurable: false })");
2767 CompileRun("Object.defineProperty(obj2, 'x',"
2768 "{ get: function() { return 'z'; }, configurable: false })");
2769
2770 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2771 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2772
2773 ExpectString("obj1.x", "z");
2774 ExpectString("obj2.x", "z");
2775
2776 CHECK(!GetGlobalProperty(&context, "obj1")->
2777 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2778 CHECK(!GetGlobalProperty(&context, "obj2")->
2779 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2780
2781 ExpectString("obj1.x", "z");
2782 ExpectString("obj2.x", "z");
2783}
2784
2785
2786THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
2787 v8::HandleScope scope;
2788 Local<ObjectTemplate> templ = ObjectTemplate::New();
2789 LocalContext context;
2790
2791 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2792 CompileRun("var obj2 = {};");
2793
2794 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2795 v8_str("x"),
2796 GetXValue, NULL,
2797 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2798 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2799 v8_str("x"),
2800 GetXValue, NULL,
2801 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
2802
2803 ExpectString("obj1.x", "x");
2804 ExpectString("obj2.x", "x");
2805
2806 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
2807 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
2808
2809 CHECK(!GetGlobalProperty(&context, "obj1")->
2810 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2811 CHECK(!GetGlobalProperty(&context, "obj2")->
2812 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
2813
2814 {
2815 v8::TryCatch try_catch;
2816 CompileRun("Object.defineProperty(obj1, 'x',"
2817 "{get: function() { return 'func'; }})");
2818 CHECK(try_catch.HasCaught());
2819 String::AsciiValue exception_value(try_catch.Exception());
2820 CHECK_EQ(*exception_value,
2821 "TypeError: Cannot redefine property: defineProperty");
2822 }
2823 {
2824 v8::TryCatch try_catch;
2825 CompileRun("Object.defineProperty(obj2, 'x',"
2826 "{get: function() { return 'func'; }})");
2827 CHECK(try_catch.HasCaught());
2828 String::AsciiValue exception_value(try_catch.Exception());
2829 CHECK_EQ(*exception_value,
2830 "TypeError: Cannot redefine property: defineProperty");
2831 }
2832}
2833
2834
2835static v8::Handle<Value> Get239Value(Local<String> name,
2836 const AccessorInfo& info) {
2837 ApiTestFuzzer::Fuzz();
2838 CHECK_EQ(info.Data(), v8_str("donut"));
2839 CHECK_EQ(name, v8_str("239"));
2840 return name;
2841}
2842
2843
2844THREADED_TEST(ElementAPIAccessor) {
2845 v8::HandleScope scope;
2846 Local<ObjectTemplate> templ = ObjectTemplate::New();
2847 LocalContext context;
2848
2849 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
2850 CompileRun("var obj2 = {};");
2851
2852 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
2853 v8_str("239"),
2854 Get239Value, NULL,
2855 v8_str("donut")));
2856 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
2857 v8_str("239"),
2858 Get239Value, NULL,
2859 v8_str("donut")));
2860
2861 ExpectString("obj1[239]", "239");
2862 ExpectString("obj2[239]", "239");
2863 ExpectString("obj1['239']", "239");
2864 ExpectString("obj2['239']", "239");
2865}
2866
Steve Blocka7e24c12009-10-30 11:49:00 +00002867
2868v8::Persistent<Value> xValue;
2869
2870
2871static void SetXValue(Local<String> name,
2872 Local<Value> value,
2873 const AccessorInfo& info) {
2874 CHECK_EQ(value, v8_num(4));
2875 CHECK_EQ(info.Data(), v8_str("donut"));
2876 CHECK_EQ(name, v8_str("x"));
2877 CHECK(xValue.IsEmpty());
2878 xValue = v8::Persistent<Value>::New(value);
2879}
2880
2881
2882THREADED_TEST(SimplePropertyWrite) {
2883 v8::HandleScope scope;
2884 Local<ObjectTemplate> templ = ObjectTemplate::New();
2885 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2886 LocalContext context;
2887 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2888 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2889 for (int i = 0; i < 10; i++) {
2890 CHECK(xValue.IsEmpty());
2891 script->Run();
2892 CHECK_EQ(v8_num(4), xValue);
2893 xValue.Dispose();
2894 xValue = v8::Persistent<Value>();
2895 }
2896}
2897
2898
2899static v8::Handle<Value> XPropertyGetter(Local<String> property,
2900 const AccessorInfo& info) {
2901 ApiTestFuzzer::Fuzz();
2902 CHECK(info.Data()->IsUndefined());
2903 return property;
2904}
2905
2906
2907THREADED_TEST(NamedInterceptorPropertyRead) {
2908 v8::HandleScope scope;
2909 Local<ObjectTemplate> templ = ObjectTemplate::New();
2910 templ->SetNamedPropertyHandler(XPropertyGetter);
2911 LocalContext context;
2912 context->Global()->Set(v8_str("obj"), templ->NewInstance());
2913 Local<Script> script = Script::Compile(v8_str("obj.x"));
2914 for (int i = 0; i < 10; i++) {
2915 Local<Value> result = script->Run();
2916 CHECK_EQ(result, v8_str("x"));
2917 }
2918}
2919
2920
Steve Block6ded16b2010-05-10 14:33:55 +01002921THREADED_TEST(NamedInterceptorDictionaryIC) {
2922 v8::HandleScope scope;
2923 Local<ObjectTemplate> templ = ObjectTemplate::New();
2924 templ->SetNamedPropertyHandler(XPropertyGetter);
2925 LocalContext context;
2926 // Create an object with a named interceptor.
2927 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
2928 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
2929 for (int i = 0; i < 10; i++) {
2930 Local<Value> result = script->Run();
2931 CHECK_EQ(result, v8_str("x"));
2932 }
2933 // Create a slow case object and a function accessing a property in
2934 // that slow case object (with dictionary probing in generated
2935 // code). Then force object with a named interceptor into slow-case,
2936 // pass it to the function, and check that the interceptor is called
2937 // instead of accessing the local property.
2938 Local<Value> result =
2939 CompileRun("function get_x(o) { return o.x; };"
2940 "var obj = { x : 42, y : 0 };"
2941 "delete obj.y;"
2942 "for (var i = 0; i < 10; i++) get_x(obj);"
2943 "interceptor_obj.x = 42;"
2944 "interceptor_obj.y = 10;"
2945 "delete interceptor_obj.y;"
2946 "get_x(interceptor_obj)");
2947 CHECK_EQ(result, v8_str("x"));
2948}
2949
2950
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002951THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
2952 v8::HandleScope scope;
2953
2954 v8::Persistent<Context> context1 = Context::New();
2955
2956 context1->Enter();
2957 Local<ObjectTemplate> templ = ObjectTemplate::New();
2958 templ->SetNamedPropertyHandler(XPropertyGetter);
2959 // Create an object with a named interceptor.
2960 v8::Local<v8::Object> object = templ->NewInstance();
2961 context1->Global()->Set(v8_str("interceptor_obj"), object);
2962
2963 // Force the object into the slow case.
2964 CompileRun("interceptor_obj.y = 0;"
2965 "delete interceptor_obj.y;");
2966 context1->Exit();
2967
2968 {
2969 // Introduce the object into a different context.
2970 // Repeat named loads to exercise ICs.
2971 LocalContext context2;
2972 context2->Global()->Set(v8_str("interceptor_obj"), object);
2973 Local<Value> result =
2974 CompileRun("function get_x(o) { return o.x; }"
2975 "interceptor_obj.x = 42;"
2976 "for (var i=0; i != 10; i++) {"
2977 " get_x(interceptor_obj);"
2978 "}"
2979 "get_x(interceptor_obj)");
2980 // Check that the interceptor was actually invoked.
2981 CHECK_EQ(result, v8_str("x"));
2982 }
2983
2984 // Return to the original context and force some object to the slow case
2985 // to cause the NormalizedMapCache to verify.
2986 context1->Enter();
2987 CompileRun("var obj = { x : 0 }; delete obj.x;");
2988 context1->Exit();
2989
2990 context1.Dispose();
2991}
2992
2993
Andrei Popescu402d9372010-02-26 13:31:12 +00002994static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2995 const AccessorInfo& info) {
2996 // Set x on the prototype object and do not handle the get request.
2997 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
Steve Block6ded16b2010-05-10 14:33:55 +01002998 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
Andrei Popescu402d9372010-02-26 13:31:12 +00002999 return v8::Handle<Value>();
3000}
3001
3002
3003// This is a regression test for http://crbug.com/20104. Map
3004// transitions should not interfere with post interceptor lookup.
3005THREADED_TEST(NamedInterceptorMapTransitionRead) {
3006 v8::HandleScope scope;
3007 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3008 Local<v8::ObjectTemplate> instance_template
3009 = function_template->InstanceTemplate();
3010 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3011 LocalContext context;
3012 context->Global()->Set(v8_str("F"), function_template->GetFunction());
3013 // Create an instance of F and introduce a map transition for x.
3014 CompileRun("var o = new F(); o.x = 23;");
3015 // Create an instance of F and invoke the getter. The result should be 23.
3016 Local<Value> result = CompileRun("o = new F(); o.x");
3017 CHECK_EQ(result->Int32Value(), 23);
3018}
3019
3020
Steve Blocka7e24c12009-10-30 11:49:00 +00003021static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3022 const AccessorInfo& info) {
3023 ApiTestFuzzer::Fuzz();
3024 if (index == 37) {
3025 return v8::Handle<Value>(v8_num(625));
3026 }
3027 return v8::Handle<Value>();
3028}
3029
3030
3031static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3032 Local<Value> value,
3033 const AccessorInfo& info) {
3034 ApiTestFuzzer::Fuzz();
3035 if (index == 39) {
3036 return value;
3037 }
3038 return v8::Handle<Value>();
3039}
3040
3041
3042THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3043 v8::HandleScope scope;
3044 Local<ObjectTemplate> templ = ObjectTemplate::New();
3045 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3046 IndexedPropertySetter);
3047 LocalContext context;
3048 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3049 Local<Script> getter_script = Script::Compile(v8_str(
3050 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3051 Local<Script> setter_script = Script::Compile(v8_str(
3052 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3053 "obj[17] = 23;"
3054 "obj.foo;"));
3055 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3056 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3057 "obj[39] = 47;"
3058 "obj.foo;")); // This setter should not run, due to the interceptor.
3059 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3060 "obj[37];"));
3061 Local<Value> result = getter_script->Run();
3062 CHECK_EQ(v8_num(5), result);
3063 result = setter_script->Run();
3064 CHECK_EQ(v8_num(23), result);
3065 result = interceptor_setter_script->Run();
3066 CHECK_EQ(v8_num(23), result);
3067 result = interceptor_getter_script->Run();
3068 CHECK_EQ(v8_num(625), result);
3069}
3070
3071
Leon Clarked91b9f72010-01-27 17:25:45 +00003072static v8::Handle<Value> IdentityIndexedPropertyGetter(
3073 uint32_t index,
3074 const AccessorInfo& info) {
Ben Murdochf87a2032010-10-22 12:50:53 +01003075 return v8::Integer::NewFromUnsigned(index);
Leon Clarked91b9f72010-01-27 17:25:45 +00003076}
3077
3078
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003079THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3080 v8::HandleScope scope;
3081 Local<ObjectTemplate> templ = ObjectTemplate::New();
3082 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3083
3084 LocalContext context;
3085 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3086
3087 // Check fast object case.
3088 const char* fast_case_code =
3089 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3090 ExpectString(fast_case_code, "0");
3091
3092 // Check slow case.
3093 const char* slow_case_code =
3094 "obj.x = 1; delete obj.x;"
3095 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3096 ExpectString(slow_case_code, "1");
3097}
3098
3099
Leon Clarked91b9f72010-01-27 17:25:45 +00003100THREADED_TEST(IndexedInterceptorWithNoSetter) {
3101 v8::HandleScope scope;
3102 Local<ObjectTemplate> templ = ObjectTemplate::New();
3103 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3104
3105 LocalContext context;
3106 context->Global()->Set(v8_str("obj"), templ->NewInstance());
3107
3108 const char* code =
3109 "try {"
3110 " obj[0] = 239;"
3111 " for (var i = 0; i < 100; i++) {"
3112 " var v = obj[0];"
3113 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3114 " }"
3115 " 'PASSED'"
3116 "} catch(e) {"
3117 " e"
3118 "}";
3119 ExpectString(code, "PASSED");
3120}
3121
3122
Andrei Popescu402d9372010-02-26 13:31:12 +00003123THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3124 v8::HandleScope scope;
3125 Local<ObjectTemplate> templ = ObjectTemplate::New();
3126 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3127
3128 LocalContext context;
3129 Local<v8::Object> obj = templ->NewInstance();
3130 obj->TurnOnAccessCheck();
3131 context->Global()->Set(v8_str("obj"), obj);
3132
3133 const char* code =
3134 "try {"
3135 " for (var i = 0; i < 100; i++) {"
3136 " var v = obj[0];"
3137 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3138 " }"
3139 " 'PASSED'"
3140 "} catch(e) {"
3141 " e"
3142 "}";
3143 ExpectString(code, "PASSED");
3144}
3145
3146
3147THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3148 i::FLAG_allow_natives_syntax = true;
3149 v8::HandleScope scope;
3150 Local<ObjectTemplate> templ = ObjectTemplate::New();
3151 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3152
3153 LocalContext context;
3154 Local<v8::Object> obj = templ->NewInstance();
3155 context->Global()->Set(v8_str("obj"), obj);
3156
3157 const char* code =
3158 "try {"
3159 " for (var i = 0; i < 100; i++) {"
3160 " var expected = i;"
3161 " if (i == 5) {"
3162 " %EnableAccessChecks(obj);"
3163 " expected = undefined;"
3164 " }"
3165 " var v = obj[i];"
3166 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3167 " if (i == 5) %DisableAccessChecks(obj);"
3168 " }"
3169 " 'PASSED'"
3170 "} catch(e) {"
3171 " e"
3172 "}";
3173 ExpectString(code, "PASSED");
3174}
3175
3176
3177THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
3178 v8::HandleScope scope;
3179 Local<ObjectTemplate> templ = ObjectTemplate::New();
3180 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3181
3182 LocalContext context;
3183 Local<v8::Object> obj = templ->NewInstance();
3184 context->Global()->Set(v8_str("obj"), obj);
3185
3186 const char* code =
3187 "try {"
3188 " for (var i = 0; i < 100; i++) {"
3189 " var v = obj[i];"
3190 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3191 " }"
3192 " 'PASSED'"
3193 "} catch(e) {"
3194 " e"
3195 "}";
3196 ExpectString(code, "PASSED");
3197}
3198
3199
Ben Murdochf87a2032010-10-22 12:50:53 +01003200THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
3201 v8::HandleScope scope;
3202 Local<ObjectTemplate> templ = ObjectTemplate::New();
3203 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3204
3205 LocalContext context;
3206 Local<v8::Object> obj = templ->NewInstance();
3207 context->Global()->Set(v8_str("obj"), obj);
3208
3209 const char* code =
3210 "try {"
3211 " for (var i = 0; i < 100; i++) {"
3212 " var expected = i;"
3213 " var key = i;"
3214 " if (i == 25) {"
3215 " key = -1;"
3216 " expected = undefined;"
3217 " }"
3218 " if (i == 50) {"
3219 " /* probe minimal Smi number on 32-bit platforms */"
3220 " key = -(1 << 30);"
3221 " expected = undefined;"
3222 " }"
3223 " if (i == 75) {"
3224 " /* probe minimal Smi number on 64-bit platforms */"
3225 " key = 1 << 31;"
3226 " expected = undefined;"
3227 " }"
3228 " var v = obj[key];"
3229 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3230 " }"
3231 " 'PASSED'"
3232 "} catch(e) {"
3233 " e"
3234 "}";
3235 ExpectString(code, "PASSED");
3236}
3237
3238
Andrei Popescu402d9372010-02-26 13:31:12 +00003239THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
3240 v8::HandleScope scope;
3241 Local<ObjectTemplate> templ = ObjectTemplate::New();
3242 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3243
3244 LocalContext context;
3245 Local<v8::Object> obj = templ->NewInstance();
3246 context->Global()->Set(v8_str("obj"), obj);
3247
3248 const char* code =
3249 "try {"
3250 " for (var i = 0; i < 100; i++) {"
3251 " var expected = i;"
Ben Murdochf87a2032010-10-22 12:50:53 +01003252 " var key = i;"
Andrei Popescu402d9372010-02-26 13:31:12 +00003253 " if (i == 50) {"
Ben Murdochf87a2032010-10-22 12:50:53 +01003254 " key = 'foobar';"
Andrei Popescu402d9372010-02-26 13:31:12 +00003255 " expected = undefined;"
3256 " }"
Ben Murdochf87a2032010-10-22 12:50:53 +01003257 " var v = obj[key];"
Andrei Popescu402d9372010-02-26 13:31:12 +00003258 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3259 " }"
3260 " 'PASSED'"
3261 "} catch(e) {"
3262 " e"
3263 "}";
3264 ExpectString(code, "PASSED");
3265}
3266
3267
3268THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
3269 v8::HandleScope scope;
3270 Local<ObjectTemplate> templ = ObjectTemplate::New();
3271 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3272
3273 LocalContext context;
3274 Local<v8::Object> obj = templ->NewInstance();
3275 context->Global()->Set(v8_str("obj"), obj);
3276
3277 const char* code =
3278 "var original = obj;"
3279 "try {"
3280 " for (var i = 0; i < 100; i++) {"
3281 " var expected = i;"
3282 " if (i == 50) {"
3283 " obj = {50: 'foobar'};"
3284 " expected = 'foobar';"
3285 " }"
3286 " var v = obj[i];"
3287 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3288 " if (i == 50) obj = original;"
3289 " }"
3290 " 'PASSED'"
3291 "} catch(e) {"
3292 " e"
3293 "}";
3294 ExpectString(code, "PASSED");
3295}
3296
3297
3298THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
3299 v8::HandleScope scope;
3300 Local<ObjectTemplate> templ = ObjectTemplate::New();
3301 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3302
3303 LocalContext context;
3304 Local<v8::Object> obj = templ->NewInstance();
3305 context->Global()->Set(v8_str("obj"), obj);
3306
3307 const char* code =
3308 "var original = obj;"
3309 "try {"
3310 " for (var i = 0; i < 100; i++) {"
3311 " var expected = i;"
3312 " if (i == 5) {"
3313 " obj = 239;"
3314 " expected = undefined;"
3315 " }"
3316 " var v = obj[i];"
3317 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
3318 " if (i == 5) obj = original;"
3319 " }"
3320 " 'PASSED'"
3321 "} catch(e) {"
3322 " e"
3323 "}";
3324 ExpectString(code, "PASSED");
3325}
3326
3327
3328THREADED_TEST(IndexedInterceptorOnProto) {
3329 v8::HandleScope scope;
3330 Local<ObjectTemplate> templ = ObjectTemplate::New();
3331 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3332
3333 LocalContext context;
3334 Local<v8::Object> obj = templ->NewInstance();
3335 context->Global()->Set(v8_str("obj"), obj);
3336
3337 const char* code =
3338 "var o = {__proto__: obj};"
3339 "try {"
3340 " for (var i = 0; i < 100; i++) {"
3341 " var v = o[i];"
3342 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
3343 " }"
3344 " 'PASSED'"
3345 "} catch(e) {"
3346 " e"
3347 "}";
3348 ExpectString(code, "PASSED");
3349}
3350
3351
Steve Blocka7e24c12009-10-30 11:49:00 +00003352THREADED_TEST(MultiContexts) {
3353 v8::HandleScope scope;
3354 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
3355 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
3356
3357 Local<String> password = v8_str("Password");
3358
3359 // Create an environment
3360 LocalContext context0(0, templ);
3361 context0->SetSecurityToken(password);
3362 v8::Handle<v8::Object> global0 = context0->Global();
3363 global0->Set(v8_str("custom"), v8_num(1234));
3364 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3365
3366 // Create an independent environment
3367 LocalContext context1(0, templ);
3368 context1->SetSecurityToken(password);
3369 v8::Handle<v8::Object> global1 = context1->Global();
3370 global1->Set(v8_str("custom"), v8_num(1234));
3371 CHECK_NE(global0, global1);
3372 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
3373 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
3374
3375 // Now create a new context with the old global
3376 LocalContext context2(0, templ, global1);
3377 context2->SetSecurityToken(password);
3378 v8::Handle<v8::Object> global2 = context2->Global();
3379 CHECK_EQ(global1, global2);
3380 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
3381 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
3382}
3383
3384
3385THREADED_TEST(FunctionPrototypeAcrossContexts) {
3386 // Make sure that functions created by cloning boilerplates cannot
3387 // communicate through their __proto__ field.
3388
3389 v8::HandleScope scope;
3390
3391 LocalContext env0;
3392 v8::Handle<v8::Object> global0 =
3393 env0->Global();
3394 v8::Handle<v8::Object> object0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003395 global0->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003396 v8::Handle<v8::Object> tostring0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003397 object0->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003398 v8::Handle<v8::Object> proto0 =
Steve Block6ded16b2010-05-10 14:33:55 +01003399 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003400 proto0->Set(v8_str("custom"), v8_num(1234));
3401
3402 LocalContext env1;
3403 v8::Handle<v8::Object> global1 =
3404 env1->Global();
3405 v8::Handle<v8::Object> object1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003406 global1->Get(v8_str("Object")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003407 v8::Handle<v8::Object> tostring1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003408 object1->Get(v8_str("toString")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003409 v8::Handle<v8::Object> proto1 =
Steve Block6ded16b2010-05-10 14:33:55 +01003410 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00003411 CHECK(!proto1->Has(v8_str("custom")));
3412}
3413
3414
3415THREADED_TEST(Regress892105) {
3416 // Make sure that object and array literals created by cloning
3417 // boilerplates cannot communicate through their __proto__
3418 // field. This is rather difficult to check, but we try to add stuff
3419 // to Object.prototype and Array.prototype and create a new
3420 // environment. This should succeed.
3421
3422 v8::HandleScope scope;
3423
3424 Local<String> source = v8_str("Object.prototype.obj = 1234;"
3425 "Array.prototype.arr = 4567;"
3426 "8901");
3427
3428 LocalContext env0;
3429 Local<Script> script0 = Script::Compile(source);
3430 CHECK_EQ(8901.0, script0->Run()->NumberValue());
3431
3432 LocalContext env1;
3433 Local<Script> script1 = Script::Compile(source);
3434 CHECK_EQ(8901.0, script1->Run()->NumberValue());
3435}
3436
3437
Steve Blocka7e24c12009-10-30 11:49:00 +00003438THREADED_TEST(UndetectableObject) {
3439 v8::HandleScope scope;
3440 LocalContext env;
3441
3442 Local<v8::FunctionTemplate> desc =
3443 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3444 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3445
3446 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3447 env->Global()->Set(v8_str("undetectable"), obj);
3448
3449 ExpectString("undetectable.toString()", "[object Object]");
3450 ExpectString("typeof undetectable", "undefined");
3451 ExpectString("typeof(undetectable)", "undefined");
3452 ExpectBoolean("typeof undetectable == 'undefined'", true);
3453 ExpectBoolean("typeof undetectable == 'object'", false);
3454 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3455 ExpectBoolean("!undetectable", true);
3456
3457 ExpectObject("true&&undetectable", obj);
3458 ExpectBoolean("false&&undetectable", false);
3459 ExpectBoolean("true||undetectable", true);
3460 ExpectObject("false||undetectable", obj);
3461
3462 ExpectObject("undetectable&&true", obj);
3463 ExpectObject("undetectable&&false", obj);
3464 ExpectBoolean("undetectable||true", true);
3465 ExpectBoolean("undetectable||false", false);
3466
3467 ExpectBoolean("undetectable==null", true);
3468 ExpectBoolean("null==undetectable", true);
3469 ExpectBoolean("undetectable==undefined", true);
3470 ExpectBoolean("undefined==undetectable", true);
3471 ExpectBoolean("undetectable==undetectable", true);
3472
3473
3474 ExpectBoolean("undetectable===null", false);
3475 ExpectBoolean("null===undetectable", false);
3476 ExpectBoolean("undetectable===undefined", false);
3477 ExpectBoolean("undefined===undetectable", false);
3478 ExpectBoolean("undetectable===undetectable", true);
3479}
3480
3481
Steve Block8defd9f2010-07-08 12:39:36 +01003482
3483THREADED_TEST(ExtensibleOnUndetectable) {
3484 v8::HandleScope scope;
3485 LocalContext env;
3486
3487 Local<v8::FunctionTemplate> desc =
3488 v8::FunctionTemplate::New(0, v8::Handle<Value>());
3489 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
3490
3491 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
3492 env->Global()->Set(v8_str("undetectable"), obj);
3493
3494 Local<String> source = v8_str("undetectable.x = 42;"
3495 "undetectable.x");
3496
3497 Local<Script> script = Script::Compile(source);
3498
3499 CHECK_EQ(v8::Integer::New(42), script->Run());
3500
3501 ExpectBoolean("Object.isExtensible(undetectable)", true);
3502
3503 source = v8_str("Object.preventExtensions(undetectable);");
3504 script = Script::Compile(source);
3505 script->Run();
3506 ExpectBoolean("Object.isExtensible(undetectable)", false);
3507
3508 source = v8_str("undetectable.y = 2000;");
3509 script = Script::Compile(source);
3510 v8::TryCatch try_catch;
3511 Local<Value> result = script->Run();
3512 CHECK(result.IsEmpty());
3513 CHECK(try_catch.HasCaught());
3514}
3515
3516
3517
Steve Blocka7e24c12009-10-30 11:49:00 +00003518THREADED_TEST(UndetectableString) {
3519 v8::HandleScope scope;
3520 LocalContext env;
3521
3522 Local<String> obj = String::NewUndetectable("foo");
3523 env->Global()->Set(v8_str("undetectable"), obj);
3524
3525 ExpectString("undetectable", "foo");
3526 ExpectString("typeof undetectable", "undefined");
3527 ExpectString("typeof(undetectable)", "undefined");
3528 ExpectBoolean("typeof undetectable == 'undefined'", true);
3529 ExpectBoolean("typeof undetectable == 'string'", false);
3530 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
3531 ExpectBoolean("!undetectable", true);
3532
3533 ExpectObject("true&&undetectable", obj);
3534 ExpectBoolean("false&&undetectable", false);
3535 ExpectBoolean("true||undetectable", true);
3536 ExpectObject("false||undetectable", obj);
3537
3538 ExpectObject("undetectable&&true", obj);
3539 ExpectObject("undetectable&&false", obj);
3540 ExpectBoolean("undetectable||true", true);
3541 ExpectBoolean("undetectable||false", false);
3542
3543 ExpectBoolean("undetectable==null", true);
3544 ExpectBoolean("null==undetectable", true);
3545 ExpectBoolean("undetectable==undefined", true);
3546 ExpectBoolean("undefined==undetectable", true);
3547 ExpectBoolean("undetectable==undetectable", true);
3548
3549
3550 ExpectBoolean("undetectable===null", false);
3551 ExpectBoolean("null===undetectable", false);
3552 ExpectBoolean("undetectable===undefined", false);
3553 ExpectBoolean("undefined===undetectable", false);
3554 ExpectBoolean("undetectable===undetectable", true);
3555}
3556
3557
3558template <typename T> static void USE(T) { }
3559
3560
3561// This test is not intended to be run, just type checked.
3562static void PersistentHandles() {
3563 USE(PersistentHandles);
3564 Local<String> str = v8_str("foo");
3565 v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3566 USE(p_str);
3567 Local<Script> scr = Script::Compile(v8_str(""));
3568 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3569 USE(p_scr);
3570 Local<ObjectTemplate> templ = ObjectTemplate::New();
3571 v8::Persistent<ObjectTemplate> p_templ =
3572 v8::Persistent<ObjectTemplate>::New(templ);
3573 USE(p_templ);
3574}
3575
3576
3577static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3578 ApiTestFuzzer::Fuzz();
3579 return v8::Undefined();
3580}
3581
3582
3583THREADED_TEST(GlobalObjectTemplate) {
3584 v8::HandleScope handle_scope;
3585 Local<ObjectTemplate> global_template = ObjectTemplate::New();
3586 global_template->Set(v8_str("JSNI_Log"),
3587 v8::FunctionTemplate::New(HandleLogDelegator));
3588 v8::Persistent<Context> context = Context::New(0, global_template);
3589 Context::Scope context_scope(context);
3590 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3591 context.Dispose();
3592}
3593
3594
3595static const char* kSimpleExtensionSource =
3596 "function Foo() {"
3597 " return 4;"
3598 "}";
3599
3600
3601THREADED_TEST(SimpleExtensions) {
3602 v8::HandleScope handle_scope;
3603 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3604 const char* extension_names[] = { "simpletest" };
3605 v8::ExtensionConfiguration extensions(1, extension_names);
3606 v8::Handle<Context> context = Context::New(&extensions);
3607 Context::Scope lock(context);
3608 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3609 CHECK_EQ(result, v8::Integer::New(4));
3610}
3611
3612
3613static const char* kEvalExtensionSource1 =
3614 "function UseEval1() {"
3615 " var x = 42;"
3616 " return eval('x');"
3617 "}";
3618
3619
3620static const char* kEvalExtensionSource2 =
3621 "(function() {"
3622 " var x = 42;"
3623 " function e() {"
3624 " return eval('x');"
3625 " }"
3626 " this.UseEval2 = e;"
3627 "})()";
3628
3629
3630THREADED_TEST(UseEvalFromExtension) {
3631 v8::HandleScope handle_scope;
3632 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3633 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3634 const char* extension_names[] = { "evaltest1", "evaltest2" };
3635 v8::ExtensionConfiguration extensions(2, extension_names);
3636 v8::Handle<Context> context = Context::New(&extensions);
3637 Context::Scope lock(context);
3638 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3639 CHECK_EQ(result, v8::Integer::New(42));
3640 result = Script::Compile(v8_str("UseEval2()"))->Run();
3641 CHECK_EQ(result, v8::Integer::New(42));
3642}
3643
3644
3645static const char* kWithExtensionSource1 =
3646 "function UseWith1() {"
3647 " var x = 42;"
3648 " with({x:87}) { return x; }"
3649 "}";
3650
3651
3652
3653static const char* kWithExtensionSource2 =
3654 "(function() {"
3655 " var x = 42;"
3656 " function e() {"
3657 " with ({x:87}) { return x; }"
3658 " }"
3659 " this.UseWith2 = e;"
3660 "})()";
3661
3662
3663THREADED_TEST(UseWithFromExtension) {
3664 v8::HandleScope handle_scope;
3665 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3666 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3667 const char* extension_names[] = { "withtest1", "withtest2" };
3668 v8::ExtensionConfiguration extensions(2, extension_names);
3669 v8::Handle<Context> context = Context::New(&extensions);
3670 Context::Scope lock(context);
3671 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3672 CHECK_EQ(result, v8::Integer::New(87));
3673 result = Script::Compile(v8_str("UseWith2()"))->Run();
3674 CHECK_EQ(result, v8::Integer::New(87));
3675}
3676
3677
3678THREADED_TEST(AutoExtensions) {
3679 v8::HandleScope handle_scope;
3680 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3681 extension->set_auto_enable(true);
3682 v8::RegisterExtension(extension);
3683 v8::Handle<Context> context = Context::New();
3684 Context::Scope lock(context);
3685 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3686 CHECK_EQ(result, v8::Integer::New(4));
3687}
3688
3689
Steve Blockd0582a62009-12-15 09:54:21 +00003690static const char* kSyntaxErrorInExtensionSource =
3691 "[";
3692
3693
3694// Test that a syntax error in an extension does not cause a fatal
3695// error but results in an empty context.
3696THREADED_TEST(SyntaxErrorExtensions) {
3697 v8::HandleScope handle_scope;
3698 v8::RegisterExtension(new Extension("syntaxerror",
3699 kSyntaxErrorInExtensionSource));
3700 const char* extension_names[] = { "syntaxerror" };
3701 v8::ExtensionConfiguration extensions(1, extension_names);
3702 v8::Handle<Context> context = Context::New(&extensions);
3703 CHECK(context.IsEmpty());
3704}
3705
3706
3707static const char* kExceptionInExtensionSource =
3708 "throw 42";
3709
3710
3711// Test that an exception when installing an extension does not cause
3712// a fatal error but results in an empty context.
3713THREADED_TEST(ExceptionExtensions) {
3714 v8::HandleScope handle_scope;
3715 v8::RegisterExtension(new Extension("exception",
3716 kExceptionInExtensionSource));
3717 const char* extension_names[] = { "exception" };
3718 v8::ExtensionConfiguration extensions(1, extension_names);
3719 v8::Handle<Context> context = Context::New(&extensions);
3720 CHECK(context.IsEmpty());
3721}
3722
3723
Iain Merrick9ac36c92010-09-13 15:29:50 +01003724static const char* kNativeCallInExtensionSource =
3725 "function call_runtime_last_index_of(x) {"
3726 " return %StringLastIndexOf(x, 'bob', 10);"
3727 "}";
3728
3729
3730static const char* kNativeCallTest =
3731 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
3732
3733// Test that a native runtime calls are supported in extensions.
3734THREADED_TEST(NativeCallInExtensions) {
3735 v8::HandleScope handle_scope;
3736 v8::RegisterExtension(new Extension("nativecall",
3737 kNativeCallInExtensionSource));
3738 const char* extension_names[] = { "nativecall" };
3739 v8::ExtensionConfiguration extensions(1, extension_names);
3740 v8::Handle<Context> context = Context::New(&extensions);
3741 Context::Scope lock(context);
3742 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
3743 CHECK_EQ(result, v8::Integer::New(3));
3744}
3745
3746
Steve Blocka7e24c12009-10-30 11:49:00 +00003747static void CheckDependencies(const char* name, const char* expected) {
3748 v8::HandleScope handle_scope;
3749 v8::ExtensionConfiguration config(1, &name);
3750 LocalContext context(&config);
3751 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3752}
3753
3754
3755/*
3756 * Configuration:
3757 *
3758 * /-- B <--\
3759 * A <- -- D <-- E
3760 * \-- C <--/
3761 */
3762THREADED_TEST(ExtensionDependency) {
3763 static const char* kEDeps[] = { "D" };
3764 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3765 static const char* kDDeps[] = { "B", "C" };
3766 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3767 static const char* kBCDeps[] = { "A" };
3768 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3769 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3770 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3771 CheckDependencies("A", "undefinedA");
3772 CheckDependencies("B", "undefinedAB");
3773 CheckDependencies("C", "undefinedAC");
3774 CheckDependencies("D", "undefinedABCD");
3775 CheckDependencies("E", "undefinedABCDE");
3776 v8::HandleScope handle_scope;
3777 static const char* exts[2] = { "C", "E" };
3778 v8::ExtensionConfiguration config(2, exts);
3779 LocalContext context(&config);
3780 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3781}
3782
3783
3784static const char* kExtensionTestScript =
3785 "native function A();"
3786 "native function B();"
3787 "native function C();"
3788 "function Foo(i) {"
3789 " if (i == 0) return A();"
3790 " if (i == 1) return B();"
3791 " if (i == 2) return C();"
3792 "}";
3793
3794
3795static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3796 ApiTestFuzzer::Fuzz();
Leon Clarkee46be812010-01-19 14:06:41 +00003797 if (args.IsConstructCall()) {
3798 args.This()->Set(v8_str("data"), args.Data());
3799 return v8::Null();
3800 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003801 return args.Data();
3802}
3803
3804
3805class FunctionExtension : public Extension {
3806 public:
3807 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3808 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3809 v8::Handle<String> name);
3810};
3811
3812
3813static int lookup_count = 0;
3814v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3815 v8::Handle<String> name) {
3816 lookup_count++;
3817 if (name->Equals(v8_str("A"))) {
3818 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3819 } else if (name->Equals(v8_str("B"))) {
3820 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3821 } else if (name->Equals(v8_str("C"))) {
3822 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3823 } else {
3824 return v8::Handle<v8::FunctionTemplate>();
3825 }
3826}
3827
3828
3829THREADED_TEST(FunctionLookup) {
3830 v8::RegisterExtension(new FunctionExtension());
3831 v8::HandleScope handle_scope;
3832 static const char* exts[1] = { "functiontest" };
3833 v8::ExtensionConfiguration config(1, exts);
3834 LocalContext context(&config);
3835 CHECK_EQ(3, lookup_count);
3836 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3837 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3838 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3839}
3840
3841
Leon Clarkee46be812010-01-19 14:06:41 +00003842THREADED_TEST(NativeFunctionConstructCall) {
3843 v8::RegisterExtension(new FunctionExtension());
3844 v8::HandleScope handle_scope;
3845 static const char* exts[1] = { "functiontest" };
3846 v8::ExtensionConfiguration config(1, exts);
3847 LocalContext context(&config);
Leon Clarked91b9f72010-01-27 17:25:45 +00003848 for (int i = 0; i < 10; i++) {
3849 // Run a few times to ensure that allocation of objects doesn't
3850 // change behavior of a constructor function.
3851 CHECK_EQ(v8::Integer::New(8),
3852 Script::Compile(v8_str("(new A()).data"))->Run());
3853 CHECK_EQ(v8::Integer::New(7),
3854 Script::Compile(v8_str("(new B()).data"))->Run());
3855 CHECK_EQ(v8::Integer::New(6),
3856 Script::Compile(v8_str("(new C()).data"))->Run());
3857 }
Leon Clarkee46be812010-01-19 14:06:41 +00003858}
3859
3860
Steve Blocka7e24c12009-10-30 11:49:00 +00003861static const char* last_location;
3862static const char* last_message;
3863void StoringErrorCallback(const char* location, const char* message) {
3864 if (last_location == NULL) {
3865 last_location = location;
3866 last_message = message;
3867 }
3868}
3869
3870
3871// ErrorReporting creates a circular extensions configuration and
3872// tests that the fatal error handler gets called. This renders V8
3873// unusable and therefore this test cannot be run in parallel.
3874TEST(ErrorReporting) {
3875 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3876 static const char* aDeps[] = { "B" };
3877 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3878 static const char* bDeps[] = { "A" };
3879 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3880 last_location = NULL;
3881 v8::ExtensionConfiguration config(1, bDeps);
3882 v8::Handle<Context> context = Context::New(&config);
3883 CHECK(context.IsEmpty());
3884 CHECK_NE(last_location, NULL);
3885}
3886
3887
3888static const char* js_code_causing_huge_string_flattening =
3889 "var str = 'X';"
3890 "for (var i = 0; i < 30; i++) {"
3891 " str = str + str;"
3892 "}"
3893 "str.match(/X/);";
3894
3895
3896void OOMCallback(const char* location, const char* message) {
3897 exit(0);
3898}
3899
3900
3901TEST(RegexpOutOfMemory) {
3902 // Execute a script that causes out of memory when flattening a string.
3903 v8::HandleScope scope;
3904 v8::V8::SetFatalErrorHandler(OOMCallback);
3905 LocalContext context;
3906 Local<Script> script =
3907 Script::Compile(String::New(js_code_causing_huge_string_flattening));
3908 last_location = NULL;
3909 Local<Value> result = script->Run();
3910
3911 CHECK(false); // Should not return.
3912}
3913
3914
3915static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3916 v8::Handle<Value> data) {
3917 CHECK_EQ(v8::Undefined(), data);
3918 CHECK(message->GetScriptResourceName()->IsUndefined());
3919 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3920 message->GetLineNumber();
3921 message->GetSourceLine();
3922}
3923
3924
3925THREADED_TEST(ErrorWithMissingScriptInfo) {
3926 v8::HandleScope scope;
3927 LocalContext context;
3928 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3929 Script::Compile(v8_str("throw Error()"))->Run();
3930 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3931}
3932
3933
3934int global_index = 0;
3935
3936class Snorkel {
3937 public:
3938 Snorkel() { index_ = global_index++; }
3939 int index_;
3940};
3941
3942class Whammy {
3943 public:
3944 Whammy() {
3945 cursor_ = 0;
3946 }
3947 ~Whammy() {
3948 script_.Dispose();
3949 }
3950 v8::Handle<Script> getScript() {
3951 if (script_.IsEmpty())
3952 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3953 return Local<Script>(*script_);
3954 }
3955
3956 public:
3957 static const int kObjectCount = 256;
3958 int cursor_;
3959 v8::Persistent<v8::Object> objects_[kObjectCount];
3960 v8::Persistent<Script> script_;
3961};
3962
3963static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3964 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3965 delete snorkel;
3966 obj.ClearWeak();
3967}
3968
3969v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3970 const AccessorInfo& info) {
3971 Whammy* whammy =
3972 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3973
3974 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3975
3976 v8::Handle<v8::Object> obj = v8::Object::New();
3977 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3978 if (!prev.IsEmpty()) {
3979 prev->Set(v8_str("next"), obj);
3980 prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3981 whammy->objects_[whammy->cursor_].Clear();
3982 }
3983 whammy->objects_[whammy->cursor_] = global;
3984 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3985 return whammy->getScript()->Run();
3986}
3987
3988THREADED_TEST(WeakReference) {
3989 v8::HandleScope handle_scope;
3990 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003991 Whammy* whammy = new Whammy();
Steve Blocka7e24c12009-10-30 11:49:00 +00003992 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3993 0, 0, 0, 0,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003994 v8::External::New(whammy));
Steve Blocka7e24c12009-10-30 11:49:00 +00003995 const char* extension_list[] = { "v8/gc" };
3996 v8::ExtensionConfiguration extensions(1, extension_list);
3997 v8::Persistent<Context> context = Context::New(&extensions);
3998 Context::Scope context_scope(context);
3999
4000 v8::Handle<v8::Object> interceptor = templ->NewInstance();
4001 context->Global()->Set(v8_str("whammy"), interceptor);
4002 const char* code =
4003 "var last;"
4004 "for (var i = 0; i < 10000; i++) {"
4005 " var obj = whammy.length;"
4006 " if (last) last.next = obj;"
4007 " last = obj;"
4008 "}"
4009 "gc();"
4010 "4";
4011 v8::Handle<Value> result = CompileRun(code);
4012 CHECK_EQ(4.0, result->NumberValue());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01004013 delete whammy;
Steve Blocka7e24c12009-10-30 11:49:00 +00004014 context.Dispose();
4015}
4016
4017
Steve Blockd0582a62009-12-15 09:54:21 +00004018static bool in_scavenge = false;
4019static int last = -1;
4020
4021static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
4022 CHECK_EQ(-1, last);
4023 last = 0;
4024 obj.Dispose();
4025 obj.Clear();
4026 in_scavenge = true;
4027 i::Heap::PerformScavenge();
4028 in_scavenge = false;
4029 *(reinterpret_cast<bool*>(data)) = true;
4030}
4031
4032static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
4033 void* data) {
4034 CHECK_EQ(0, last);
4035 last = 1;
4036 *(reinterpret_cast<bool*>(data)) = in_scavenge;
4037 obj.Dispose();
4038 obj.Clear();
4039}
4040
4041THREADED_TEST(NoWeakRefCallbacksInScavenge) {
4042 // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
4043 // Calling callbacks from scavenges is unsafe as objects held by those
4044 // handlers might have become strongly reachable, but scavenge doesn't
4045 // check that.
4046 v8::Persistent<Context> context = Context::New();
4047 Context::Scope context_scope(context);
4048
4049 v8::Persistent<v8::Object> object_a;
4050 v8::Persistent<v8::Object> object_b;
4051
4052 {
4053 v8::HandleScope handle_scope;
4054 object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
4055 object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
4056 }
4057
4058 bool object_a_disposed = false;
4059 object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
4060 bool released_in_scavenge = false;
4061 object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
4062
4063 while (!object_a_disposed) {
4064 i::Heap::CollectAllGarbage(false);
4065 }
4066 CHECK(!released_in_scavenge);
4067}
4068
4069
Steve Blocka7e24c12009-10-30 11:49:00 +00004070v8::Handle<Function> args_fun;
4071
4072
4073static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
4074 ApiTestFuzzer::Fuzz();
4075 CHECK_EQ(args_fun, args.Callee());
4076 CHECK_EQ(3, args.Length());
4077 CHECK_EQ(v8::Integer::New(1), args[0]);
4078 CHECK_EQ(v8::Integer::New(2), args[1]);
4079 CHECK_EQ(v8::Integer::New(3), args[2]);
4080 CHECK_EQ(v8::Undefined(), args[3]);
4081 v8::HandleScope scope;
4082 i::Heap::CollectAllGarbage(false);
4083 return v8::Undefined();
4084}
4085
4086
4087THREADED_TEST(Arguments) {
4088 v8::HandleScope scope;
4089 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
4090 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
4091 LocalContext context(NULL, global);
Steve Block6ded16b2010-05-10 14:33:55 +01004092 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
Steve Blocka7e24c12009-10-30 11:49:00 +00004093 v8_compile("f(1, 2, 3)")->Run();
4094}
4095
4096
Steve Blocka7e24c12009-10-30 11:49:00 +00004097static v8::Handle<Value> NoBlockGetterX(Local<String> name,
4098 const AccessorInfo&) {
4099 return v8::Handle<Value>();
4100}
4101
4102
4103static v8::Handle<Value> NoBlockGetterI(uint32_t index,
4104 const AccessorInfo&) {
4105 return v8::Handle<Value>();
4106}
4107
4108
4109static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
4110 const AccessorInfo&) {
4111 if (!name->Equals(v8_str("foo"))) {
4112 return v8::Handle<v8::Boolean>(); // not intercepted
4113 }
4114
4115 return v8::False(); // intercepted, and don't delete the property
4116}
4117
4118
4119static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
4120 if (index != 2) {
4121 return v8::Handle<v8::Boolean>(); // not intercepted
4122 }
4123
4124 return v8::False(); // intercepted, and don't delete the property
4125}
4126
4127
4128THREADED_TEST(Deleter) {
4129 v8::HandleScope scope;
4130 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4131 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
4132 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
4133 LocalContext context;
4134 context->Global()->Set(v8_str("k"), obj->NewInstance());
4135 CompileRun(
4136 "k.foo = 'foo';"
4137 "k.bar = 'bar';"
4138 "k[2] = 2;"
4139 "k[4] = 4;");
4140 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
4141 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
4142
4143 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
4144 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
4145
4146 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
4147 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
4148
4149 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
4150 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
4151}
4152
4153
4154static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
4155 ApiTestFuzzer::Fuzz();
4156 if (name->Equals(v8_str("foo")) ||
4157 name->Equals(v8_str("bar")) ||
4158 name->Equals(v8_str("baz"))) {
4159 return v8::Undefined();
4160 }
4161 return v8::Handle<Value>();
4162}
4163
4164
4165static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
4166 ApiTestFuzzer::Fuzz();
4167 if (index == 0 || index == 1) return v8::Undefined();
4168 return v8::Handle<Value>();
4169}
4170
4171
4172static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
4173 ApiTestFuzzer::Fuzz();
4174 v8::Handle<v8::Array> result = v8::Array::New(3);
4175 result->Set(v8::Integer::New(0), v8_str("foo"));
4176 result->Set(v8::Integer::New(1), v8_str("bar"));
4177 result->Set(v8::Integer::New(2), v8_str("baz"));
4178 return result;
4179}
4180
4181
4182static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
4183 ApiTestFuzzer::Fuzz();
4184 v8::Handle<v8::Array> result = v8::Array::New(2);
4185 result->Set(v8::Integer::New(0), v8_str("0"));
4186 result->Set(v8::Integer::New(1), v8_str("1"));
4187 return result;
4188}
4189
4190
4191THREADED_TEST(Enumerators) {
4192 v8::HandleScope scope;
4193 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4194 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
4195 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
4196 LocalContext context;
4197 context->Global()->Set(v8_str("k"), obj->NewInstance());
4198 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4199 "k[10] = 0;"
4200 "k.a = 0;"
4201 "k[5] = 0;"
4202 "k.b = 0;"
4203 "k[4294967295] = 0;"
4204 "k.c = 0;"
4205 "k[4294967296] = 0;"
4206 "k.d = 0;"
4207 "k[140000] = 0;"
4208 "k.e = 0;"
4209 "k[30000000000] = 0;"
4210 "k.f = 0;"
4211 "var result = [];"
4212 "for (var prop in k) {"
4213 " result.push(prop);"
4214 "}"
4215 "result"));
4216 // Check that we get all the property names returned including the
4217 // ones from the enumerators in the right order: indexed properties
4218 // in numerical order, indexed interceptor properties, named
4219 // properties in insertion order, named interceptor properties.
4220 // This order is not mandated by the spec, so this test is just
4221 // documenting our behavior.
4222 CHECK_EQ(17, result->Length());
4223 // Indexed properties in numerical order.
4224 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
4225 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
4226 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
4227 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
4228 // Indexed interceptor properties in the order they are returned
4229 // from the enumerator interceptor.
4230 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
4231 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
4232 // Named properties in insertion order.
4233 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
4234 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
4235 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
4236 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
4237 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
4238 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
4239 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
4240 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
4241 // Named interceptor properties.
4242 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
4243 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
4244 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
4245}
4246
4247
4248int p_getter_count;
4249int p_getter_count2;
4250
4251
4252static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
4253 ApiTestFuzzer::Fuzz();
4254 p_getter_count++;
4255 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4256 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4257 if (name->Equals(v8_str("p1"))) {
4258 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4259 } else if (name->Equals(v8_str("p2"))) {
4260 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4261 } else if (name->Equals(v8_str("p3"))) {
4262 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4263 } else if (name->Equals(v8_str("p4"))) {
4264 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4265 }
4266 return v8::Undefined();
4267}
4268
4269
4270static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
4271 ApiTestFuzzer::Fuzz();
4272 LocalContext context;
4273 context->Global()->Set(v8_str("o1"), obj->NewInstance());
4274 CompileRun(
4275 "o1.__proto__ = { };"
4276 "var o2 = { __proto__: o1 };"
4277 "var o3 = { __proto__: o2 };"
4278 "var o4 = { __proto__: o3 };"
4279 "for (var i = 0; i < 10; i++) o4.p4;"
4280 "for (var i = 0; i < 10; i++) o3.p3;"
4281 "for (var i = 0; i < 10; i++) o2.p2;"
4282 "for (var i = 0; i < 10; i++) o1.p1;");
4283}
4284
4285
4286static v8::Handle<Value> PGetter2(Local<String> name,
4287 const AccessorInfo& info) {
4288 ApiTestFuzzer::Fuzz();
4289 p_getter_count2++;
4290 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
4291 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
4292 if (name->Equals(v8_str("p1"))) {
4293 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
4294 } else if (name->Equals(v8_str("p2"))) {
4295 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
4296 } else if (name->Equals(v8_str("p3"))) {
4297 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
4298 } else if (name->Equals(v8_str("p4"))) {
4299 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
4300 }
4301 return v8::Undefined();
4302}
4303
4304
4305THREADED_TEST(GetterHolders) {
4306 v8::HandleScope scope;
4307 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4308 obj->SetAccessor(v8_str("p1"), PGetter);
4309 obj->SetAccessor(v8_str("p2"), PGetter);
4310 obj->SetAccessor(v8_str("p3"), PGetter);
4311 obj->SetAccessor(v8_str("p4"), PGetter);
4312 p_getter_count = 0;
4313 RunHolderTest(obj);
4314 CHECK_EQ(40, p_getter_count);
4315}
4316
4317
4318THREADED_TEST(PreInterceptorHolders) {
4319 v8::HandleScope scope;
4320 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4321 obj->SetNamedPropertyHandler(PGetter2);
4322 p_getter_count2 = 0;
4323 RunHolderTest(obj);
4324 CHECK_EQ(40, p_getter_count2);
4325}
4326
4327
4328THREADED_TEST(ObjectInstantiation) {
4329 v8::HandleScope scope;
4330 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
4331 templ->SetAccessor(v8_str("t"), PGetter2);
4332 LocalContext context;
4333 context->Global()->Set(v8_str("o"), templ->NewInstance());
4334 for (int i = 0; i < 100; i++) {
4335 v8::HandleScope inner_scope;
4336 v8::Handle<v8::Object> obj = templ->NewInstance();
4337 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
4338 context->Global()->Set(v8_str("o2"), obj);
4339 v8::Handle<Value> value =
4340 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
4341 CHECK_EQ(v8::True(), value);
4342 context->Global()->Set(v8_str("o"), obj);
4343 }
4344}
4345
4346
Ben Murdochb0fe1622011-05-05 13:52:32 +01004347static int StrCmp16(uint16_t* a, uint16_t* b) {
4348 while (true) {
4349 if (*a == 0 && *b == 0) return 0;
4350 if (*a != *b) return 0 + *a - *b;
4351 a++;
4352 b++;
4353 }
4354}
4355
4356
4357static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
4358 while (true) {
4359 if (n-- == 0) return 0;
4360 if (*a == 0 && *b == 0) return 0;
4361 if (*a != *b) return 0 + *a - *b;
4362 a++;
4363 b++;
4364 }
4365}
4366
4367
Steve Blocka7e24c12009-10-30 11:49:00 +00004368THREADED_TEST(StringWrite) {
4369 v8::HandleScope scope;
4370 v8::Handle<String> str = v8_str("abcde");
Ben Murdochb0fe1622011-05-05 13:52:32 +01004371 // abc<Icelandic eth><Unicode snowman>.
4372 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
4373
4374 CHECK_EQ(5, str2->Length());
Steve Blocka7e24c12009-10-30 11:49:00 +00004375
4376 char buf[100];
Ben Murdochb0fe1622011-05-05 13:52:32 +01004377 char utf8buf[100];
4378 uint16_t wbuf[100];
Steve Blocka7e24c12009-10-30 11:49:00 +00004379 int len;
Ben Murdochb0fe1622011-05-05 13:52:32 +01004380 int charlen;
4381
4382 memset(utf8buf, 0x1, sizeof(utf8buf));
4383 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
4384 CHECK_EQ(len, 9);
4385 CHECK_EQ(charlen, 5);
4386 CHECK_EQ(strcmp(utf8buf, "abc\303\260\342\230\203"), 0);
4387
4388 memset(utf8buf, 0x1, sizeof(utf8buf));
4389 len = str2->WriteUtf8(utf8buf, 8, &charlen);
4390 CHECK_EQ(len, 8);
4391 CHECK_EQ(charlen, 5);
4392 CHECK_EQ(strncmp(utf8buf, "abc\303\260\342\230\203\1", 9), 0);
4393
4394 memset(utf8buf, 0x1, sizeof(utf8buf));
4395 len = str2->WriteUtf8(utf8buf, 7, &charlen);
4396 CHECK_EQ(len, 5);
4397 CHECK_EQ(charlen, 4);
4398 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4399
4400 memset(utf8buf, 0x1, sizeof(utf8buf));
4401 len = str2->WriteUtf8(utf8buf, 6, &charlen);
4402 CHECK_EQ(len, 5);
4403 CHECK_EQ(charlen, 4);
4404 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4405
4406 memset(utf8buf, 0x1, sizeof(utf8buf));
4407 len = str2->WriteUtf8(utf8buf, 5, &charlen);
4408 CHECK_EQ(len, 5);
4409 CHECK_EQ(charlen, 4);
4410 CHECK_EQ(strncmp(utf8buf, "abc\303\260\1", 5), 0);
4411
4412 memset(utf8buf, 0x1, sizeof(utf8buf));
4413 len = str2->WriteUtf8(utf8buf, 4, &charlen);
4414 CHECK_EQ(len, 3);
4415 CHECK_EQ(charlen, 3);
4416 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4417
4418 memset(utf8buf, 0x1, sizeof(utf8buf));
4419 len = str2->WriteUtf8(utf8buf, 3, &charlen);
4420 CHECK_EQ(len, 3);
4421 CHECK_EQ(charlen, 3);
4422 CHECK_EQ(strncmp(utf8buf, "abc\1", 4), 0);
4423
4424 memset(utf8buf, 0x1, sizeof(utf8buf));
4425 len = str2->WriteUtf8(utf8buf, 2, &charlen);
4426 CHECK_EQ(len, 2);
4427 CHECK_EQ(charlen, 2);
4428 CHECK_EQ(strncmp(utf8buf, "ab\1", 3), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004429
4430 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004431 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004432 len = str->WriteAscii(buf);
4433 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004434 len = str->Write(wbuf);
4435 CHECK_EQ(len, 5);
4436 CHECK_EQ(strcmp("abcde", buf), 0);
4437 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4438 CHECK_EQ(StrCmp16(answer1, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004439
4440 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004441 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004442 len = str->WriteAscii(buf, 0, 4);
4443 CHECK_EQ(len, 4);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004444 len = str->Write(wbuf, 0, 4);
4445 CHECK_EQ(len, 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00004446 CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004447 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
4448 CHECK_EQ(StrNCmp16(answer2, wbuf, 5), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004449
4450 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004451 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004452 len = str->WriteAscii(buf, 0, 5);
4453 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004454 len = str->Write(wbuf, 0, 5);
4455 CHECK_EQ(len, 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00004456 CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004457 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
4458 CHECK_EQ(StrNCmp16(answer3, wbuf, 6), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004459
4460 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004461 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004462 len = str->WriteAscii(buf, 0, 6);
4463 CHECK_EQ(len, 5);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004464 len = str->Write(wbuf, 0, 6);
4465 CHECK_EQ(len, 5);
4466 CHECK_EQ(strcmp("abcde", buf), 0);
4467 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
4468 CHECK_EQ(StrCmp16(answer4, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004469
4470 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004471 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004472 len = str->WriteAscii(buf, 4, -1);
4473 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004474 len = str->Write(wbuf, 4, -1);
4475 CHECK_EQ(len, 1);
4476 CHECK_EQ(strcmp("e", buf), 0);
4477 uint16_t answer5[] = {'e', '\0'};
4478 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004479
4480 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004481 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004482 len = str->WriteAscii(buf, 4, 6);
4483 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004484 len = str->Write(wbuf, 4, 6);
4485 CHECK_EQ(len, 1);
4486 CHECK_EQ(strcmp("e", buf), 0);
4487 CHECK_EQ(StrCmp16(answer5, wbuf), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004488
4489 memset(buf, 0x1, sizeof(buf));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004490 memset(wbuf, 0x1, sizeof(wbuf));
Steve Blocka7e24c12009-10-30 11:49:00 +00004491 len = str->WriteAscii(buf, 4, 1);
4492 CHECK_EQ(len, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004493 len = str->Write(wbuf, 4, 1);
4494 CHECK_EQ(len, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004495 CHECK_EQ(strncmp("e\1", buf, 2), 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004496 uint16_t answer6[] = {'e', 0x101};
4497 CHECK_EQ(StrNCmp16(answer6, wbuf, 2), 0);
4498
4499 memset(buf, 0x1, sizeof(buf));
4500 memset(wbuf, 0x1, sizeof(wbuf));
4501 len = str->WriteAscii(buf, 3, 1);
4502 CHECK_EQ(len, 1);
4503 len = str->Write(wbuf, 3, 1);
4504 CHECK_EQ(len, 1);
4505 CHECK_EQ(strncmp("d\1", buf, 2), 0);
4506 uint16_t answer7[] = {'d', 0x101};
4507 CHECK_EQ(StrNCmp16(answer7, wbuf, 2), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004508}
4509
4510
4511THREADED_TEST(ToArrayIndex) {
4512 v8::HandleScope scope;
4513 LocalContext context;
4514
4515 v8::Handle<String> str = v8_str("42");
4516 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
4517 CHECK(!index.IsEmpty());
4518 CHECK_EQ(42.0, index->Uint32Value());
4519 str = v8_str("42asdf");
4520 index = str->ToArrayIndex();
4521 CHECK(index.IsEmpty());
4522 str = v8_str("-42");
4523 index = str->ToArrayIndex();
4524 CHECK(index.IsEmpty());
4525 str = v8_str("4294967295");
4526 index = str->ToArrayIndex();
4527 CHECK(!index.IsEmpty());
4528 CHECK_EQ(4294967295.0, index->Uint32Value());
4529 v8::Handle<v8::Number> num = v8::Number::New(1);
4530 index = num->ToArrayIndex();
4531 CHECK(!index.IsEmpty());
4532 CHECK_EQ(1.0, index->Uint32Value());
4533 num = v8::Number::New(-1);
4534 index = num->ToArrayIndex();
4535 CHECK(index.IsEmpty());
4536 v8::Handle<v8::Object> obj = v8::Object::New();
4537 index = obj->ToArrayIndex();
4538 CHECK(index.IsEmpty());
4539}
4540
4541
4542THREADED_TEST(ErrorConstruction) {
4543 v8::HandleScope scope;
4544 LocalContext context;
4545
4546 v8::Handle<String> foo = v8_str("foo");
4547 v8::Handle<String> message = v8_str("message");
4548 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
4549 CHECK(range_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004550 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>();
4551 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004552 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
4553 CHECK(reference_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004554 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004555 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
4556 CHECK(syntax_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004557 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004558 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
4559 CHECK(type_error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004560 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004561 v8::Handle<Value> error = v8::Exception::Error(foo);
4562 CHECK(error->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01004563 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
Steve Blocka7e24c12009-10-30 11:49:00 +00004564}
4565
4566
4567static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
4568 ApiTestFuzzer::Fuzz();
4569 return v8_num(10);
4570}
4571
4572
4573static void YSetter(Local<String> name,
4574 Local<Value> value,
4575 const AccessorInfo& info) {
4576 if (info.This()->Has(name)) {
4577 info.This()->Delete(name);
4578 }
4579 info.This()->Set(name, value);
4580}
4581
4582
4583THREADED_TEST(DeleteAccessor) {
4584 v8::HandleScope scope;
4585 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
4586 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
4587 LocalContext context;
4588 v8::Handle<v8::Object> holder = obj->NewInstance();
4589 context->Global()->Set(v8_str("holder"), holder);
4590 v8::Handle<Value> result = CompileRun(
4591 "holder.y = 11; holder.y = 12; holder.y");
4592 CHECK_EQ(12, result->Uint32Value());
4593}
4594
4595
4596THREADED_TEST(TypeSwitch) {
4597 v8::HandleScope scope;
4598 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
4599 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
4600 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
4601 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
4602 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
4603 LocalContext context;
4604 v8::Handle<v8::Object> obj0 = v8::Object::New();
4605 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
4606 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
4607 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
4608 for (int i = 0; i < 10; i++) {
4609 CHECK_EQ(0, type_switch->match(obj0));
4610 CHECK_EQ(1, type_switch->match(obj1));
4611 CHECK_EQ(2, type_switch->match(obj2));
4612 CHECK_EQ(3, type_switch->match(obj3));
4613 CHECK_EQ(3, type_switch->match(obj3));
4614 CHECK_EQ(2, type_switch->match(obj2));
4615 CHECK_EQ(1, type_switch->match(obj1));
4616 CHECK_EQ(0, type_switch->match(obj0));
4617 }
4618}
4619
4620
4621// For use within the TestSecurityHandler() test.
4622static bool g_security_callback_result = false;
4623static bool NamedSecurityTestCallback(Local<v8::Object> global,
4624 Local<Value> name,
4625 v8::AccessType type,
4626 Local<Value> data) {
4627 // Always allow read access.
4628 if (type == v8::ACCESS_GET)
4629 return true;
4630
4631 // Sometimes allow other access.
4632 return g_security_callback_result;
4633}
4634
4635
4636static bool IndexedSecurityTestCallback(Local<v8::Object> global,
4637 uint32_t key,
4638 v8::AccessType type,
4639 Local<Value> data) {
4640 // Always allow read access.
4641 if (type == v8::ACCESS_GET)
4642 return true;
4643
4644 // Sometimes allow other access.
4645 return g_security_callback_result;
4646}
4647
4648
4649static int trouble_nesting = 0;
4650static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
4651 ApiTestFuzzer::Fuzz();
4652 trouble_nesting++;
4653
4654 // Call a JS function that throws an uncaught exception.
4655 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
4656 Local<Value> trouble_callee = (trouble_nesting == 3) ?
4657 arg_this->Get(v8_str("trouble_callee")) :
4658 arg_this->Get(v8_str("trouble_caller"));
4659 CHECK(trouble_callee->IsFunction());
4660 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
4661}
4662
4663
4664static int report_count = 0;
4665static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
4666 v8::Handle<Value>) {
4667 report_count++;
4668}
4669
4670
4671// Counts uncaught exceptions, but other tests running in parallel
4672// also have uncaught exceptions.
4673TEST(ApiUncaughtException) {
4674 report_count = 0;
4675 v8::HandleScope scope;
4676 LocalContext env;
4677 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
4678
4679 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4680 v8::Local<v8::Object> global = env->Global();
4681 global->Set(v8_str("trouble"), fun->GetFunction());
4682
4683 Script::Compile(v8_str("function trouble_callee() {"
4684 " var x = null;"
4685 " return x.foo;"
4686 "};"
4687 "function trouble_caller() {"
4688 " trouble();"
4689 "};"))->Run();
4690 Local<Value> trouble = global->Get(v8_str("trouble"));
4691 CHECK(trouble->IsFunction());
4692 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
4693 CHECK(trouble_callee->IsFunction());
4694 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
4695 CHECK(trouble_caller->IsFunction());
4696 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
4697 CHECK_EQ(1, report_count);
4698 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
4699}
4700
Leon Clarke4515c472010-02-03 11:58:03 +00004701static const char* script_resource_name = "ExceptionInNativeScript.js";
4702static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4703 v8::Handle<Value>) {
4704 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4705 CHECK(!name_val.IsEmpty() && name_val->IsString());
4706 v8::String::AsciiValue name(message->GetScriptResourceName());
4707 CHECK_EQ(script_resource_name, *name);
4708 CHECK_EQ(3, message->GetLineNumber());
4709 v8::String::AsciiValue source_line(message->GetSourceLine());
4710 CHECK_EQ(" new o.foo();", *source_line);
4711}
4712
4713TEST(ExceptionInNativeScript) {
4714 v8::HandleScope scope;
4715 LocalContext env;
4716 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4717
4718 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4719 v8::Local<v8::Object> global = env->Global();
4720 global->Set(v8_str("trouble"), fun->GetFunction());
4721
4722 Script::Compile(v8_str("function trouble() {\n"
4723 " var o = {};\n"
4724 " new o.foo();\n"
4725 "};"), v8::String::New(script_resource_name))->Run();
4726 Local<Value> trouble = global->Get(v8_str("trouble"));
4727 CHECK(trouble->IsFunction());
4728 Function::Cast(*trouble)->Call(global, 0, NULL);
4729 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4730}
4731
Steve Blocka7e24c12009-10-30 11:49:00 +00004732
4733TEST(CompilationErrorUsingTryCatchHandler) {
4734 v8::HandleScope scope;
4735 LocalContext env;
4736 v8::TryCatch try_catch;
4737 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4738 CHECK_NE(NULL, *try_catch.Exception());
4739 CHECK(try_catch.HasCaught());
4740}
4741
4742
4743TEST(TryCatchFinallyUsingTryCatchHandler) {
4744 v8::HandleScope scope;
4745 LocalContext env;
4746 v8::TryCatch try_catch;
4747 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4748 CHECK(!try_catch.HasCaught());
4749 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4750 CHECK(try_catch.HasCaught());
4751 try_catch.Reset();
4752 Script::Compile(v8_str("(function() {"
4753 "try { throw ''; } finally { return; }"
4754 "})()"))->Run();
4755 CHECK(!try_catch.HasCaught());
4756 Script::Compile(v8_str("(function()"
4757 " { try { throw ''; } finally { throw 0; }"
4758 "})()"))->Run();
4759 CHECK(try_catch.HasCaught());
4760}
4761
4762
4763// SecurityHandler can't be run twice
4764TEST(SecurityHandler) {
4765 v8::HandleScope scope0;
4766 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4767 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4768 IndexedSecurityTestCallback);
4769 // Create an environment
4770 v8::Persistent<Context> context0 =
4771 Context::New(NULL, global_template);
4772 context0->Enter();
4773
4774 v8::Handle<v8::Object> global0 = context0->Global();
4775 v8::Handle<Script> script0 = v8_compile("foo = 111");
4776 script0->Run();
4777 global0->Set(v8_str("0"), v8_num(999));
4778 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4779 CHECK_EQ(111, foo0->Int32Value());
4780 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4781 CHECK_EQ(999, z0->Int32Value());
4782
4783 // Create another environment, should fail security checks.
4784 v8::HandleScope scope1;
4785
4786 v8::Persistent<Context> context1 =
4787 Context::New(NULL, global_template);
4788 context1->Enter();
4789
4790 v8::Handle<v8::Object> global1 = context1->Global();
4791 global1->Set(v8_str("othercontext"), global0);
4792 // This set will fail the security check.
4793 v8::Handle<Script> script1 =
4794 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4795 script1->Run();
4796 // This read will pass the security check.
4797 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4798 CHECK_EQ(111, foo1->Int32Value());
4799 // This read will pass the security check.
4800 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4801 CHECK_EQ(999, z1->Int32Value());
4802
4803 // Create another environment, should pass security checks.
4804 { g_security_callback_result = true; // allow security handler to pass.
4805 v8::HandleScope scope2;
4806 LocalContext context2;
4807 v8::Handle<v8::Object> global2 = context2->Global();
4808 global2->Set(v8_str("othercontext"), global0);
4809 v8::Handle<Script> script2 =
4810 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4811 script2->Run();
4812 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4813 CHECK_EQ(333, foo2->Int32Value());
4814 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4815 CHECK_EQ(888, z2->Int32Value());
4816 }
4817
4818 context1->Exit();
4819 context1.Dispose();
4820
4821 context0->Exit();
4822 context0.Dispose();
4823}
4824
4825
4826THREADED_TEST(SecurityChecks) {
4827 v8::HandleScope handle_scope;
4828 LocalContext env1;
4829 v8::Persistent<Context> env2 = Context::New();
4830
4831 Local<Value> foo = v8_str("foo");
4832 Local<Value> bar = v8_str("bar");
4833
4834 // Set to the same domain.
4835 env1->SetSecurityToken(foo);
4836
4837 // Create a function in env1.
4838 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4839 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4840 CHECK(spy->IsFunction());
4841
4842 // Create another function accessing global objects.
4843 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4844 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4845 CHECK(spy2->IsFunction());
4846
4847 // Switch to env2 in the same domain and invoke spy on env2.
4848 {
4849 env2->SetSecurityToken(foo);
4850 // Enter env2
4851 Context::Scope scope_env2(env2);
4852 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4853 CHECK(result->IsFunction());
4854 }
4855
4856 {
4857 env2->SetSecurityToken(bar);
4858 Context::Scope scope_env2(env2);
4859
4860 // Call cross_domain_call, it should throw an exception
4861 v8::TryCatch try_catch;
4862 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4863 CHECK(try_catch.HasCaught());
4864 }
4865
4866 env2.Dispose();
4867}
4868
4869
4870// Regression test case for issue 1183439.
4871THREADED_TEST(SecurityChecksForPrototypeChain) {
4872 v8::HandleScope scope;
4873 LocalContext current;
4874 v8::Persistent<Context> other = Context::New();
4875
4876 // Change context to be able to get to the Object function in the
4877 // other context without hitting the security checks.
4878 v8::Local<Value> other_object;
4879 { Context::Scope scope(other);
4880 other_object = other->Global()->Get(v8_str("Object"));
4881 other->Global()->Set(v8_num(42), v8_num(87));
4882 }
4883
4884 current->Global()->Set(v8_str("other"), other->Global());
4885 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4886
4887 // Make sure the security check fails here and we get an undefined
4888 // result instead of getting the Object function. Repeat in a loop
4889 // to make sure to exercise the IC code.
4890 v8::Local<Script> access_other0 = v8_compile("other.Object");
4891 v8::Local<Script> access_other1 = v8_compile("other[42]");
4892 for (int i = 0; i < 5; i++) {
4893 CHECK(!access_other0->Run()->Equals(other_object));
4894 CHECK(access_other0->Run()->IsUndefined());
4895 CHECK(!access_other1->Run()->Equals(v8_num(87)));
4896 CHECK(access_other1->Run()->IsUndefined());
4897 }
4898
4899 // Create an object that has 'other' in its prototype chain and make
4900 // sure we cannot access the Object function indirectly through
4901 // that. Repeat in a loop to make sure to exercise the IC code.
4902 v8_compile("function F() { };"
4903 "F.prototype = other;"
4904 "var f = new F();")->Run();
4905 v8::Local<Script> access_f0 = v8_compile("f.Object");
4906 v8::Local<Script> access_f1 = v8_compile("f[42]");
4907 for (int j = 0; j < 5; j++) {
4908 CHECK(!access_f0->Run()->Equals(other_object));
4909 CHECK(access_f0->Run()->IsUndefined());
4910 CHECK(!access_f1->Run()->Equals(v8_num(87)));
4911 CHECK(access_f1->Run()->IsUndefined());
4912 }
4913
4914 // Now it gets hairy: Set the prototype for the other global object
4915 // to be the current global object. The prototype chain for 'f' now
4916 // goes through 'other' but ends up in the current global object.
4917 { Context::Scope scope(other);
4918 other->Global()->Set(v8_str("__proto__"), current->Global());
4919 }
4920 // Set a named and an index property on the current global
4921 // object. To force the lookup to go through the other global object,
4922 // the properties must not exist in the other global object.
4923 current->Global()->Set(v8_str("foo"), v8_num(100));
4924 current->Global()->Set(v8_num(99), v8_num(101));
4925 // Try to read the properties from f and make sure that the access
4926 // gets stopped by the security checks on the other global object.
4927 Local<Script> access_f2 = v8_compile("f.foo");
4928 Local<Script> access_f3 = v8_compile("f[99]");
4929 for (int k = 0; k < 5; k++) {
4930 CHECK(!access_f2->Run()->Equals(v8_num(100)));
4931 CHECK(access_f2->Run()->IsUndefined());
4932 CHECK(!access_f3->Run()->Equals(v8_num(101)));
4933 CHECK(access_f3->Run()->IsUndefined());
4934 }
4935 other.Dispose();
4936}
4937
4938
4939THREADED_TEST(CrossDomainDelete) {
4940 v8::HandleScope handle_scope;
4941 LocalContext env1;
4942 v8::Persistent<Context> env2 = Context::New();
4943
4944 Local<Value> foo = v8_str("foo");
4945 Local<Value> bar = v8_str("bar");
4946
4947 // Set to the same domain.
4948 env1->SetSecurityToken(foo);
4949 env2->SetSecurityToken(foo);
4950
4951 env1->Global()->Set(v8_str("prop"), v8_num(3));
4952 env2->Global()->Set(v8_str("env1"), env1->Global());
4953
4954 // Change env2 to a different domain and delete env1.prop.
4955 env2->SetSecurityToken(bar);
4956 {
4957 Context::Scope scope_env2(env2);
4958 Local<Value> result =
4959 Script::Compile(v8_str("delete env1.prop"))->Run();
4960 CHECK(result->IsFalse());
4961 }
4962
4963 // Check that env1.prop still exists.
4964 Local<Value> v = env1->Global()->Get(v8_str("prop"));
4965 CHECK(v->IsNumber());
4966 CHECK_EQ(3, v->Int32Value());
4967
4968 env2.Dispose();
4969}
4970
4971
4972THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4973 v8::HandleScope handle_scope;
4974 LocalContext env1;
4975 v8::Persistent<Context> env2 = Context::New();
4976
4977 Local<Value> foo = v8_str("foo");
4978 Local<Value> bar = v8_str("bar");
4979
4980 // Set to the same domain.
4981 env1->SetSecurityToken(foo);
4982 env2->SetSecurityToken(foo);
4983
4984 env1->Global()->Set(v8_str("prop"), v8_num(3));
4985 env2->Global()->Set(v8_str("env1"), env1->Global());
4986
4987 // env1.prop is enumerable in env2.
4988 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4989 {
4990 Context::Scope scope_env2(env2);
4991 Local<Value> result = Script::Compile(test)->Run();
4992 CHECK(result->IsTrue());
4993 }
4994
4995 // Change env2 to a different domain and test again.
4996 env2->SetSecurityToken(bar);
4997 {
4998 Context::Scope scope_env2(env2);
4999 Local<Value> result = Script::Compile(test)->Run();
5000 CHECK(result->IsFalse());
5001 }
5002
5003 env2.Dispose();
5004}
5005
5006
5007THREADED_TEST(CrossDomainForIn) {
5008 v8::HandleScope handle_scope;
5009 LocalContext env1;
5010 v8::Persistent<Context> env2 = Context::New();
5011
5012 Local<Value> foo = v8_str("foo");
5013 Local<Value> bar = v8_str("bar");
5014
5015 // Set to the same domain.
5016 env1->SetSecurityToken(foo);
5017 env2->SetSecurityToken(foo);
5018
5019 env1->Global()->Set(v8_str("prop"), v8_num(3));
5020 env2->Global()->Set(v8_str("env1"), env1->Global());
5021
5022 // Change env2 to a different domain and set env1's global object
5023 // as the __proto__ of an object in env2 and enumerate properties
5024 // in for-in. It shouldn't enumerate properties on env1's global
5025 // object.
5026 env2->SetSecurityToken(bar);
5027 {
5028 Context::Scope scope_env2(env2);
5029 Local<Value> result =
5030 CompileRun("(function(){var obj = {'__proto__':env1};"
5031 "for (var p in obj)"
5032 " if (p == 'prop') return false;"
5033 "return true;})()");
5034 CHECK(result->IsTrue());
5035 }
5036 env2.Dispose();
5037}
5038
5039
5040TEST(ContextDetachGlobal) {
5041 v8::HandleScope handle_scope;
5042 LocalContext env1;
5043 v8::Persistent<Context> env2 = Context::New();
5044
5045 Local<v8::Object> global1 = env1->Global();
5046
5047 Local<Value> foo = v8_str("foo");
5048
5049 // Set to the same domain.
5050 env1->SetSecurityToken(foo);
5051 env2->SetSecurityToken(foo);
5052
5053 // Enter env2
5054 env2->Enter();
5055
Andrei Popescu74b3c142010-03-29 12:03:09 +01005056 // Create a function in env2 and add a reference to it in env1.
Steve Blocka7e24c12009-10-30 11:49:00 +00005057 Local<v8::Object> global2 = env2->Global();
5058 global2->Set(v8_str("prop"), v8::Integer::New(1));
5059 CompileRun("function getProp() {return prop;}");
5060
5061 env1->Global()->Set(v8_str("getProp"),
5062 global2->Get(v8_str("getProp")));
5063
Andrei Popescu74b3c142010-03-29 12:03:09 +01005064 // Detach env2's global, and reuse the global object of env2
Steve Blocka7e24c12009-10-30 11:49:00 +00005065 env2->Exit();
5066 env2->DetachGlobal();
5067 // env2 has a new global object.
5068 CHECK(!env2->Global()->Equals(global2));
5069
5070 v8::Persistent<Context> env3 =
5071 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5072 env3->SetSecurityToken(v8_str("bar"));
5073 env3->Enter();
5074
5075 Local<v8::Object> global3 = env3->Global();
5076 CHECK_EQ(global2, global3);
5077 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
5078 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
5079 global3->Set(v8_str("prop"), v8::Integer::New(-1));
5080 global3->Set(v8_str("prop2"), v8::Integer::New(2));
5081 env3->Exit();
5082
5083 // Call getProp in env1, and it should return the value 1
5084 {
5085 Local<Value> get_prop = global1->Get(v8_str("getProp"));
5086 CHECK(get_prop->IsFunction());
5087 v8::TryCatch try_catch;
5088 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
5089 CHECK(!try_catch.HasCaught());
5090 CHECK_EQ(1, r->Int32Value());
5091 }
5092
5093 // Check that env3 is not accessible from env1
5094 {
5095 Local<Value> r = global3->Get(v8_str("prop2"));
5096 CHECK(r->IsUndefined());
5097 }
5098
5099 env2.Dispose();
5100 env3.Dispose();
5101}
5102
5103
Andrei Popescu74b3c142010-03-29 12:03:09 +01005104TEST(DetachAndReattachGlobal) {
5105 v8::HandleScope scope;
5106 LocalContext env1;
5107
5108 // Create second environment.
5109 v8::Persistent<Context> env2 = Context::New();
5110
5111 Local<Value> foo = v8_str("foo");
5112
5113 // Set same security token for env1 and env2.
5114 env1->SetSecurityToken(foo);
5115 env2->SetSecurityToken(foo);
5116
5117 // Create a property on the global object in env2.
5118 {
5119 v8::Context::Scope scope(env2);
5120 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
5121 }
5122
5123 // Create a reference to env2 global from env1 global.
5124 env1->Global()->Set(v8_str("other"), env2->Global());
5125
5126 // Check that we have access to other.p in env2 from env1.
5127 Local<Value> result = CompileRun("other.p");
5128 CHECK(result->IsInt32());
5129 CHECK_EQ(42, result->Int32Value());
5130
5131 // Hold on to global from env2 and detach global from env2.
5132 Local<v8::Object> global2 = env2->Global();
5133 env2->DetachGlobal();
5134
5135 // Check that the global has been detached. No other.p property can
5136 // be found.
5137 result = CompileRun("other.p");
5138 CHECK(result->IsUndefined());
5139
5140 // Reuse global2 for env3.
5141 v8::Persistent<Context> env3 =
5142 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
5143 CHECK_EQ(global2, env3->Global());
5144
5145 // Start by using the same security token for env3 as for env1 and env2.
5146 env3->SetSecurityToken(foo);
5147
5148 // Create a property on the global object in env3.
5149 {
5150 v8::Context::Scope scope(env3);
5151 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
5152 }
5153
5154 // Check that other.p is now the property in env3 and that we have access.
5155 result = CompileRun("other.p");
5156 CHECK(result->IsInt32());
5157 CHECK_EQ(24, result->Int32Value());
5158
5159 // Change security token for env3 to something different from env1 and env2.
5160 env3->SetSecurityToken(v8_str("bar"));
5161
5162 // Check that we do not have access to other.p in env1. |other| is now
5163 // the global object for env3 which has a different security token,
5164 // so access should be blocked.
5165 result = CompileRun("other.p");
5166 CHECK(result->IsUndefined());
5167
5168 // Detach the global for env3 and reattach it to env2.
5169 env3->DetachGlobal();
5170 env2->ReattachGlobal(global2);
5171
5172 // Check that we have access to other.p again in env1. |other| is now
5173 // the global object for env2 which has the same security token as env1.
5174 result = CompileRun("other.p");
5175 CHECK(result->IsInt32());
5176 CHECK_EQ(42, result->Int32Value());
5177
5178 env2.Dispose();
5179 env3.Dispose();
5180}
5181
5182
Steve Blocka7e24c12009-10-30 11:49:00 +00005183static bool NamedAccessBlocker(Local<v8::Object> global,
5184 Local<Value> name,
5185 v8::AccessType type,
5186 Local<Value> data) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005187 return Context::GetCurrent()->Global()->Equals(global);
Steve Blocka7e24c12009-10-30 11:49:00 +00005188}
5189
5190
5191static bool IndexedAccessBlocker(Local<v8::Object> global,
5192 uint32_t key,
5193 v8::AccessType type,
5194 Local<Value> data) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005195 return Context::GetCurrent()->Global()->Equals(global);
Steve Blocka7e24c12009-10-30 11:49:00 +00005196}
5197
5198
5199static int g_echo_value = -1;
5200static v8::Handle<Value> EchoGetter(Local<String> name,
5201 const AccessorInfo& info) {
5202 return v8_num(g_echo_value);
5203}
5204
5205
5206static void EchoSetter(Local<String> name,
5207 Local<Value> value,
5208 const AccessorInfo&) {
5209 if (value->IsNumber())
5210 g_echo_value = value->Int32Value();
5211}
5212
5213
5214static v8::Handle<Value> UnreachableGetter(Local<String> name,
5215 const AccessorInfo& info) {
5216 CHECK(false); // This function should not be called..
5217 return v8::Undefined();
5218}
5219
5220
5221static void UnreachableSetter(Local<String>, Local<Value>,
5222 const AccessorInfo&) {
5223 CHECK(false); // This function should nto be called.
5224}
5225
5226
Ben Murdochb0fe1622011-05-05 13:52:32 +01005227THREADED_TEST(AccessControl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005228 v8::HandleScope handle_scope;
5229 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5230
5231 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
5232 IndexedAccessBlocker);
5233
5234 // Add an accessor accessible by cross-domain JS code.
5235 global_template->SetAccessor(
5236 v8_str("accessible_prop"),
5237 EchoGetter, EchoSetter,
5238 v8::Handle<Value>(),
5239 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
5240
5241 // Add an accessor that is not accessible by cross-domain JS code.
5242 global_template->SetAccessor(v8_str("blocked_prop"),
5243 UnreachableGetter, UnreachableSetter,
5244 v8::Handle<Value>(),
5245 v8::DEFAULT);
5246
5247 // Create an environment
5248 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5249 context0->Enter();
5250
5251 v8::Handle<v8::Object> global0 = context0->Global();
5252
5253 v8::HandleScope scope1;
5254
5255 v8::Persistent<Context> context1 = Context::New();
5256 context1->Enter();
5257
5258 v8::Handle<v8::Object> global1 = context1->Global();
5259 global1->Set(v8_str("other"), global0);
5260
5261 v8::Handle<Value> value;
5262
Ben Murdochb0fe1622011-05-05 13:52:32 +01005263 // Access blocked property
5264 value = v8_compile("other.blocked_prop = 1")->Run();
5265 value = v8_compile("other.blocked_prop")->Run();
5266 CHECK(value->IsUndefined());
5267
5268 value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
5269 CHECK(value->IsFalse());
5270
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 // Access accessible property
Ben Murdochb0fe1622011-05-05 13:52:32 +01005272 value = v8_compile("other.accessible_prop = 3")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005273 CHECK(value->IsNumber());
5274 CHECK_EQ(3, value->Int32Value());
Andrei Popescu31002712010-02-23 13:46:05 +00005275 CHECK_EQ(3, g_echo_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005276
Ben Murdochb0fe1622011-05-05 13:52:32 +01005277 value = v8_compile("other.accessible_prop")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005278 CHECK(value->IsNumber());
5279 CHECK_EQ(3, value->Int32Value());
5280
Ben Murdochb0fe1622011-05-05 13:52:32 +01005281 value =
5282 v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005283 CHECK(value->IsTrue());
5284
5285 // Enumeration doesn't enumerate accessors from inaccessible objects in
5286 // the prototype chain even if the accessors are in themselves accessible.
Ben Murdochb0fe1622011-05-05 13:52:32 +01005287 Local<Value> result =
Steve Blocka7e24c12009-10-30 11:49:00 +00005288 CompileRun("(function(){var obj = {'__proto__':other};"
5289 "for (var p in obj)"
5290 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
5291 " return false;"
5292 " }"
5293 "return true;})()");
Ben Murdochb0fe1622011-05-05 13:52:32 +01005294 CHECK(result->IsTrue());
Steve Blocka7e24c12009-10-30 11:49:00 +00005295
5296 context1->Exit();
5297 context0->Exit();
5298 context1.Dispose();
5299 context0.Dispose();
5300}
5301
5302
Leon Clarke4515c472010-02-03 11:58:03 +00005303static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
5304 Local<Value> name,
5305 v8::AccessType type,
5306 Local<Value> data) {
5307 return false;
5308}
5309
5310
5311static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
5312 uint32_t key,
5313 v8::AccessType type,
5314 Local<Value> data) {
5315 return false;
5316}
5317
5318
5319THREADED_TEST(AccessControlGetOwnPropertyNames) {
5320 v8::HandleScope handle_scope;
5321 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5322
5323 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5324 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
5325 GetOwnPropertyNamesIndexedBlocker);
5326
5327 // Create an environment
5328 v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
5329 context0->Enter();
5330
5331 v8::Handle<v8::Object> global0 = context0->Global();
5332
5333 v8::HandleScope scope1;
5334
5335 v8::Persistent<Context> context1 = Context::New();
5336 context1->Enter();
5337
5338 v8::Handle<v8::Object> global1 = context1->Global();
5339 global1->Set(v8_str("other"), global0);
5340 global1->Set(v8_str("object"), obj_template->NewInstance());
5341
5342 v8::Handle<Value> value;
5343
5344 // Attempt to get the property names of the other global object and
5345 // of an object that requires access checks. Accessing the other
5346 // global object should be blocked by access checks on the global
5347 // proxy object. Accessing the object that requires access checks
5348 // is blocked by the access checks on the object itself.
5349 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
5350 CHECK(value->IsTrue());
5351
5352 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
5353 CHECK(value->IsTrue());
5354
5355 context1->Exit();
5356 context0->Exit();
5357 context1.Dispose();
5358 context0.Dispose();
5359}
5360
5361
Steve Block8defd9f2010-07-08 12:39:36 +01005362static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
5363 v8::Handle<v8::Array> result = v8::Array::New(1);
5364 result->Set(0, v8_str("x"));
5365 return result;
5366}
5367
5368
5369THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
5370 v8::HandleScope handle_scope;
5371 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
5372
5373 obj_template->Set(v8_str("x"), v8::Integer::New(42));
5374 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
5375 NamedPropertyEnumerator);
5376
5377 LocalContext context;
5378 v8::Handle<v8::Object> global = context->Global();
5379 global->Set(v8_str("object"), obj_template->NewInstance());
5380
5381 v8::Handle<Value> value =
5382 CompileRun("Object.getOwnPropertyNames(object).join(',')");
5383 CHECK_EQ(v8_str("x"), value);
5384}
5385
5386
Steve Blocka7e24c12009-10-30 11:49:00 +00005387static v8::Handle<Value> ConstTenGetter(Local<String> name,
5388 const AccessorInfo& info) {
5389 return v8_num(10);
5390}
5391
5392
5393THREADED_TEST(CrossDomainAccessors) {
5394 v8::HandleScope handle_scope;
5395
5396 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
5397
5398 v8::Handle<v8::ObjectTemplate> global_template =
5399 func_template->InstanceTemplate();
5400
5401 v8::Handle<v8::ObjectTemplate> proto_template =
5402 func_template->PrototypeTemplate();
5403
5404 // Add an accessor to proto that's accessible by cross-domain JS code.
5405 proto_template->SetAccessor(v8_str("accessible"),
5406 ConstTenGetter, 0,
5407 v8::Handle<Value>(),
5408 v8::ALL_CAN_READ);
5409
5410 // Add an accessor that is not accessible by cross-domain JS code.
5411 global_template->SetAccessor(v8_str("unreachable"),
5412 UnreachableGetter, 0,
5413 v8::Handle<Value>(),
5414 v8::DEFAULT);
5415
5416 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
5417 context0->Enter();
5418
5419 Local<v8::Object> global = context0->Global();
5420 // Add a normal property that shadows 'accessible'
5421 global->Set(v8_str("accessible"), v8_num(11));
5422
5423 // Enter a new context.
5424 v8::HandleScope scope1;
5425 v8::Persistent<Context> context1 = Context::New();
5426 context1->Enter();
5427
5428 v8::Handle<v8::Object> global1 = context1->Global();
5429 global1->Set(v8_str("other"), global);
5430
5431 // Should return 10, instead of 11
5432 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
5433 CHECK(value->IsNumber());
5434 CHECK_EQ(10, value->Int32Value());
5435
5436 value = v8_compile("other.unreachable")->Run();
5437 CHECK(value->IsUndefined());
5438
5439 context1->Exit();
5440 context0->Exit();
5441 context1.Dispose();
5442 context0.Dispose();
5443}
5444
5445
5446static int named_access_count = 0;
5447static int indexed_access_count = 0;
5448
5449static bool NamedAccessCounter(Local<v8::Object> global,
5450 Local<Value> name,
5451 v8::AccessType type,
5452 Local<Value> data) {
5453 named_access_count++;
5454 return true;
5455}
5456
5457
5458static bool IndexedAccessCounter(Local<v8::Object> global,
5459 uint32_t key,
5460 v8::AccessType type,
5461 Local<Value> data) {
5462 indexed_access_count++;
5463 return true;
5464}
5465
5466
5467// This one is too easily disturbed by other tests.
5468TEST(AccessControlIC) {
5469 named_access_count = 0;
5470 indexed_access_count = 0;
5471
5472 v8::HandleScope handle_scope;
5473
5474 // Create an environment.
5475 v8::Persistent<Context> context0 = Context::New();
5476 context0->Enter();
5477
5478 // Create an object that requires access-check functions to be
5479 // called for cross-domain access.
5480 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5481 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5482 IndexedAccessCounter);
5483 Local<v8::Object> object = object_template->NewInstance();
5484
5485 v8::HandleScope scope1;
5486
5487 // Create another environment.
5488 v8::Persistent<Context> context1 = Context::New();
5489 context1->Enter();
5490
5491 // Make easy access to the object from the other environment.
5492 v8::Handle<v8::Object> global1 = context1->Global();
5493 global1->Set(v8_str("obj"), object);
5494
5495 v8::Handle<Value> value;
5496
5497 // Check that the named access-control function is called every time.
5498 CompileRun("function testProp(obj) {"
5499 " for (var i = 0; i < 10; i++) obj.prop = 1;"
5500 " for (var j = 0; j < 10; j++) obj.prop;"
5501 " return obj.prop"
5502 "}");
5503 value = CompileRun("testProp(obj)");
5504 CHECK(value->IsNumber());
5505 CHECK_EQ(1, value->Int32Value());
5506 CHECK_EQ(21, named_access_count);
5507
5508 // Check that the named access-control function is called every time.
5509 CompileRun("var p = 'prop';"
5510 "function testKeyed(obj) {"
5511 " for (var i = 0; i < 10; i++) obj[p] = 1;"
5512 " for (var j = 0; j < 10; j++) obj[p];"
5513 " return obj[p];"
5514 "}");
5515 // Use obj which requires access checks. No inline caching is used
5516 // in that case.
5517 value = CompileRun("testKeyed(obj)");
5518 CHECK(value->IsNumber());
5519 CHECK_EQ(1, value->Int32Value());
5520 CHECK_EQ(42, named_access_count);
5521 // Force the inline caches into generic state and try again.
5522 CompileRun("testKeyed({ a: 0 })");
5523 CompileRun("testKeyed({ b: 0 })");
5524 value = CompileRun("testKeyed(obj)");
5525 CHECK(value->IsNumber());
5526 CHECK_EQ(1, value->Int32Value());
5527 CHECK_EQ(63, named_access_count);
5528
5529 // Check that the indexed access-control function is called every time.
5530 CompileRun("function testIndexed(obj) {"
5531 " for (var i = 0; i < 10; i++) obj[0] = 1;"
5532 " for (var j = 0; j < 10; j++) obj[0];"
5533 " return obj[0]"
5534 "}");
5535 value = CompileRun("testIndexed(obj)");
5536 CHECK(value->IsNumber());
5537 CHECK_EQ(1, value->Int32Value());
5538 CHECK_EQ(21, indexed_access_count);
5539 // Force the inline caches into generic state.
5540 CompileRun("testIndexed(new Array(1))");
5541 // Test that the indexed access check is called.
5542 value = CompileRun("testIndexed(obj)");
5543 CHECK(value->IsNumber());
5544 CHECK_EQ(1, value->Int32Value());
5545 CHECK_EQ(42, indexed_access_count);
5546
5547 // Check that the named access check is called when invoking
5548 // functions on an object that requires access checks.
5549 CompileRun("obj.f = function() {}");
5550 CompileRun("function testCallNormal(obj) {"
5551 " for (var i = 0; i < 10; i++) obj.f();"
5552 "}");
5553 CompileRun("testCallNormal(obj)");
5554 CHECK_EQ(74, named_access_count);
5555
5556 // Force obj into slow case.
5557 value = CompileRun("delete obj.prop");
5558 CHECK(value->BooleanValue());
5559 // Force inline caches into dictionary probing mode.
5560 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
5561 // Test that the named access check is called.
5562 value = CompileRun("testProp(obj);");
5563 CHECK(value->IsNumber());
5564 CHECK_EQ(1, value->Int32Value());
5565 CHECK_EQ(96, named_access_count);
5566
5567 // Force the call inline cache into dictionary probing mode.
5568 CompileRun("o.f = function() {}; testCallNormal(o)");
5569 // Test that the named access check is still called for each
5570 // invocation of the function.
5571 value = CompileRun("testCallNormal(obj)");
5572 CHECK_EQ(106, named_access_count);
5573
5574 context1->Exit();
5575 context0->Exit();
5576 context1.Dispose();
5577 context0.Dispose();
5578}
5579
5580
5581static bool NamedAccessFlatten(Local<v8::Object> global,
5582 Local<Value> name,
5583 v8::AccessType type,
5584 Local<Value> data) {
5585 char buf[100];
5586 int len;
5587
5588 CHECK(name->IsString());
5589
5590 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005591 len = name.As<String>()->WriteAscii(buf);
Steve Blocka7e24c12009-10-30 11:49:00 +00005592 CHECK_EQ(4, len);
5593
5594 uint16_t buf2[100];
5595
5596 memset(buf, 0x1, sizeof(buf));
Steve Block6ded16b2010-05-10 14:33:55 +01005597 len = name.As<String>()->Write(buf2);
Steve Blocka7e24c12009-10-30 11:49:00 +00005598 CHECK_EQ(4, len);
5599
5600 return true;
5601}
5602
5603
5604static bool IndexedAccessFlatten(Local<v8::Object> global,
5605 uint32_t key,
5606 v8::AccessType type,
5607 Local<Value> data) {
5608 return true;
5609}
5610
5611
5612// Regression test. In access checks, operations that may cause
5613// garbage collection are not allowed. It used to be the case that
5614// using the Write operation on a string could cause a garbage
5615// collection due to flattening of the string. This is no longer the
5616// case.
5617THREADED_TEST(AccessControlFlatten) {
5618 named_access_count = 0;
5619 indexed_access_count = 0;
5620
5621 v8::HandleScope handle_scope;
5622
5623 // Create an environment.
5624 v8::Persistent<Context> context0 = Context::New();
5625 context0->Enter();
5626
5627 // Create an object that requires access-check functions to be
5628 // called for cross-domain access.
5629 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5630 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
5631 IndexedAccessFlatten);
5632 Local<v8::Object> object = object_template->NewInstance();
5633
5634 v8::HandleScope scope1;
5635
5636 // Create another environment.
5637 v8::Persistent<Context> context1 = Context::New();
5638 context1->Enter();
5639
5640 // Make easy access to the object from the other environment.
5641 v8::Handle<v8::Object> global1 = context1->Global();
5642 global1->Set(v8_str("obj"), object);
5643
5644 v8::Handle<Value> value;
5645
5646 value = v8_compile("var p = 'as' + 'df';")->Run();
5647 value = v8_compile("obj[p];")->Run();
5648
5649 context1->Exit();
5650 context0->Exit();
5651 context1.Dispose();
5652 context0.Dispose();
5653}
5654
5655
5656static v8::Handle<Value> AccessControlNamedGetter(
5657 Local<String>, const AccessorInfo&) {
5658 return v8::Integer::New(42);
5659}
5660
5661
5662static v8::Handle<Value> AccessControlNamedSetter(
5663 Local<String>, Local<Value> value, const AccessorInfo&) {
5664 return value;
5665}
5666
5667
5668static v8::Handle<Value> AccessControlIndexedGetter(
5669 uint32_t index,
5670 const AccessorInfo& info) {
5671 return v8_num(42);
5672}
5673
5674
5675static v8::Handle<Value> AccessControlIndexedSetter(
5676 uint32_t, Local<Value> value, const AccessorInfo&) {
5677 return value;
5678}
5679
5680
5681THREADED_TEST(AccessControlInterceptorIC) {
5682 named_access_count = 0;
5683 indexed_access_count = 0;
5684
5685 v8::HandleScope handle_scope;
5686
5687 // Create an environment.
5688 v8::Persistent<Context> context0 = Context::New();
5689 context0->Enter();
5690
5691 // Create an object that requires access-check functions to be
5692 // called for cross-domain access. The object also has interceptors
5693 // interceptor.
5694 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
5695 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
5696 IndexedAccessCounter);
5697 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
5698 AccessControlNamedSetter);
5699 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
5700 AccessControlIndexedSetter);
5701 Local<v8::Object> object = object_template->NewInstance();
5702
5703 v8::HandleScope scope1;
5704
5705 // Create another environment.
5706 v8::Persistent<Context> context1 = Context::New();
5707 context1->Enter();
5708
5709 // Make easy access to the object from the other environment.
5710 v8::Handle<v8::Object> global1 = context1->Global();
5711 global1->Set(v8_str("obj"), object);
5712
5713 v8::Handle<Value> value;
5714
5715 // Check that the named access-control function is called every time
5716 // eventhough there is an interceptor on the object.
5717 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
5718 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
5719 "obj.x")->Run();
5720 CHECK(value->IsNumber());
5721 CHECK_EQ(42, value->Int32Value());
5722 CHECK_EQ(21, named_access_count);
5723
5724 value = v8_compile("var p = 'x';")->Run();
5725 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
5726 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
5727 "obj[p]")->Run();
5728 CHECK(value->IsNumber());
5729 CHECK_EQ(42, value->Int32Value());
5730 CHECK_EQ(42, named_access_count);
5731
5732 // Check that the indexed access-control function is called every
5733 // time eventhough there is an interceptor on the object.
5734 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5735 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5736 "obj[0]")->Run();
5737 CHECK(value->IsNumber());
5738 CHECK_EQ(42, value->Int32Value());
5739 CHECK_EQ(21, indexed_access_count);
5740
5741 context1->Exit();
5742 context0->Exit();
5743 context1.Dispose();
5744 context0.Dispose();
5745}
5746
5747
5748THREADED_TEST(Version) {
5749 v8::V8::GetVersion();
5750}
5751
5752
5753static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5754 ApiTestFuzzer::Fuzz();
5755 return v8_num(12);
5756}
5757
5758
5759THREADED_TEST(InstanceProperties) {
5760 v8::HandleScope handle_scope;
5761 LocalContext context;
5762
5763 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5764 Local<ObjectTemplate> instance = t->InstanceTemplate();
5765
5766 instance->Set(v8_str("x"), v8_num(42));
5767 instance->Set(v8_str("f"),
5768 v8::FunctionTemplate::New(InstanceFunctionCallback));
5769
5770 Local<Value> o = t->GetFunction()->NewInstance();
5771
5772 context->Global()->Set(v8_str("i"), o);
5773 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5774 CHECK_EQ(42, value->Int32Value());
5775
5776 value = Script::Compile(v8_str("i.f()"))->Run();
5777 CHECK_EQ(12, value->Int32Value());
5778}
5779
5780
5781static v8::Handle<Value>
5782GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5783 ApiTestFuzzer::Fuzz();
5784 return v8::Handle<Value>();
5785}
5786
5787
5788THREADED_TEST(GlobalObjectInstanceProperties) {
5789 v8::HandleScope handle_scope;
5790
5791 Local<Value> global_object;
5792
5793 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5794 t->InstanceTemplate()->SetNamedPropertyHandler(
5795 GlobalObjectInstancePropertiesGet);
5796 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5797 instance_template->Set(v8_str("x"), v8_num(42));
5798 instance_template->Set(v8_str("f"),
5799 v8::FunctionTemplate::New(InstanceFunctionCallback));
5800
Ben Murdochb0fe1622011-05-05 13:52:32 +01005801 // The script to check how Crankshaft compiles missing global function
5802 // invocations. function g is not defined and should throw on call.
5803 const char* script =
5804 "function wrapper(call) {"
5805 " var x = 0, y = 1;"
5806 " for (var i = 0; i < 1000; i++) {"
5807 " x += i * 100;"
5808 " y += i * 100;"
5809 " }"
5810 " if (call) g();"
5811 "}"
5812 "for (var i = 0; i < 17; i++) wrapper(false);"
5813 "var thrown = 0;"
5814 "try { wrapper(true); } catch (e) { thrown = 1; };"
5815 "thrown";
5816
Steve Blocka7e24c12009-10-30 11:49:00 +00005817 {
5818 LocalContext env(NULL, instance_template);
5819 // Hold on to the global object so it can be used again in another
5820 // environment initialization.
5821 global_object = env->Global();
5822
5823 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5824 CHECK_EQ(42, value->Int32Value());
5825 value = Script::Compile(v8_str("f()"))->Run();
5826 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005827 value = Script::Compile(v8_str(script))->Run();
5828 CHECK_EQ(1, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005829 }
5830
5831 {
5832 // Create new environment reusing the global object.
5833 LocalContext env(NULL, instance_template, global_object);
5834 Local<Value> value = Script::Compile(v8_str("x"))->Run();
5835 CHECK_EQ(42, value->Int32Value());
5836 value = Script::Compile(v8_str("f()"))->Run();
5837 CHECK_EQ(12, value->Int32Value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005838 value = Script::Compile(v8_str(script))->Run();
5839 CHECK_EQ(1, value->Int32Value());
5840 }
5841}
5842
5843
5844THREADED_TEST(CallKnownGlobalReceiver) {
5845 v8::HandleScope handle_scope;
5846
5847 Local<Value> global_object;
5848
5849 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5850 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5851
5852 // The script to check that we leave global object not
5853 // global object proxy on stack when we deoptimize from inside
5854 // arguments evaluation.
5855 // To provoke error we need to both force deoptimization
5856 // from arguments evaluation and to force CallIC to take
5857 // CallIC_Miss code path that can't cope with global proxy.
5858 const char* script =
5859 "function bar(x, y) { try { } finally { } }"
5860 "function baz(x) { try { } finally { } }"
5861 "function bom(x) { try { } finally { } }"
5862 "function foo(x) { bar([x], bom(2)); }"
5863 "for (var i = 0; i < 10000; i++) foo(1);"
5864 "foo";
5865
5866 Local<Value> foo;
5867 {
5868 LocalContext env(NULL, instance_template);
5869 // Hold on to the global object so it can be used again in another
5870 // environment initialization.
5871 global_object = env->Global();
5872 foo = Script::Compile(v8_str(script))->Run();
5873 }
5874
5875 {
5876 // Create new environment reusing the global object.
5877 LocalContext env(NULL, instance_template, global_object);
5878 env->Global()->Set(v8_str("foo"), foo);
5879 Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +00005880 }
5881}
5882
5883
5884static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5885 ApiTestFuzzer::Fuzz();
5886 return v8_num(42);
5887}
5888
5889
5890static int shadow_y;
5891static int shadow_y_setter_call_count;
5892static int shadow_y_getter_call_count;
5893
5894
5895static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5896 shadow_y_setter_call_count++;
5897 shadow_y = 42;
5898}
5899
5900
5901static v8::Handle<Value> ShadowYGetter(Local<String> name,
5902 const AccessorInfo& info) {
5903 ApiTestFuzzer::Fuzz();
5904 shadow_y_getter_call_count++;
5905 return v8_num(shadow_y);
5906}
5907
5908
5909static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5910 const AccessorInfo& info) {
5911 return v8::Handle<Value>();
5912}
5913
5914
5915static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5916 const AccessorInfo&) {
5917 return v8::Handle<Value>();
5918}
5919
5920
5921THREADED_TEST(ShadowObject) {
5922 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5923 v8::HandleScope handle_scope;
5924
5925 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5926 LocalContext context(NULL, global_template);
5927
5928 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5929 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5930 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5931 Local<ObjectTemplate> proto = t->PrototypeTemplate();
5932 Local<ObjectTemplate> instance = t->InstanceTemplate();
5933
5934 // Only allow calls of f on instances of t.
5935 Local<v8::Signature> signature = v8::Signature::New(t);
5936 proto->Set(v8_str("f"),
5937 v8::FunctionTemplate::New(ShadowFunctionCallback,
5938 Local<Value>(),
5939 signature));
5940 proto->Set(v8_str("x"), v8_num(12));
5941
5942 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5943
5944 Local<Value> o = t->GetFunction()->NewInstance();
5945 context->Global()->Set(v8_str("__proto__"), o);
5946
5947 Local<Value> value =
5948 Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5949 CHECK(value->IsBoolean());
5950 CHECK(!value->BooleanValue());
5951
5952 value = Script::Compile(v8_str("x"))->Run();
5953 CHECK_EQ(12, value->Int32Value());
5954
5955 value = Script::Compile(v8_str("f()"))->Run();
5956 CHECK_EQ(42, value->Int32Value());
5957
5958 Script::Compile(v8_str("y = 42"))->Run();
5959 CHECK_EQ(1, shadow_y_setter_call_count);
5960 value = Script::Compile(v8_str("y"))->Run();
5961 CHECK_EQ(1, shadow_y_getter_call_count);
5962 CHECK_EQ(42, value->Int32Value());
5963}
5964
5965
5966THREADED_TEST(HiddenPrototype) {
5967 v8::HandleScope handle_scope;
5968 LocalContext context;
5969
5970 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5971 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5972 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5973 t1->SetHiddenPrototype(true);
5974 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5975 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5976 t2->SetHiddenPrototype(true);
5977 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5978 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5979 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5980
5981 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5982 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5983 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5984 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5985
5986 // Setting the prototype on an object skips hidden prototypes.
5987 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5988 o0->Set(v8_str("__proto__"), o1);
5989 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5990 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5991 o0->Set(v8_str("__proto__"), o2);
5992 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5993 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5994 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5995 o0->Set(v8_str("__proto__"), o3);
5996 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5997 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5998 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5999 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6000
6001 // Getting the prototype of o0 should get the first visible one
6002 // which is o3. Therefore, z should not be defined on the prototype
6003 // object.
6004 Local<Value> proto = o0->Get(v8_str("__proto__"));
6005 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006006 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00006007}
6008
6009
Andrei Popescu402d9372010-02-26 13:31:12 +00006010THREADED_TEST(SetPrototype) {
6011 v8::HandleScope handle_scope;
6012 LocalContext context;
6013
6014 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
6015 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
6016 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
6017 t1->SetHiddenPrototype(true);
6018 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
6019 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
6020 t2->SetHiddenPrototype(true);
6021 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
6022 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
6023 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
6024
6025 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
6026 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
6027 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
6028 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
6029
6030 // Setting the prototype on an object does not skip hidden prototypes.
6031 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6032 CHECK(o0->SetPrototype(o1));
6033 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6034 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6035 CHECK(o1->SetPrototype(o2));
6036 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6037 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6038 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6039 CHECK(o2->SetPrototype(o3));
6040 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
6041 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
6042 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
6043 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
6044
6045 // Getting the prototype of o0 should get the first visible one
6046 // which is o3. Therefore, z should not be defined on the prototype
6047 // object.
6048 Local<Value> proto = o0->Get(v8_str("__proto__"));
6049 CHECK(proto->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006050 CHECK_EQ(proto.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00006051
6052 // However, Object::GetPrototype ignores hidden prototype.
6053 Local<Value> proto0 = o0->GetPrototype();
6054 CHECK(proto0->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006055 CHECK_EQ(proto0.As<v8::Object>(), o1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006056
6057 Local<Value> proto1 = o1->GetPrototype();
6058 CHECK(proto1->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006059 CHECK_EQ(proto1.As<v8::Object>(), o2);
Andrei Popescu402d9372010-02-26 13:31:12 +00006060
6061 Local<Value> proto2 = o2->GetPrototype();
6062 CHECK(proto2->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01006063 CHECK_EQ(proto2.As<v8::Object>(), o3);
Andrei Popescu402d9372010-02-26 13:31:12 +00006064}
6065
6066
6067THREADED_TEST(SetPrototypeThrows) {
6068 v8::HandleScope handle_scope;
6069 LocalContext context;
6070
6071 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6072
6073 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
6074 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
6075
6076 CHECK(o0->SetPrototype(o1));
6077 // If setting the prototype leads to the cycle, SetPrototype should
6078 // return false and keep VM in sane state.
6079 v8::TryCatch try_catch;
6080 CHECK(!o1->SetPrototype(o0));
6081 CHECK(!try_catch.HasCaught());
6082 ASSERT(!i::Top::has_pending_exception());
6083
6084 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
6085}
6086
6087
Steve Blocka7e24c12009-10-30 11:49:00 +00006088THREADED_TEST(GetterSetterExceptions) {
6089 v8::HandleScope handle_scope;
6090 LocalContext context;
6091 CompileRun(
6092 "function Foo() { };"
6093 "function Throw() { throw 5; };"
6094 "var x = { };"
6095 "x.__defineSetter__('set', Throw);"
6096 "x.__defineGetter__('get', Throw);");
6097 Local<v8::Object> x =
6098 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
6099 v8::TryCatch try_catch;
6100 x->Set(v8_str("set"), v8::Integer::New(8));
6101 x->Get(v8_str("get"));
6102 x->Set(v8_str("set"), v8::Integer::New(8));
6103 x->Get(v8_str("get"));
6104 x->Set(v8_str("set"), v8::Integer::New(8));
6105 x->Get(v8_str("get"));
6106 x->Set(v8_str("set"), v8::Integer::New(8));
6107 x->Get(v8_str("get"));
6108}
6109
6110
6111THREADED_TEST(Constructor) {
6112 v8::HandleScope handle_scope;
6113 LocalContext context;
6114 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6115 templ->SetClassName(v8_str("Fun"));
6116 Local<Function> cons = templ->GetFunction();
6117 context->Global()->Set(v8_str("Fun"), cons);
6118 Local<v8::Object> inst = cons->NewInstance();
6119 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
6120 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
6121 CHECK(value->BooleanValue());
6122}
6123
6124THREADED_TEST(FunctionDescriptorException) {
6125 v8::HandleScope handle_scope;
6126 LocalContext context;
6127 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6128 templ->SetClassName(v8_str("Fun"));
6129 Local<Function> cons = templ->GetFunction();
6130 context->Global()->Set(v8_str("Fun"), cons);
6131 Local<Value> value = CompileRun(
6132 "function test() {"
6133 " try {"
6134 " (new Fun()).blah()"
6135 " } catch (e) {"
6136 " var str = String(e);"
6137 " if (str.indexOf('TypeError') == -1) return 1;"
6138 " if (str.indexOf('[object Fun]') != -1) return 2;"
6139 " if (str.indexOf('#<a Fun>') == -1) return 3;"
6140 " return 0;"
6141 " }"
6142 " return 4;"
6143 "}"
6144 "test();");
6145 CHECK_EQ(0, value->Int32Value());
6146}
6147
6148
6149THREADED_TEST(EvalAliasedDynamic) {
6150 v8::HandleScope scope;
6151 LocalContext current;
6152
6153 // Tests where aliased eval can only be resolved dynamically.
6154 Local<Script> script =
6155 Script::Compile(v8_str("function f(x) { "
6156 " var foo = 2;"
6157 " with (x) { return eval('foo'); }"
6158 "}"
6159 "foo = 0;"
6160 "result1 = f(new Object());"
6161 "result2 = f(this);"
6162 "var x = new Object();"
6163 "x.eval = function(x) { return 1; };"
6164 "result3 = f(x);"));
6165 script->Run();
6166 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
6167 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
6168 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
6169
6170 v8::TryCatch try_catch;
6171 script =
6172 Script::Compile(v8_str("function f(x) { "
6173 " var bar = 2;"
6174 " with (x) { return eval('bar'); }"
6175 "}"
6176 "f(this)"));
6177 script->Run();
6178 CHECK(try_catch.HasCaught());
6179 try_catch.Reset();
6180}
6181
6182
6183THREADED_TEST(CrossEval) {
6184 v8::HandleScope scope;
6185 LocalContext other;
6186 LocalContext current;
6187
6188 Local<String> token = v8_str("<security token>");
6189 other->SetSecurityToken(token);
6190 current->SetSecurityToken(token);
6191
6192 // Setup reference from current to other.
6193 current->Global()->Set(v8_str("other"), other->Global());
6194
6195 // Check that new variables are introduced in other context.
6196 Local<Script> script =
6197 Script::Compile(v8_str("other.eval('var foo = 1234')"));
6198 script->Run();
6199 Local<Value> foo = other->Global()->Get(v8_str("foo"));
6200 CHECK_EQ(1234, foo->Int32Value());
6201 CHECK(!current->Global()->Has(v8_str("foo")));
6202
6203 // Check that writing to non-existing properties introduces them in
6204 // the other context.
6205 script =
6206 Script::Compile(v8_str("other.eval('na = 1234')"));
6207 script->Run();
6208 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
6209 CHECK(!current->Global()->Has(v8_str("na")));
6210
6211 // Check that global variables in current context are not visible in other
6212 // context.
6213 v8::TryCatch try_catch;
6214 script =
6215 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
6216 Local<Value> result = script->Run();
6217 CHECK(try_catch.HasCaught());
6218 try_catch.Reset();
6219
6220 // Check that local variables in current context are not visible in other
6221 // context.
6222 script =
6223 Script::Compile(v8_str("(function() { "
6224 " var baz = 87;"
6225 " return other.eval('baz');"
6226 "})();"));
6227 result = script->Run();
6228 CHECK(try_catch.HasCaught());
6229 try_catch.Reset();
6230
6231 // Check that global variables in the other environment are visible
6232 // when evaluting code.
6233 other->Global()->Set(v8_str("bis"), v8_num(1234));
6234 script = Script::Compile(v8_str("other.eval('bis')"));
6235 CHECK_EQ(1234, script->Run()->Int32Value());
6236 CHECK(!try_catch.HasCaught());
6237
6238 // Check that the 'this' pointer points to the global object evaluating
6239 // code.
6240 other->Global()->Set(v8_str("t"), other->Global());
6241 script = Script::Compile(v8_str("other.eval('this == t')"));
6242 result = script->Run();
6243 CHECK(result->IsTrue());
6244 CHECK(!try_catch.HasCaught());
6245
6246 // Check that variables introduced in with-statement are not visible in
6247 // other context.
6248 script =
6249 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
6250 result = script->Run();
6251 CHECK(try_catch.HasCaught());
6252 try_catch.Reset();
6253
6254 // Check that you cannot use 'eval.call' with another object than the
6255 // current global object.
6256 script =
6257 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
6258 result = script->Run();
6259 CHECK(try_catch.HasCaught());
6260}
6261
6262
6263// Test that calling eval in a context which has been detached from
6264// its global throws an exception. This behavior is consistent with
6265// other JavaScript implementations.
6266THREADED_TEST(EvalInDetachedGlobal) {
6267 v8::HandleScope scope;
6268
6269 v8::Persistent<Context> context0 = Context::New();
6270 v8::Persistent<Context> context1 = Context::New();
6271
6272 // Setup function in context0 that uses eval from context0.
6273 context0->Enter();
6274 v8::Handle<v8::Value> fun =
6275 CompileRun("var x = 42;"
6276 "(function() {"
6277 " var e = eval;"
6278 " return function(s) { return e(s); }"
6279 "})()");
6280 context0->Exit();
6281
6282 // Put the function into context1 and call it before and after
6283 // detaching the global. Before detaching, the call succeeds and
6284 // after detaching and exception is thrown.
6285 context1->Enter();
6286 context1->Global()->Set(v8_str("fun"), fun);
6287 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
6288 CHECK_EQ(42, x_value->Int32Value());
6289 context0->DetachGlobal();
6290 v8::TryCatch catcher;
6291 x_value = CompileRun("fun('x')");
6292 CHECK(x_value.IsEmpty());
6293 CHECK(catcher.HasCaught());
6294 context1->Exit();
6295
6296 context1.Dispose();
6297 context0.Dispose();
6298}
6299
6300
6301THREADED_TEST(CrossLazyLoad) {
6302 v8::HandleScope scope;
6303 LocalContext other;
6304 LocalContext current;
6305
6306 Local<String> token = v8_str("<security token>");
6307 other->SetSecurityToken(token);
6308 current->SetSecurityToken(token);
6309
6310 // Setup reference from current to other.
6311 current->Global()->Set(v8_str("other"), other->Global());
6312
6313 // Trigger lazy loading in other context.
6314 Local<Script> script =
6315 Script::Compile(v8_str("other.eval('new Date(42)')"));
6316 Local<Value> value = script->Run();
6317 CHECK_EQ(42.0, value->NumberValue());
6318}
6319
6320
6321static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006322 ApiTestFuzzer::Fuzz();
Steve Blocka7e24c12009-10-30 11:49:00 +00006323 if (args.IsConstructCall()) {
6324 if (args[0]->IsInt32()) {
6325 return v8_num(-args[0]->Int32Value());
6326 }
6327 }
6328
6329 return args[0];
6330}
6331
6332
6333// Test that a call handler can be set for objects which will allow
6334// non-function objects created through the API to be called as
6335// functions.
6336THREADED_TEST(CallAsFunction) {
6337 v8::HandleScope scope;
6338 LocalContext context;
6339
6340 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
6341 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
6342 instance_template->SetCallAsFunctionHandler(call_as_function);
6343 Local<v8::Object> instance = t->GetFunction()->NewInstance();
6344 context->Global()->Set(v8_str("obj"), instance);
6345 v8::TryCatch try_catch;
6346 Local<Value> value;
6347 CHECK(!try_catch.HasCaught());
6348
6349 value = CompileRun("obj(42)");
6350 CHECK(!try_catch.HasCaught());
6351 CHECK_EQ(42, value->Int32Value());
6352
6353 value = CompileRun("(function(o){return o(49)})(obj)");
6354 CHECK(!try_catch.HasCaught());
6355 CHECK_EQ(49, value->Int32Value());
6356
6357 // test special case of call as function
6358 value = CompileRun("[obj]['0'](45)");
6359 CHECK(!try_catch.HasCaught());
6360 CHECK_EQ(45, value->Int32Value());
6361
6362 value = CompileRun("obj.call = Function.prototype.call;"
6363 "obj.call(null, 87)");
6364 CHECK(!try_catch.HasCaught());
6365 CHECK_EQ(87, value->Int32Value());
6366
6367 // Regression tests for bug #1116356: Calling call through call/apply
6368 // must work for non-function receivers.
6369 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
6370 value = CompileRun(apply_99);
6371 CHECK(!try_catch.HasCaught());
6372 CHECK_EQ(99, value->Int32Value());
6373
6374 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
6375 value = CompileRun(call_17);
6376 CHECK(!try_catch.HasCaught());
6377 CHECK_EQ(17, value->Int32Value());
6378
6379 // Check that the call-as-function handler can be called through
Leon Clarkee46be812010-01-19 14:06:41 +00006380 // new.
Steve Blocka7e24c12009-10-30 11:49:00 +00006381 value = CompileRun("new obj(43)");
6382 CHECK(!try_catch.HasCaught());
6383 CHECK_EQ(-43, value->Int32Value());
6384}
6385
6386
6387static int CountHandles() {
6388 return v8::HandleScope::NumberOfHandles();
6389}
6390
6391
6392static int Recurse(int depth, int iterations) {
6393 v8::HandleScope scope;
6394 if (depth == 0) return CountHandles();
6395 for (int i = 0; i < iterations; i++) {
6396 Local<v8::Number> n = v8::Integer::New(42);
6397 }
6398 return Recurse(depth - 1, iterations);
6399}
6400
6401
6402THREADED_TEST(HandleIteration) {
6403 static const int kIterations = 500;
6404 static const int kNesting = 200;
6405 CHECK_EQ(0, CountHandles());
6406 {
6407 v8::HandleScope scope1;
6408 CHECK_EQ(0, CountHandles());
6409 for (int i = 0; i < kIterations; i++) {
6410 Local<v8::Number> n = v8::Integer::New(42);
6411 CHECK_EQ(i + 1, CountHandles());
6412 }
6413
6414 CHECK_EQ(kIterations, CountHandles());
6415 {
6416 v8::HandleScope scope2;
6417 for (int j = 0; j < kIterations; j++) {
6418 Local<v8::Number> n = v8::Integer::New(42);
6419 CHECK_EQ(j + 1 + kIterations, CountHandles());
6420 }
6421 }
6422 CHECK_EQ(kIterations, CountHandles());
6423 }
6424 CHECK_EQ(0, CountHandles());
6425 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
6426}
6427
6428
6429static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
6430 Local<String> name,
6431 const AccessorInfo& info) {
6432 ApiTestFuzzer::Fuzz();
6433 return v8::Handle<Value>();
6434}
6435
6436
6437THREADED_TEST(InterceptorHasOwnProperty) {
6438 v8::HandleScope scope;
6439 LocalContext context;
6440 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6441 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6442 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
6443 Local<Function> function = fun_templ->GetFunction();
6444 context->Global()->Set(v8_str("constructor"), function);
6445 v8::Handle<Value> value = CompileRun(
6446 "var o = new constructor();"
6447 "o.hasOwnProperty('ostehaps');");
6448 CHECK_EQ(false, value->BooleanValue());
6449 value = CompileRun(
6450 "o.ostehaps = 42;"
6451 "o.hasOwnProperty('ostehaps');");
6452 CHECK_EQ(true, value->BooleanValue());
6453 value = CompileRun(
6454 "var p = new constructor();"
6455 "p.hasOwnProperty('ostehaps');");
6456 CHECK_EQ(false, value->BooleanValue());
6457}
6458
6459
6460static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
6461 Local<String> name,
6462 const AccessorInfo& info) {
6463 ApiTestFuzzer::Fuzz();
6464 i::Heap::CollectAllGarbage(false);
6465 return v8::Handle<Value>();
6466}
6467
6468
6469THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
6470 v8::HandleScope scope;
6471 LocalContext context;
6472 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6473 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
6474 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
6475 Local<Function> function = fun_templ->GetFunction();
6476 context->Global()->Set(v8_str("constructor"), function);
6477 // Let's first make some stuff so we can be sure to get a good GC.
6478 CompileRun(
6479 "function makestr(size) {"
6480 " switch (size) {"
6481 " case 1: return 'f';"
6482 " case 2: return 'fo';"
6483 " case 3: return 'foo';"
6484 " }"
6485 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
6486 "}"
6487 "var x = makestr(12345);"
6488 "x = makestr(31415);"
6489 "x = makestr(23456);");
6490 v8::Handle<Value> value = CompileRun(
6491 "var o = new constructor();"
6492 "o.__proto__ = new String(x);"
6493 "o.hasOwnProperty('ostehaps');");
6494 CHECK_EQ(false, value->BooleanValue());
6495}
6496
6497
6498typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
6499 const AccessorInfo& info);
6500
6501
6502static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
6503 const char* source,
6504 int expected) {
6505 v8::HandleScope scope;
6506 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006507 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00006508 LocalContext context;
6509 context->Global()->Set(v8_str("o"), templ->NewInstance());
6510 v8::Handle<Value> value = CompileRun(source);
6511 CHECK_EQ(expected, value->Int32Value());
6512}
6513
6514
6515static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
6516 const AccessorInfo& info) {
6517 ApiTestFuzzer::Fuzz();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006518 CHECK_EQ(v8_str("data"), info.Data());
6519 CHECK_EQ(v8_str("x"), name);
Steve Blocka7e24c12009-10-30 11:49:00 +00006520 return v8::Integer::New(42);
6521}
6522
6523
6524// This test should hit the load IC for the interceptor case.
6525THREADED_TEST(InterceptorLoadIC) {
6526 CheckInterceptorLoadIC(InterceptorLoadICGetter,
6527 "var result = 0;"
6528 "for (var i = 0; i < 1000; i++) {"
6529 " result = o.x;"
6530 "}",
6531 42);
6532}
6533
6534
6535// Below go several tests which verify that JITing for various
6536// configurations of interceptor and explicit fields works fine
6537// (those cases are special cased to get better performance).
6538
6539static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
6540 const AccessorInfo& info) {
6541 ApiTestFuzzer::Fuzz();
6542 return v8_str("x")->Equals(name)
6543 ? v8::Integer::New(42) : v8::Handle<v8::Value>();
6544}
6545
6546
6547THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
6548 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6549 "var result = 0;"
6550 "o.y = 239;"
6551 "for (var i = 0; i < 1000; i++) {"
6552 " result = o.y;"
6553 "}",
6554 239);
6555}
6556
6557
6558THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
6559 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6560 "var result = 0;"
6561 "o.__proto__ = { 'y': 239 };"
6562 "for (var i = 0; i < 1000; i++) {"
6563 " result = o.y + o.x;"
6564 "}",
6565 239 + 42);
6566}
6567
6568
6569THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
6570 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6571 "var result = 0;"
6572 "o.__proto__.y = 239;"
6573 "for (var i = 0; i < 1000; i++) {"
6574 " result = o.y + o.x;"
6575 "}",
6576 239 + 42);
6577}
6578
6579
6580THREADED_TEST(InterceptorLoadICUndefined) {
6581 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6582 "var result = 0;"
6583 "for (var i = 0; i < 1000; i++) {"
6584 " result = (o.y == undefined) ? 239 : 42;"
6585 "}",
6586 239);
6587}
6588
6589
6590THREADED_TEST(InterceptorLoadICWithOverride) {
6591 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6592 "fst = new Object(); fst.__proto__ = o;"
6593 "snd = new Object(); snd.__proto__ = fst;"
6594 "var result1 = 0;"
6595 "for (var i = 0; i < 1000; i++) {"
6596 " result1 = snd.x;"
6597 "}"
6598 "fst.x = 239;"
6599 "var result = 0;"
6600 "for (var i = 0; i < 1000; i++) {"
6601 " result = snd.x;"
6602 "}"
6603 "result + result1",
6604 239 + 42);
6605}
6606
6607
6608// Test the case when we stored field into
6609// a stub, but interceptor produced value on its own.
6610THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
6611 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6612 "proto = new Object();"
6613 "o.__proto__ = proto;"
6614 "proto.x = 239;"
6615 "for (var i = 0; i < 1000; i++) {"
6616 " o.x;"
6617 // Now it should be ICed and keep a reference to x defined on proto
6618 "}"
6619 "var result = 0;"
6620 "for (var i = 0; i < 1000; i++) {"
6621 " result += o.x;"
6622 "}"
6623 "result;",
6624 42 * 1000);
6625}
6626
6627
6628// Test the case when we stored field into
6629// a stub, but it got invalidated later on.
6630THREADED_TEST(InterceptorLoadICInvalidatedField) {
6631 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6632 "proto1 = new Object();"
6633 "proto2 = new Object();"
6634 "o.__proto__ = proto1;"
6635 "proto1.__proto__ = proto2;"
6636 "proto2.y = 239;"
6637 "for (var i = 0; i < 1000; i++) {"
6638 " o.y;"
6639 // Now it should be ICed and keep a reference to y defined on proto2
6640 "}"
6641 "proto1.y = 42;"
6642 "var result = 0;"
6643 "for (var i = 0; i < 1000; i++) {"
6644 " result += o.y;"
6645 "}"
6646 "result;",
6647 42 * 1000);
6648}
6649
6650
Steve Block6ded16b2010-05-10 14:33:55 +01006651static int interceptor_load_not_handled_calls = 0;
6652static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
6653 const AccessorInfo& info) {
6654 ++interceptor_load_not_handled_calls;
6655 return v8::Handle<v8::Value>();
6656}
6657
6658
6659// Test how post-interceptor lookups are done in the non-cacheable
6660// case: the interceptor should not be invoked during this lookup.
6661THREADED_TEST(InterceptorLoadICPostInterceptor) {
6662 interceptor_load_not_handled_calls = 0;
6663 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
6664 "receiver = new Object();"
6665 "receiver.__proto__ = o;"
6666 "proto = new Object();"
6667 "/* Make proto a slow-case object. */"
6668 "for (var i = 0; i < 1000; i++) {"
6669 " proto[\"xxxxxxxx\" + i] = [];"
6670 "}"
6671 "proto.x = 17;"
6672 "o.__proto__ = proto;"
6673 "var result = 0;"
6674 "for (var i = 0; i < 1000; i++) {"
6675 " result += receiver.x;"
6676 "}"
6677 "result;",
6678 17 * 1000);
6679 CHECK_EQ(1000, interceptor_load_not_handled_calls);
6680}
6681
6682
Steve Blocka7e24c12009-10-30 11:49:00 +00006683// Test the case when we stored field into
6684// a stub, but it got invalidated later on due to override on
6685// global object which is between interceptor and fields' holders.
6686THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
6687 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
6688 "o.__proto__ = this;" // set a global to be a proto of o.
6689 "this.__proto__.y = 239;"
6690 "for (var i = 0; i < 10; i++) {"
6691 " if (o.y != 239) throw 'oops: ' + o.y;"
6692 // Now it should be ICed and keep a reference to y defined on field_holder.
6693 "}"
6694 "this.y = 42;" // Assign on a global.
6695 "var result = 0;"
6696 "for (var i = 0; i < 10; i++) {"
6697 " result += o.y;"
6698 "}"
6699 "result;",
6700 42 * 10);
6701}
6702
6703
Steve Blocka7e24c12009-10-30 11:49:00 +00006704static void SetOnThis(Local<String> name,
6705 Local<Value> value,
6706 const AccessorInfo& info) {
6707 info.This()->ForceSet(name, value);
6708}
6709
6710
6711THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
6712 v8::HandleScope scope;
6713 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6714 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6715 templ->SetAccessor(v8_str("y"), Return239);
6716 LocalContext context;
6717 context->Global()->Set(v8_str("o"), templ->NewInstance());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006718
6719 // Check the case when receiver and interceptor's holder
6720 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00006721 v8::Handle<Value> value = CompileRun(
6722 "var result = 0;"
6723 "for (var i = 0; i < 7; i++) {"
6724 " result = o.y;"
6725 "}");
6726 CHECK_EQ(239, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006727
6728 // Check the case when interceptor's holder is in proto chain
6729 // of receiver.
6730 value = CompileRun(
6731 "r = { __proto__: o };"
6732 "var result = 0;"
6733 "for (var i = 0; i < 7; i++) {"
6734 " result = r.y;"
6735 "}");
6736 CHECK_EQ(239, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006737}
6738
6739
6740THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
6741 v8::HandleScope scope;
6742 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6743 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6744 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6745 templ_p->SetAccessor(v8_str("y"), Return239);
6746
6747 LocalContext context;
6748 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6749 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6750
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006751 // Check the case when receiver and interceptor's holder
6752 // are the same objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00006753 v8::Handle<Value> value = CompileRun(
6754 "o.__proto__ = p;"
6755 "var result = 0;"
6756 "for (var i = 0; i < 7; i++) {"
6757 " result = o.x + o.y;"
6758 "}");
6759 CHECK_EQ(239 + 42, value->Int32Value());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006760
6761 // Check the case when interceptor's holder is in proto chain
6762 // of receiver.
6763 value = CompileRun(
6764 "r = { __proto__: o };"
6765 "var result = 0;"
6766 "for (var i = 0; i < 7; i++) {"
6767 " result = r.x + r.y;"
6768 "}");
6769 CHECK_EQ(239 + 42, value->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006770}
6771
6772
6773THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
6774 v8::HandleScope scope;
6775 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6776 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6777 templ->SetAccessor(v8_str("y"), Return239);
6778
6779 LocalContext context;
6780 context->Global()->Set(v8_str("o"), templ->NewInstance());
6781
6782 v8::Handle<Value> value = CompileRun(
6783 "fst = new Object(); fst.__proto__ = o;"
6784 "snd = new Object(); snd.__proto__ = fst;"
6785 "var result1 = 0;"
6786 "for (var i = 0; i < 7; i++) {"
6787 " result1 = snd.x;"
6788 "}"
6789 "fst.x = 239;"
6790 "var result = 0;"
6791 "for (var i = 0; i < 7; i++) {"
6792 " result = snd.x;"
6793 "}"
6794 "result + result1");
6795 CHECK_EQ(239 + 42, value->Int32Value());
6796}
6797
6798
6799// Test the case when we stored callback into
6800// a stub, but interceptor produced value on its own.
6801THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
6802 v8::HandleScope scope;
6803 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6804 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6805 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6806 templ_p->SetAccessor(v8_str("y"), Return239);
6807
6808 LocalContext context;
6809 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6810 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6811
6812 v8::Handle<Value> value = CompileRun(
6813 "o.__proto__ = p;"
6814 "for (var i = 0; i < 7; i++) {"
6815 " o.x;"
6816 // Now it should be ICed and keep a reference to x defined on p
6817 "}"
6818 "var result = 0;"
6819 "for (var i = 0; i < 7; i++) {"
6820 " result += o.x;"
6821 "}"
6822 "result");
6823 CHECK_EQ(42 * 7, value->Int32Value());
6824}
6825
6826
6827// Test the case when we stored callback into
6828// a stub, but it got invalidated later on.
6829THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
6830 v8::HandleScope scope;
6831 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6832 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6833 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6834 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6835
6836 LocalContext context;
6837 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6838 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6839
6840 v8::Handle<Value> value = CompileRun(
6841 "inbetween = new Object();"
6842 "o.__proto__ = inbetween;"
6843 "inbetween.__proto__ = p;"
6844 "for (var i = 0; i < 10; i++) {"
6845 " o.y;"
6846 // Now it should be ICed and keep a reference to y defined on p
6847 "}"
6848 "inbetween.y = 42;"
6849 "var result = 0;"
6850 "for (var i = 0; i < 10; i++) {"
6851 " result += o.y;"
6852 "}"
6853 "result");
6854 CHECK_EQ(42 * 10, value->Int32Value());
6855}
6856
6857
6858// Test the case when we stored callback into
6859// a stub, but it got invalidated later on due to override on
6860// global object which is between interceptor and callbacks' holders.
6861THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6862 v8::HandleScope scope;
6863 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6864 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6865 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6866 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6867
6868 LocalContext context;
6869 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6870 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6871
6872 v8::Handle<Value> value = CompileRun(
6873 "o.__proto__ = this;"
6874 "this.__proto__ = p;"
6875 "for (var i = 0; i < 10; i++) {"
6876 " if (o.y != 239) throw 'oops: ' + o.y;"
6877 // Now it should be ICed and keep a reference to y defined on p
6878 "}"
6879 "this.y = 42;"
6880 "var result = 0;"
6881 "for (var i = 0; i < 10; i++) {"
6882 " result += o.y;"
6883 "}"
6884 "result");
6885 CHECK_EQ(42 * 10, value->Int32Value());
6886}
6887
6888
6889static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6890 const AccessorInfo& info) {
6891 ApiTestFuzzer::Fuzz();
6892 CHECK(v8_str("x")->Equals(name));
6893 return v8::Integer::New(0);
6894}
6895
6896
6897THREADED_TEST(InterceptorReturningZero) {
6898 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6899 "o.x == undefined ? 1 : 0",
6900 0);
6901}
6902
6903
6904static v8::Handle<Value> InterceptorStoreICSetter(
6905 Local<String> key, Local<Value> value, const AccessorInfo&) {
6906 CHECK(v8_str("x")->Equals(key));
6907 CHECK_EQ(42, value->Int32Value());
6908 return value;
6909}
6910
6911
6912// This test should hit the store IC for the interceptor case.
6913THREADED_TEST(InterceptorStoreIC) {
6914 v8::HandleScope scope;
6915 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6916 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006917 InterceptorStoreICSetter,
6918 0, 0, 0, v8_str("data"));
Steve Blocka7e24c12009-10-30 11:49:00 +00006919 LocalContext context;
6920 context->Global()->Set(v8_str("o"), templ->NewInstance());
6921 v8::Handle<Value> value = CompileRun(
6922 "for (var i = 0; i < 1000; i++) {"
6923 " o.x = 42;"
6924 "}");
6925}
6926
6927
6928THREADED_TEST(InterceptorStoreICWithNoSetter) {
6929 v8::HandleScope scope;
6930 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6931 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6932 LocalContext context;
6933 context->Global()->Set(v8_str("o"), templ->NewInstance());
6934 v8::Handle<Value> value = CompileRun(
6935 "for (var i = 0; i < 1000; i++) {"
6936 " o.y = 239;"
6937 "}"
6938 "42 + o.y");
6939 CHECK_EQ(239 + 42, value->Int32Value());
6940}
6941
6942
6943
6944
6945v8::Handle<Value> call_ic_function;
6946v8::Handle<Value> call_ic_function2;
6947v8::Handle<Value> call_ic_function3;
6948
6949static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6950 const AccessorInfo& info) {
6951 ApiTestFuzzer::Fuzz();
6952 CHECK(v8_str("x")->Equals(name));
6953 return call_ic_function;
6954}
6955
6956
6957// This test should hit the call IC for the interceptor case.
6958THREADED_TEST(InterceptorCallIC) {
6959 v8::HandleScope scope;
6960 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6961 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6962 LocalContext context;
6963 context->Global()->Set(v8_str("o"), templ->NewInstance());
6964 call_ic_function =
6965 v8_compile("function f(x) { return x + 1; }; f")->Run();
6966 v8::Handle<Value> value = CompileRun(
6967 "var result = 0;"
6968 "for (var i = 0; i < 1000; i++) {"
6969 " result = o.x(41);"
6970 "}");
6971 CHECK_EQ(42, value->Int32Value());
6972}
6973
6974
6975// This test checks that if interceptor doesn't provide
6976// a value, we can fetch regular value.
6977THREADED_TEST(InterceptorCallICSeesOthers) {
6978 v8::HandleScope scope;
6979 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6980 templ->SetNamedPropertyHandler(NoBlockGetterX);
6981 LocalContext context;
6982 context->Global()->Set(v8_str("o"), templ->NewInstance());
6983 v8::Handle<Value> value = CompileRun(
6984 "o.x = function f(x) { return x + 1; };"
6985 "var result = 0;"
6986 "for (var i = 0; i < 7; i++) {"
6987 " result = o.x(41);"
6988 "}");
6989 CHECK_EQ(42, value->Int32Value());
6990}
6991
6992
6993static v8::Handle<Value> call_ic_function4;
6994static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6995 const AccessorInfo& info) {
6996 ApiTestFuzzer::Fuzz();
6997 CHECK(v8_str("x")->Equals(name));
6998 return call_ic_function4;
6999}
7000
7001
7002// This test checks that if interceptor provides a function,
7003// even if we cached shadowed variant, interceptor's function
7004// is invoked
7005THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
7006 v8::HandleScope scope;
7007 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7008 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
7009 LocalContext context;
7010 context->Global()->Set(v8_str("o"), templ->NewInstance());
7011 call_ic_function4 =
7012 v8_compile("function f(x) { return x - 1; }; f")->Run();
7013 v8::Handle<Value> value = CompileRun(
7014 "o.__proto__.x = function(x) { return x + 1; };"
7015 "var result = 0;"
7016 "for (var i = 0; i < 1000; i++) {"
7017 " result = o.x(42);"
7018 "}");
7019 CHECK_EQ(41, value->Int32Value());
7020}
7021
7022
7023// Test the case when we stored cacheable lookup into
7024// a stub, but it got invalidated later on
7025THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
7026 v8::HandleScope scope;
7027 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7028 templ->SetNamedPropertyHandler(NoBlockGetterX);
7029 LocalContext context;
7030 context->Global()->Set(v8_str("o"), templ->NewInstance());
7031 v8::Handle<Value> value = CompileRun(
7032 "proto1 = new Object();"
7033 "proto2 = new Object();"
7034 "o.__proto__ = proto1;"
7035 "proto1.__proto__ = proto2;"
7036 "proto2.y = function(x) { return x + 1; };"
7037 // Invoke it many times to compile a stub
7038 "for (var i = 0; i < 7; i++) {"
7039 " o.y(42);"
7040 "}"
7041 "proto1.y = function(x) { return x - 1; };"
7042 "var result = 0;"
7043 "for (var i = 0; i < 7; i++) {"
7044 " result += o.y(42);"
7045 "}");
7046 CHECK_EQ(41 * 7, value->Int32Value());
7047}
7048
7049
7050static v8::Handle<Value> call_ic_function5;
7051static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
7052 const AccessorInfo& info) {
7053 ApiTestFuzzer::Fuzz();
7054 if (v8_str("x")->Equals(name))
7055 return call_ic_function5;
7056 else
7057 return Local<Value>();
7058}
7059
7060
7061// This test checks that if interceptor doesn't provide a function,
7062// cached constant function is used
7063THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
7064 v8::HandleScope scope;
7065 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7066 templ->SetNamedPropertyHandler(NoBlockGetterX);
7067 LocalContext context;
7068 context->Global()->Set(v8_str("o"), templ->NewInstance());
7069 v8::Handle<Value> value = CompileRun(
7070 "function inc(x) { return x + 1; };"
7071 "inc(1);"
7072 "o.x = inc;"
7073 "var result = 0;"
7074 "for (var i = 0; i < 1000; i++) {"
7075 " result = o.x(42);"
7076 "}");
7077 CHECK_EQ(43, value->Int32Value());
7078}
7079
7080
7081// This test checks that if interceptor provides a function,
7082// even if we cached constant function, interceptor's function
7083// is invoked
7084THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
7085 v8::HandleScope scope;
7086 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7087 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
7088 LocalContext context;
7089 context->Global()->Set(v8_str("o"), templ->NewInstance());
7090 call_ic_function5 =
7091 v8_compile("function f(x) { return x - 1; }; f")->Run();
7092 v8::Handle<Value> value = CompileRun(
7093 "function inc(x) { return x + 1; };"
7094 "inc(1);"
7095 "o.x = inc;"
7096 "var result = 0;"
7097 "for (var i = 0; i < 1000; i++) {"
7098 " result = o.x(42);"
7099 "}");
7100 CHECK_EQ(41, value->Int32Value());
7101}
7102
7103
7104// Test the case when we stored constant function into
7105// a stub, but it got invalidated later on
7106THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
7107 v8::HandleScope scope;
7108 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7109 templ->SetNamedPropertyHandler(NoBlockGetterX);
7110 LocalContext context;
7111 context->Global()->Set(v8_str("o"), templ->NewInstance());
7112 v8::Handle<Value> value = CompileRun(
7113 "function inc(x) { return x + 1; };"
7114 "inc(1);"
7115 "proto1 = new Object();"
7116 "proto2 = new Object();"
7117 "o.__proto__ = proto1;"
7118 "proto1.__proto__ = proto2;"
7119 "proto2.y = inc;"
7120 // Invoke it many times to compile a stub
7121 "for (var i = 0; i < 7; i++) {"
7122 " o.y(42);"
7123 "}"
7124 "proto1.y = function(x) { return x - 1; };"
7125 "var result = 0;"
7126 "for (var i = 0; i < 7; i++) {"
7127 " result += o.y(42);"
7128 "}");
7129 CHECK_EQ(41 * 7, value->Int32Value());
7130}
7131
7132
7133// Test the case when we stored constant function into
7134// a stub, but it got invalidated later on due to override on
7135// global object which is between interceptor and constant function' holders.
7136THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
7137 v8::HandleScope scope;
7138 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7139 templ->SetNamedPropertyHandler(NoBlockGetterX);
7140 LocalContext context;
7141 context->Global()->Set(v8_str("o"), templ->NewInstance());
7142 v8::Handle<Value> value = CompileRun(
7143 "function inc(x) { return x + 1; };"
7144 "inc(1);"
7145 "o.__proto__ = this;"
7146 "this.__proto__.y = inc;"
7147 // Invoke it many times to compile a stub
7148 "for (var i = 0; i < 7; i++) {"
7149 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
7150 "}"
7151 "this.y = function(x) { return x - 1; };"
7152 "var result = 0;"
7153 "for (var i = 0; i < 7; i++) {"
7154 " result += o.y(42);"
7155 "}");
7156 CHECK_EQ(41 * 7, value->Int32Value());
7157}
7158
7159
Leon Clarke4515c472010-02-03 11:58:03 +00007160// Test the case when actual function to call sits on global object.
7161THREADED_TEST(InterceptorCallICCachedFromGlobal) {
7162 v8::HandleScope scope;
7163 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7164 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7165
7166 LocalContext context;
7167 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7168
7169 v8::Handle<Value> value = CompileRun(
7170 "try {"
7171 " o.__proto__ = this;"
7172 " for (var i = 0; i < 10; i++) {"
7173 " var v = o.parseFloat('239');"
7174 " if (v != 239) throw v;"
7175 // Now it should be ICed and keep a reference to parseFloat.
7176 " }"
7177 " var result = 0;"
7178 " for (var i = 0; i < 10; i++) {"
7179 " result += o.parseFloat('239');"
7180 " }"
7181 " result"
7182 "} catch(e) {"
7183 " e"
7184 "};");
7185 CHECK_EQ(239 * 10, value->Int32Value());
7186}
7187
Andrei Popescu402d9372010-02-26 13:31:12 +00007188static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
7189 const AccessorInfo& info) {
7190 ApiTestFuzzer::Fuzz();
7191 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
7192 ++(*call_count);
7193 if ((*call_count) % 20 == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01007194 i::Heap::CollectAllGarbage(true);
Andrei Popescu402d9372010-02-26 13:31:12 +00007195 }
7196 return v8::Handle<Value>();
7197}
7198
7199static v8::Handle<Value> FastApiCallback_TrivialSignature(
7200 const v8::Arguments& args) {
7201 ApiTestFuzzer::Fuzz();
7202 CHECK_EQ(args.This(), args.Holder());
7203 CHECK(args.Data()->Equals(v8_str("method_data")));
7204 return v8::Integer::New(args[0]->Int32Value() + 1);
7205}
7206
7207static v8::Handle<Value> FastApiCallback_SimpleSignature(
7208 const v8::Arguments& args) {
7209 ApiTestFuzzer::Fuzz();
7210 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
7211 CHECK(args.Data()->Equals(v8_str("method_data")));
7212 // Note, we're using HasRealNamedProperty instead of Has to avoid
7213 // invoking the interceptor again.
7214 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
7215 return v8::Integer::New(args[0]->Int32Value() + 1);
7216}
7217
7218// Helper to maximize the odds of object moving.
7219static void GenerateSomeGarbage() {
7220 CompileRun(
7221 "var garbage;"
7222 "for (var i = 0; i < 1000; i++) {"
7223 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
7224 "}"
7225 "garbage = undefined;");
7226}
7227
7228THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
7229 int interceptor_call_count = 0;
7230 v8::HandleScope scope;
7231 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7232 v8::Handle<v8::FunctionTemplate> method_templ =
7233 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7234 v8_str("method_data"),
7235 v8::Handle<v8::Signature>());
7236 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7237 proto_templ->Set(v8_str("method"), method_templ);
7238 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7239 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7240 NULL, NULL, NULL, NULL,
7241 v8::External::Wrap(&interceptor_call_count));
7242 LocalContext context;
7243 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7244 GenerateSomeGarbage();
7245 context->Global()->Set(v8_str("o"), fun->NewInstance());
7246 v8::Handle<Value> value = CompileRun(
7247 "var result = 0;"
7248 "for (var i = 0; i < 100; i++) {"
7249 " result = o.method(41);"
7250 "}");
7251 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7252 CHECK_EQ(100, interceptor_call_count);
7253}
7254
7255THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
7256 int interceptor_call_count = 0;
7257 v8::HandleScope scope;
7258 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7259 v8::Handle<v8::FunctionTemplate> method_templ =
7260 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7261 v8_str("method_data"),
7262 v8::Signature::New(fun_templ));
7263 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7264 proto_templ->Set(v8_str("method"), method_templ);
7265 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7266 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7267 NULL, NULL, NULL, NULL,
7268 v8::External::Wrap(&interceptor_call_count));
7269 LocalContext context;
7270 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7271 GenerateSomeGarbage();
7272 context->Global()->Set(v8_str("o"), fun->NewInstance());
7273 v8::Handle<Value> value = CompileRun(
7274 "o.foo = 17;"
7275 "var receiver = {};"
7276 "receiver.__proto__ = o;"
7277 "var result = 0;"
7278 "for (var i = 0; i < 100; i++) {"
7279 " result = receiver.method(41);"
7280 "}");
7281 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7282 CHECK_EQ(100, interceptor_call_count);
7283}
7284
7285THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
7286 int interceptor_call_count = 0;
7287 v8::HandleScope scope;
7288 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7289 v8::Handle<v8::FunctionTemplate> method_templ =
7290 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7291 v8_str("method_data"),
7292 v8::Signature::New(fun_templ));
7293 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7294 proto_templ->Set(v8_str("method"), method_templ);
7295 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7296 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7297 NULL, NULL, NULL, NULL,
7298 v8::External::Wrap(&interceptor_call_count));
7299 LocalContext context;
7300 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7301 GenerateSomeGarbage();
7302 context->Global()->Set(v8_str("o"), fun->NewInstance());
7303 v8::Handle<Value> value = CompileRun(
7304 "o.foo = 17;"
7305 "var receiver = {};"
7306 "receiver.__proto__ = o;"
7307 "var result = 0;"
7308 "var saved_result = 0;"
7309 "for (var i = 0; i < 100; i++) {"
7310 " result = receiver.method(41);"
7311 " if (i == 50) {"
7312 " saved_result = result;"
7313 " receiver = {method: function(x) { return x - 1 }};"
7314 " }"
7315 "}");
7316 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7317 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7318 CHECK_GE(interceptor_call_count, 50);
7319}
7320
7321THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
7322 int interceptor_call_count = 0;
7323 v8::HandleScope scope;
7324 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7325 v8::Handle<v8::FunctionTemplate> method_templ =
7326 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7327 v8_str("method_data"),
7328 v8::Signature::New(fun_templ));
7329 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7330 proto_templ->Set(v8_str("method"), method_templ);
7331 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7332 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7333 NULL, NULL, NULL, NULL,
7334 v8::External::Wrap(&interceptor_call_count));
7335 LocalContext context;
7336 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7337 GenerateSomeGarbage();
7338 context->Global()->Set(v8_str("o"), fun->NewInstance());
7339 v8::Handle<Value> value = CompileRun(
7340 "o.foo = 17;"
7341 "var receiver = {};"
7342 "receiver.__proto__ = o;"
7343 "var result = 0;"
7344 "var saved_result = 0;"
7345 "for (var i = 0; i < 100; i++) {"
7346 " result = receiver.method(41);"
7347 " if (i == 50) {"
7348 " saved_result = result;"
7349 " o.method = function(x) { return x - 1 };"
7350 " }"
7351 "}");
7352 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7353 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7354 CHECK_GE(interceptor_call_count, 50);
7355}
7356
Steve Block6ded16b2010-05-10 14:33:55 +01007357THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
7358 int interceptor_call_count = 0;
7359 v8::HandleScope scope;
7360 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7361 v8::Handle<v8::FunctionTemplate> method_templ =
7362 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7363 v8_str("method_data"),
7364 v8::Signature::New(fun_templ));
7365 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7366 proto_templ->Set(v8_str("method"), method_templ);
7367 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7368 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7369 NULL, NULL, NULL, NULL,
7370 v8::External::Wrap(&interceptor_call_count));
7371 LocalContext context;
7372 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7373 GenerateSomeGarbage();
7374 context->Global()->Set(v8_str("o"), fun->NewInstance());
7375 v8::TryCatch try_catch;
7376 v8::Handle<Value> value = CompileRun(
7377 "o.foo = 17;"
7378 "var receiver = {};"
7379 "receiver.__proto__ = o;"
7380 "var result = 0;"
7381 "var saved_result = 0;"
7382 "for (var i = 0; i < 100; i++) {"
7383 " result = receiver.method(41);"
7384 " if (i == 50) {"
7385 " saved_result = result;"
7386 " receiver = 333;"
7387 " }"
7388 "}");
7389 CHECK(try_catch.HasCaught());
7390 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7391 try_catch.Exception()->ToString());
7392 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7393 CHECK_GE(interceptor_call_count, 50);
7394}
7395
Andrei Popescu402d9372010-02-26 13:31:12 +00007396THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
7397 int interceptor_call_count = 0;
7398 v8::HandleScope scope;
7399 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7400 v8::Handle<v8::FunctionTemplate> method_templ =
7401 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7402 v8_str("method_data"),
7403 v8::Signature::New(fun_templ));
7404 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7405 proto_templ->Set(v8_str("method"), method_templ);
7406 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7407 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
7408 NULL, NULL, NULL, NULL,
7409 v8::External::Wrap(&interceptor_call_count));
7410 LocalContext context;
7411 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7412 GenerateSomeGarbage();
7413 context->Global()->Set(v8_str("o"), fun->NewInstance());
7414 v8::TryCatch try_catch;
7415 v8::Handle<Value> value = CompileRun(
7416 "o.foo = 17;"
7417 "var receiver = {};"
7418 "receiver.__proto__ = o;"
7419 "var result = 0;"
7420 "var saved_result = 0;"
7421 "for (var i = 0; i < 100; i++) {"
7422 " result = receiver.method(41);"
7423 " if (i == 50) {"
7424 " saved_result = result;"
7425 " receiver = {method: receiver.method};"
7426 " }"
7427 "}");
7428 CHECK(try_catch.HasCaught());
7429 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
7430 try_catch.Exception()->ToString());
7431 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7432 CHECK_GE(interceptor_call_count, 50);
7433}
7434
7435THREADED_TEST(CallICFastApi_TrivialSignature) {
7436 v8::HandleScope scope;
7437 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7438 v8::Handle<v8::FunctionTemplate> method_templ =
7439 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
7440 v8_str("method_data"),
7441 v8::Handle<v8::Signature>());
7442 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7443 proto_templ->Set(v8_str("method"), method_templ);
7444 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7445 LocalContext context;
7446 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7447 GenerateSomeGarbage();
7448 context->Global()->Set(v8_str("o"), fun->NewInstance());
7449 v8::Handle<Value> value = CompileRun(
7450 "var result = 0;"
7451 "for (var i = 0; i < 100; i++) {"
7452 " result = o.method(41);"
7453 "}");
7454
7455 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7456}
7457
7458THREADED_TEST(CallICFastApi_SimpleSignature) {
7459 v8::HandleScope scope;
7460 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7461 v8::Handle<v8::FunctionTemplate> method_templ =
7462 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7463 v8_str("method_data"),
7464 v8::Signature::New(fun_templ));
7465 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7466 proto_templ->Set(v8_str("method"), method_templ);
7467 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7468 LocalContext context;
7469 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7470 GenerateSomeGarbage();
7471 context->Global()->Set(v8_str("o"), fun->NewInstance());
7472 v8::Handle<Value> value = CompileRun(
7473 "o.foo = 17;"
7474 "var receiver = {};"
7475 "receiver.__proto__ = o;"
7476 "var result = 0;"
7477 "for (var i = 0; i < 100; i++) {"
7478 " result = receiver.method(41);"
7479 "}");
7480
7481 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
7482}
7483
Steve Block6ded16b2010-05-10 14:33:55 +01007484THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007485 v8::HandleScope scope;
7486 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7487 v8::Handle<v8::FunctionTemplate> method_templ =
7488 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7489 v8_str("method_data"),
7490 v8::Signature::New(fun_templ));
7491 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7492 proto_templ->Set(v8_str("method"), method_templ);
7493 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7494 LocalContext context;
7495 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7496 GenerateSomeGarbage();
7497 context->Global()->Set(v8_str("o"), fun->NewInstance());
7498 v8::Handle<Value> value = CompileRun(
7499 "o.foo = 17;"
7500 "var receiver = {};"
7501 "receiver.__proto__ = o;"
7502 "var result = 0;"
7503 "var saved_result = 0;"
7504 "for (var i = 0; i < 100; i++) {"
7505 " result = receiver.method(41);"
7506 " if (i == 50) {"
7507 " saved_result = result;"
7508 " receiver = {method: function(x) { return x - 1 }};"
7509 " }"
7510 "}");
7511 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
7512 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7513}
7514
Steve Block6ded16b2010-05-10 14:33:55 +01007515THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
7516 v8::HandleScope scope;
7517 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
7518 v8::Handle<v8::FunctionTemplate> method_templ =
7519 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
7520 v8_str("method_data"),
7521 v8::Signature::New(fun_templ));
7522 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
7523 proto_templ->Set(v8_str("method"), method_templ);
7524 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
7525 LocalContext context;
7526 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
7527 GenerateSomeGarbage();
7528 context->Global()->Set(v8_str("o"), fun->NewInstance());
7529 v8::TryCatch try_catch;
7530 v8::Handle<Value> value = CompileRun(
7531 "o.foo = 17;"
7532 "var receiver = {};"
7533 "receiver.__proto__ = o;"
7534 "var result = 0;"
7535 "var saved_result = 0;"
7536 "for (var i = 0; i < 100; i++) {"
7537 " result = receiver.method(41);"
7538 " if (i == 50) {"
7539 " saved_result = result;"
7540 " receiver = 333;"
7541 " }"
7542 "}");
7543 CHECK(try_catch.HasCaught());
7544 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
7545 try_catch.Exception()->ToString());
7546 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7547}
7548
Leon Clarke4515c472010-02-03 11:58:03 +00007549
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007550v8::Handle<Value> keyed_call_ic_function;
7551
7552static v8::Handle<Value> InterceptorKeyedCallICGetter(
7553 Local<String> name, const AccessorInfo& info) {
7554 ApiTestFuzzer::Fuzz();
7555 if (v8_str("x")->Equals(name)) {
7556 return keyed_call_ic_function;
7557 }
7558 return v8::Handle<Value>();
7559}
7560
7561
7562// Test the case when we stored cacheable lookup into
7563// a stub, but the function name changed (to another cacheable function).
7564THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
7565 v8::HandleScope scope;
7566 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7567 templ->SetNamedPropertyHandler(NoBlockGetterX);
7568 LocalContext context;
7569 context->Global()->Set(v8_str("o"), templ->NewInstance());
7570 v8::Handle<Value> value = CompileRun(
7571 "proto = new Object();"
7572 "proto.y = function(x) { return x + 1; };"
7573 "proto.z = function(x) { return x - 1; };"
7574 "o.__proto__ = proto;"
7575 "var result = 0;"
7576 "var method = 'y';"
7577 "for (var i = 0; i < 10; i++) {"
7578 " if (i == 5) { method = 'z'; };"
7579 " result += o[method](41);"
7580 "}");
7581 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7582}
7583
7584
7585// Test the case when we stored cacheable lookup into
7586// a stub, but the function name changed (and the new function is present
7587// both before and after the interceptor in the prototype chain).
7588THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
7589 v8::HandleScope scope;
7590 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7591 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
7592 LocalContext context;
7593 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
7594 keyed_call_ic_function =
7595 v8_compile("function f(x) { return x - 1; }; f")->Run();
7596 v8::Handle<Value> value = CompileRun(
7597 "o = new Object();"
7598 "proto2 = new Object();"
7599 "o.y = function(x) { return x + 1; };"
7600 "proto2.y = function(x) { return x + 2; };"
7601 "o.__proto__ = proto1;"
7602 "proto1.__proto__ = proto2;"
7603 "var result = 0;"
7604 "var method = 'x';"
7605 "for (var i = 0; i < 10; i++) {"
7606 " if (i == 5) { method = 'y'; };"
7607 " result += o[method](41);"
7608 "}");
7609 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7610}
7611
7612
7613// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
7614// on the global object.
7615THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
7616 v8::HandleScope scope;
7617 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7618 templ->SetNamedPropertyHandler(NoBlockGetterX);
7619 LocalContext context;
7620 context->Global()->Set(v8_str("o"), templ->NewInstance());
7621 v8::Handle<Value> value = CompileRun(
7622 "function inc(x) { return x + 1; };"
7623 "inc(1);"
7624 "function dec(x) { return x - 1; };"
7625 "dec(1);"
7626 "o.__proto__ = this;"
7627 "this.__proto__.x = inc;"
7628 "this.__proto__.y = dec;"
7629 "var result = 0;"
7630 "var method = 'x';"
7631 "for (var i = 0; i < 10; i++) {"
7632 " if (i == 5) { method = 'y'; };"
7633 " result += o[method](41);"
7634 "}");
7635 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7636}
7637
7638
7639// Test the case when actual function to call sits on global object.
7640THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
7641 v8::HandleScope scope;
7642 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7643 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7644 LocalContext context;
7645 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7646
7647 v8::Handle<Value> value = CompileRun(
7648 "function len(x) { return x.length; };"
7649 "o.__proto__ = this;"
7650 "var m = 'parseFloat';"
7651 "var result = 0;"
7652 "for (var i = 0; i < 10; i++) {"
7653 " if (i == 5) {"
7654 " m = 'len';"
7655 " saved_result = result;"
7656 " };"
7657 " result = o[m]('239');"
7658 "}");
7659 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
7660 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
7661}
7662
7663// Test the map transition before the interceptor.
7664THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
7665 v8::HandleScope scope;
7666 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7667 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7668 LocalContext context;
7669 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
7670
7671 v8::Handle<Value> value = CompileRun(
7672 "var o = new Object();"
7673 "o.__proto__ = proto;"
7674 "o.method = function(x) { return x + 1; };"
7675 "var m = 'method';"
7676 "var result = 0;"
7677 "for (var i = 0; i < 10; i++) {"
7678 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
7679 " result += o[m](41);"
7680 "}");
7681 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7682}
7683
7684
7685// Test the map transition after the interceptor.
7686THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
7687 v8::HandleScope scope;
7688 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
7689 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
7690 LocalContext context;
7691 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
7692
7693 v8::Handle<Value> value = CompileRun(
7694 "var proto = new Object();"
7695 "o.__proto__ = proto;"
7696 "proto.method = function(x) { return x + 1; };"
7697 "var m = 'method';"
7698 "var result = 0;"
7699 "for (var i = 0; i < 10; i++) {"
7700 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
7701 " result += o[m](41);"
7702 "}");
7703 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
7704}
7705
7706
Steve Blocka7e24c12009-10-30 11:49:00 +00007707static int interceptor_call_count = 0;
7708
7709static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
7710 const AccessorInfo& info) {
7711 ApiTestFuzzer::Fuzz();
7712 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
7713 return call_ic_function2;
7714 }
7715 return v8::Handle<Value>();
7716}
7717
7718
7719// This test should hit load and call ICs for the interceptor case.
7720// Once in a while, the interceptor will reply that a property was not
7721// found in which case we should get a reference error.
7722THREADED_TEST(InterceptorICReferenceErrors) {
7723 v8::HandleScope scope;
7724 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7725 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
7726 LocalContext context(0, templ, v8::Handle<Value>());
7727 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
7728 v8::Handle<Value> value = CompileRun(
7729 "function f() {"
7730 " for (var i = 0; i < 1000; i++) {"
7731 " try { x; } catch(e) { return true; }"
7732 " }"
7733 " return false;"
7734 "};"
7735 "f();");
7736 CHECK_EQ(true, value->BooleanValue());
7737 interceptor_call_count = 0;
7738 value = CompileRun(
7739 "function g() {"
7740 " for (var i = 0; i < 1000; i++) {"
7741 " try { x(42); } catch(e) { return true; }"
7742 " }"
7743 " return false;"
7744 "};"
7745 "g();");
7746 CHECK_EQ(true, value->BooleanValue());
7747}
7748
7749
7750static int interceptor_ic_exception_get_count = 0;
7751
7752static v8::Handle<Value> InterceptorICExceptionGetter(
7753 Local<String> name,
7754 const AccessorInfo& info) {
7755 ApiTestFuzzer::Fuzz();
7756 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
7757 return call_ic_function3;
7758 }
7759 if (interceptor_ic_exception_get_count == 20) {
7760 return v8::ThrowException(v8_num(42));
7761 }
7762 // Do not handle get for properties other than x.
7763 return v8::Handle<Value>();
7764}
7765
7766// Test interceptor load/call IC where the interceptor throws an
7767// exception once in a while.
7768THREADED_TEST(InterceptorICGetterExceptions) {
7769 interceptor_ic_exception_get_count = 0;
7770 v8::HandleScope scope;
7771 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7772 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
7773 LocalContext context(0, templ, v8::Handle<Value>());
7774 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
7775 v8::Handle<Value> value = CompileRun(
7776 "function f() {"
7777 " for (var i = 0; i < 100; i++) {"
7778 " try { x; } catch(e) { return true; }"
7779 " }"
7780 " return false;"
7781 "};"
7782 "f();");
7783 CHECK_EQ(true, value->BooleanValue());
7784 interceptor_ic_exception_get_count = 0;
7785 value = CompileRun(
7786 "function f() {"
7787 " for (var i = 0; i < 100; i++) {"
7788 " try { x(42); } catch(e) { return true; }"
7789 " }"
7790 " return false;"
7791 "};"
7792 "f();");
7793 CHECK_EQ(true, value->BooleanValue());
7794}
7795
7796
7797static int interceptor_ic_exception_set_count = 0;
7798
7799static v8::Handle<Value> InterceptorICExceptionSetter(
7800 Local<String> key, Local<Value> value, const AccessorInfo&) {
7801 ApiTestFuzzer::Fuzz();
7802 if (++interceptor_ic_exception_set_count > 20) {
7803 return v8::ThrowException(v8_num(42));
7804 }
7805 // Do not actually handle setting.
7806 return v8::Handle<Value>();
7807}
7808
7809// Test interceptor store IC where the interceptor throws an exception
7810// once in a while.
7811THREADED_TEST(InterceptorICSetterExceptions) {
7812 interceptor_ic_exception_set_count = 0;
7813 v8::HandleScope scope;
7814 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7815 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
7816 LocalContext context(0, templ, v8::Handle<Value>());
7817 v8::Handle<Value> value = CompileRun(
7818 "function f() {"
7819 " for (var i = 0; i < 100; i++) {"
7820 " try { x = 42; } catch(e) { return true; }"
7821 " }"
7822 " return false;"
7823 "};"
7824 "f();");
7825 CHECK_EQ(true, value->BooleanValue());
7826}
7827
7828
7829// Test that we ignore null interceptors.
7830THREADED_TEST(NullNamedInterceptor) {
7831 v8::HandleScope scope;
7832 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7833 templ->SetNamedPropertyHandler(0);
7834 LocalContext context;
7835 templ->Set("x", v8_num(42));
7836 v8::Handle<v8::Object> obj = templ->NewInstance();
7837 context->Global()->Set(v8_str("obj"), obj);
7838 v8::Handle<Value> value = CompileRun("obj.x");
7839 CHECK(value->IsInt32());
7840 CHECK_EQ(42, value->Int32Value());
7841}
7842
7843
7844// Test that we ignore null interceptors.
7845THREADED_TEST(NullIndexedInterceptor) {
7846 v8::HandleScope scope;
7847 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7848 templ->SetIndexedPropertyHandler(0);
7849 LocalContext context;
7850 templ->Set("42", v8_num(42));
7851 v8::Handle<v8::Object> obj = templ->NewInstance();
7852 context->Global()->Set(v8_str("obj"), obj);
7853 v8::Handle<Value> value = CompileRun("obj[42]");
7854 CHECK(value->IsInt32());
7855 CHECK_EQ(42, value->Int32Value());
7856}
7857
7858
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007859THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
7860 v8::HandleScope scope;
7861 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7862 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
7863 LocalContext env;
7864 env->Global()->Set(v8_str("obj"),
7865 templ->GetFunction()->NewInstance());
7866 ExpectTrue("obj.x === 42");
7867 ExpectTrue("!obj.propertyIsEnumerable('x')");
7868}
7869
7870
Steve Blocka7e24c12009-10-30 11:49:00 +00007871static v8::Handle<Value> ParentGetter(Local<String> name,
7872 const AccessorInfo& info) {
7873 ApiTestFuzzer::Fuzz();
7874 return v8_num(1);
7875}
7876
7877
7878static v8::Handle<Value> ChildGetter(Local<String> name,
7879 const AccessorInfo& info) {
7880 ApiTestFuzzer::Fuzz();
7881 return v8_num(42);
7882}
7883
7884
7885THREADED_TEST(Overriding) {
7886 v8::HandleScope scope;
7887 LocalContext context;
7888
7889 // Parent template.
7890 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
7891 Local<ObjectTemplate> parent_instance_templ =
7892 parent_templ->InstanceTemplate();
7893 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
7894
7895 // Template that inherits from the parent template.
7896 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
7897 Local<ObjectTemplate> child_instance_templ =
7898 child_templ->InstanceTemplate();
7899 child_templ->Inherit(parent_templ);
7900 // Override 'f'. The child version of 'f' should get called for child
7901 // instances.
7902 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
7903 // Add 'g' twice. The 'g' added last should get called for instances.
7904 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
7905 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
7906
7907 // Add 'h' as an accessor to the proto template with ReadOnly attributes
7908 // so 'h' can be shadowed on the instance object.
7909 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
7910 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
7911 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7912
7913 // Add 'i' as an accessor to the instance template with ReadOnly attributes
7914 // but the attribute does not have effect because it is duplicated with
7915 // NULL setter.
7916 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
7917 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
7918
7919
7920
7921 // Instantiate the child template.
7922 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
7923
7924 // Check that the child function overrides the parent one.
7925 context->Global()->Set(v8_str("o"), instance);
7926 Local<Value> value = v8_compile("o.f")->Run();
7927 // Check that the 'g' that was added last is hit.
7928 CHECK_EQ(42, value->Int32Value());
7929 value = v8_compile("o.g")->Run();
7930 CHECK_EQ(42, value->Int32Value());
7931
7932 // Check 'h' can be shadowed.
7933 value = v8_compile("o.h = 3; o.h")->Run();
7934 CHECK_EQ(3, value->Int32Value());
7935
7936 // Check 'i' is cannot be shadowed or changed.
7937 value = v8_compile("o.i = 3; o.i")->Run();
7938 CHECK_EQ(42, value->Int32Value());
7939}
7940
7941
7942static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
7943 ApiTestFuzzer::Fuzz();
7944 if (args.IsConstructCall()) {
7945 return v8::Boolean::New(true);
7946 }
7947 return v8::Boolean::New(false);
7948}
7949
7950
7951THREADED_TEST(IsConstructCall) {
7952 v8::HandleScope scope;
7953
7954 // Function template with call handler.
7955 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7956 templ->SetCallHandler(IsConstructHandler);
7957
7958 LocalContext context;
7959
7960 context->Global()->Set(v8_str("f"), templ->GetFunction());
7961 Local<Value> value = v8_compile("f()")->Run();
7962 CHECK(!value->BooleanValue());
7963 value = v8_compile("new f()")->Run();
7964 CHECK(value->BooleanValue());
7965}
7966
7967
7968THREADED_TEST(ObjectProtoToString) {
7969 v8::HandleScope scope;
7970 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7971 templ->SetClassName(v8_str("MyClass"));
7972
7973 LocalContext context;
7974
7975 Local<String> customized_tostring = v8_str("customized toString");
7976
7977 // Replace Object.prototype.toString
7978 v8_compile("Object.prototype.toString = function() {"
7979 " return 'customized toString';"
7980 "}")->Run();
7981
7982 // Normal ToString call should call replaced Object.prototype.toString
7983 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
7984 Local<String> value = instance->ToString();
7985 CHECK(value->IsString() && value->Equals(customized_tostring));
7986
7987 // ObjectProtoToString should not call replace toString function.
7988 value = instance->ObjectProtoToString();
7989 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
7990
7991 // Check global
7992 value = context->Global()->ObjectProtoToString();
7993 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
7994
7995 // Check ordinary object
7996 Local<Value> object = v8_compile("new Object()")->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01007997 value = object.As<v8::Object>()->ObjectProtoToString();
Steve Blocka7e24c12009-10-30 11:49:00 +00007998 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
7999}
8000
8001
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008002THREADED_TEST(ObjectGetConstructorName) {
8003 v8::HandleScope scope;
8004 LocalContext context;
8005 v8_compile("function Parent() {};"
8006 "function Child() {};"
8007 "Child.prototype = new Parent();"
8008 "var outer = { inner: function() { } };"
8009 "var p = new Parent();"
8010 "var c = new Child();"
8011 "var x = new outer.inner();")->Run();
8012
8013 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
8014 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
8015 v8_str("Parent")));
8016
8017 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
8018 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
8019 v8_str("Child")));
8020
8021 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
8022 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
8023 v8_str("outer.inner")));
8024}
8025
8026
Steve Blocka7e24c12009-10-30 11:49:00 +00008027bool ApiTestFuzzer::fuzzing_ = false;
Steve Block8defd9f2010-07-08 12:39:36 +01008028i::Semaphore* ApiTestFuzzer::all_tests_done_=
8029 i::OS::CreateSemaphore(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008030int ApiTestFuzzer::active_tests_;
8031int ApiTestFuzzer::tests_being_run_;
8032int ApiTestFuzzer::current_;
8033
8034
8035// We are in a callback and want to switch to another thread (if we
8036// are currently running the thread fuzzing test).
8037void ApiTestFuzzer::Fuzz() {
8038 if (!fuzzing_) return;
8039 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
8040 test->ContextSwitch();
8041}
8042
8043
8044// Let the next thread go. Since it is also waiting on the V8 lock it may
8045// not start immediately.
8046bool ApiTestFuzzer::NextThread() {
8047 int test_position = GetNextTestNumber();
Steve Blockd0582a62009-12-15 09:54:21 +00008048 const char* test_name = RegisterThreadedTest::nth(current_)->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00008049 if (test_position == current_) {
Steve Blockd0582a62009-12-15 09:54:21 +00008050 if (kLogThreading)
8051 printf("Stay with %s\n", test_name);
Steve Blocka7e24c12009-10-30 11:49:00 +00008052 return false;
8053 }
Steve Blockd0582a62009-12-15 09:54:21 +00008054 if (kLogThreading) {
8055 printf("Switch from %s to %s\n",
8056 test_name,
8057 RegisterThreadedTest::nth(test_position)->name());
8058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008059 current_ = test_position;
8060 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
8061 return true;
8062}
8063
8064
8065void ApiTestFuzzer::Run() {
8066 // When it is our turn...
8067 gate_->Wait();
8068 {
8069 // ... get the V8 lock and start running the test.
8070 v8::Locker locker;
8071 CallTest();
8072 }
8073 // This test finished.
8074 active_ = false;
8075 active_tests_--;
8076 // If it was the last then signal that fact.
8077 if (active_tests_ == 0) {
8078 all_tests_done_->Signal();
8079 } else {
8080 // Otherwise select a new test and start that.
8081 NextThread();
8082 }
8083}
8084
8085
8086static unsigned linear_congruential_generator;
8087
8088
8089void ApiTestFuzzer::Setup(PartOfTest part) {
8090 linear_congruential_generator = i::FLAG_testing_prng_seed;
8091 fuzzing_ = true;
8092 int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
8093 int end = (part == FIRST_PART)
8094 ? (RegisterThreadedTest::count() >> 1)
8095 : RegisterThreadedTest::count();
8096 active_tests_ = tests_being_run_ = end - start;
8097 for (int i = 0; i < tests_being_run_; i++) {
8098 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
8099 }
8100 for (int i = 0; i < active_tests_; i++) {
8101 RegisterThreadedTest::nth(i)->fuzzer_->Start();
8102 }
8103}
8104
8105
8106static void CallTestNumber(int test_number) {
8107 (RegisterThreadedTest::nth(test_number)->callback())();
8108}
8109
8110
8111void ApiTestFuzzer::RunAllTests() {
8112 // Set off the first test.
8113 current_ = -1;
8114 NextThread();
8115 // Wait till they are all done.
8116 all_tests_done_->Wait();
8117}
8118
8119
8120int ApiTestFuzzer::GetNextTestNumber() {
8121 int next_test;
8122 do {
8123 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
8124 linear_congruential_generator *= 1664525u;
8125 linear_congruential_generator += 1013904223u;
8126 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
8127 return next_test;
8128}
8129
8130
8131void ApiTestFuzzer::ContextSwitch() {
8132 // If the new thread is the same as the current thread there is nothing to do.
8133 if (NextThread()) {
8134 // Now it can start.
8135 v8::Unlocker unlocker;
8136 // Wait till someone starts us again.
8137 gate_->Wait();
8138 // And we're off.
8139 }
8140}
8141
8142
8143void ApiTestFuzzer::TearDown() {
8144 fuzzing_ = false;
8145 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
8146 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
8147 if (fuzzer != NULL) fuzzer->Join();
8148 }
8149}
8150
8151
8152// Lets not be needlessly self-referential.
8153TEST(Threading) {
8154 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
8155 ApiTestFuzzer::RunAllTests();
8156 ApiTestFuzzer::TearDown();
8157}
8158
8159TEST(Threading2) {
8160 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
8161 ApiTestFuzzer::RunAllTests();
8162 ApiTestFuzzer::TearDown();
8163}
8164
8165
8166void ApiTestFuzzer::CallTest() {
Steve Blockd0582a62009-12-15 09:54:21 +00008167 if (kLogThreading)
8168 printf("Start test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008169 CallTestNumber(test_number_);
Steve Blockd0582a62009-12-15 09:54:21 +00008170 if (kLogThreading)
8171 printf("End test %d\n", test_number_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008172}
8173
8174
8175static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
8176 CHECK(v8::Locker::IsLocked());
8177 ApiTestFuzzer::Fuzz();
8178 v8::Unlocker unlocker;
8179 const char* code = "throw 7;";
8180 {
8181 v8::Locker nested_locker;
8182 v8::HandleScope scope;
8183 v8::Handle<Value> exception;
8184 { v8::TryCatch try_catch;
8185 v8::Handle<Value> value = CompileRun(code);
8186 CHECK(value.IsEmpty());
8187 CHECK(try_catch.HasCaught());
8188 // Make sure to wrap the exception in a new handle because
8189 // the handle returned from the TryCatch is destroyed
8190 // when the TryCatch is destroyed.
8191 exception = Local<Value>::New(try_catch.Exception());
8192 }
8193 return v8::ThrowException(exception);
8194 }
8195}
8196
8197
8198static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
8199 CHECK(v8::Locker::IsLocked());
8200 ApiTestFuzzer::Fuzz();
8201 v8::Unlocker unlocker;
8202 const char* code = "throw 7;";
8203 {
8204 v8::Locker nested_locker;
8205 v8::HandleScope scope;
8206 v8::Handle<Value> value = CompileRun(code);
8207 CHECK(value.IsEmpty());
8208 return v8_str("foo");
8209 }
8210}
8211
8212
8213// These are locking tests that don't need to be run again
8214// as part of the locking aggregation tests.
8215TEST(NestedLockers) {
8216 v8::Locker locker;
8217 CHECK(v8::Locker::IsLocked());
8218 v8::HandleScope scope;
8219 LocalContext env;
8220 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
8221 Local<Function> fun = fun_templ->GetFunction();
8222 env->Global()->Set(v8_str("throw_in_js"), fun);
8223 Local<Script> script = v8_compile("(function () {"
8224 " try {"
8225 " throw_in_js();"
8226 " return 42;"
8227 " } catch (e) {"
8228 " return e * 13;"
8229 " }"
8230 "})();");
8231 CHECK_EQ(91, script->Run()->Int32Value());
8232}
8233
8234
8235// These are locking tests that don't need to be run again
8236// as part of the locking aggregation tests.
8237TEST(NestedLockersNoTryCatch) {
8238 v8::Locker locker;
8239 v8::HandleScope scope;
8240 LocalContext env;
8241 Local<v8::FunctionTemplate> fun_templ =
8242 v8::FunctionTemplate::New(ThrowInJSNoCatch);
8243 Local<Function> fun = fun_templ->GetFunction();
8244 env->Global()->Set(v8_str("throw_in_js"), fun);
8245 Local<Script> script = v8_compile("(function () {"
8246 " try {"
8247 " throw_in_js();"
8248 " return 42;"
8249 " } catch (e) {"
8250 " return e * 13;"
8251 " }"
8252 "})();");
8253 CHECK_EQ(91, script->Run()->Int32Value());
8254}
8255
8256
8257THREADED_TEST(RecursiveLocking) {
8258 v8::Locker locker;
8259 {
8260 v8::Locker locker2;
8261 CHECK(v8::Locker::IsLocked());
8262 }
8263}
8264
8265
8266static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
8267 ApiTestFuzzer::Fuzz();
8268 v8::Unlocker unlocker;
8269 return v8::Undefined();
8270}
8271
8272
8273THREADED_TEST(LockUnlockLock) {
8274 {
8275 v8::Locker locker;
8276 v8::HandleScope scope;
8277 LocalContext env;
8278 Local<v8::FunctionTemplate> fun_templ =
8279 v8::FunctionTemplate::New(UnlockForAMoment);
8280 Local<Function> fun = fun_templ->GetFunction();
8281 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8282 Local<Script> script = v8_compile("(function () {"
8283 " unlock_for_a_moment();"
8284 " return 42;"
8285 "})();");
8286 CHECK_EQ(42, script->Run()->Int32Value());
8287 }
8288 {
8289 v8::Locker locker;
8290 v8::HandleScope scope;
8291 LocalContext env;
8292 Local<v8::FunctionTemplate> fun_templ =
8293 v8::FunctionTemplate::New(UnlockForAMoment);
8294 Local<Function> fun = fun_templ->GetFunction();
8295 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
8296 Local<Script> script = v8_compile("(function () {"
8297 " unlock_for_a_moment();"
8298 " return 42;"
8299 "})();");
8300 CHECK_EQ(42, script->Run()->Int32Value());
8301 }
8302}
8303
8304
Leon Clarked91b9f72010-01-27 17:25:45 +00008305static int GetGlobalObjectsCount() {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00008306 int count = 0;
Steve Block8defd9f2010-07-08 12:39:36 +01008307 i::HeapIterator it;
Leon Clarked91b9f72010-01-27 17:25:45 +00008308 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
8309 if (object->IsJSGlobalObject()) count++;
8310 return count;
8311}
8312
8313
Ben Murdochf87a2032010-10-22 12:50:53 +01008314static void CheckSurvivingGlobalObjectsCount(int expected) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008315 // We need to collect all garbage twice to be sure that everything
8316 // has been collected. This is because inline caches are cleared in
8317 // the first garbage collection but some of the maps have already
8318 // been marked at that point. Therefore some of the maps are not
8319 // collected until the second garbage collection.
Steve Block8defd9f2010-07-08 12:39:36 +01008320 i::Heap::CollectAllGarbage(false);
8321 i::Heap::CollectAllGarbage(false);
Leon Clarked91b9f72010-01-27 17:25:45 +00008322 int count = GetGlobalObjectsCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00008323#ifdef DEBUG
Ben Murdochf87a2032010-10-22 12:50:53 +01008324 if (count != expected) i::Heap::TracePathToGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +00008325#endif
Ben Murdochf87a2032010-10-22 12:50:53 +01008326 CHECK_EQ(expected, count);
Steve Blocka7e24c12009-10-30 11:49:00 +00008327}
8328
8329
8330TEST(DontLeakGlobalObjects) {
8331 // Regression test for issues 1139850 and 1174891.
8332
8333 v8::V8::Initialize();
8334
Steve Blocka7e24c12009-10-30 11:49:00 +00008335 for (int i = 0; i < 5; i++) {
8336 { v8::HandleScope scope;
8337 LocalContext context;
8338 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008339 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008340
8341 { v8::HandleScope scope;
8342 LocalContext context;
8343 v8_compile("Date")->Run();
8344 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008345 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008346
8347 { v8::HandleScope scope;
8348 LocalContext context;
8349 v8_compile("/aaa/")->Run();
8350 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008351 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008352
8353 { v8::HandleScope scope;
8354 const char* extension_list[] = { "v8/gc" };
8355 v8::ExtensionConfiguration extensions(1, extension_list);
8356 LocalContext context(&extensions);
8357 v8_compile("gc();")->Run();
8358 }
Ben Murdochf87a2032010-10-22 12:50:53 +01008359 CheckSurvivingGlobalObjectsCount(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008360 }
8361}
8362
8363
8364v8::Persistent<v8::Object> some_object;
8365v8::Persistent<v8::Object> bad_handle;
8366
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008367void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008368 v8::HandleScope scope;
8369 bad_handle = v8::Persistent<v8::Object>::New(some_object);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008370 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00008371}
8372
8373
8374THREADED_TEST(NewPersistentHandleFromWeakCallback) {
8375 LocalContext context;
8376
8377 v8::Persistent<v8::Object> handle1, handle2;
8378 {
8379 v8::HandleScope scope;
8380 some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
8381 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8382 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8383 }
8384 // Note: order is implementation dependent alas: currently
8385 // global handle nodes are processed by PostGarbageCollectionProcessing
8386 // in reverse allocation order, so if second allocated handle is deleted,
8387 // weak callback of the first handle would be able to 'reallocate' it.
8388 handle1.MakeWeak(NULL, NewPersistentHandleCallback);
8389 handle2.Dispose();
8390 i::Heap::CollectAllGarbage(false);
8391}
8392
8393
8394v8::Persistent<v8::Object> to_be_disposed;
8395
8396void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
8397 to_be_disposed.Dispose();
8398 i::Heap::CollectAllGarbage(false);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008399 handle.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00008400}
8401
8402
8403THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
8404 LocalContext context;
8405
8406 v8::Persistent<v8::Object> handle1, handle2;
8407 {
8408 v8::HandleScope scope;
8409 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8410 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8411 }
8412 handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
8413 to_be_disposed = handle2;
8414 i::Heap::CollectAllGarbage(false);
8415}
8416
Steve Blockd0582a62009-12-15 09:54:21 +00008417void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
8418 handle.Dispose();
8419}
8420
8421void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
8422 v8::HandleScope scope;
8423 v8::Persistent<v8::Object>::New(v8::Object::New());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008424 handle.Dispose();
Steve Blockd0582a62009-12-15 09:54:21 +00008425}
8426
8427
8428THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
8429 LocalContext context;
8430
8431 v8::Persistent<v8::Object> handle1, handle2, handle3;
8432 {
8433 v8::HandleScope scope;
8434 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
8435 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
8436 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
8437 }
8438 handle2.MakeWeak(NULL, DisposingCallback);
8439 handle3.MakeWeak(NULL, HandleCreatingCallback);
8440 i::Heap::CollectAllGarbage(false);
8441}
8442
Steve Blocka7e24c12009-10-30 11:49:00 +00008443
8444THREADED_TEST(CheckForCrossContextObjectLiterals) {
8445 v8::V8::Initialize();
8446
8447 const int nof = 2;
8448 const char* sources[nof] = {
8449 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
8450 "Object()"
8451 };
8452
8453 for (int i = 0; i < nof; i++) {
8454 const char* source = sources[i];
8455 { v8::HandleScope scope;
8456 LocalContext context;
8457 CompileRun(source);
8458 }
8459 { v8::HandleScope scope;
8460 LocalContext context;
8461 CompileRun(source);
8462 }
8463 }
8464}
8465
8466
8467static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
8468 v8::HandleScope inner;
8469 env->Enter();
8470 v8::Handle<Value> three = v8_num(3);
8471 v8::Handle<Value> value = inner.Close(three);
8472 env->Exit();
8473 return value;
8474}
8475
8476
8477THREADED_TEST(NestedHandleScopeAndContexts) {
8478 v8::HandleScope outer;
8479 v8::Persistent<Context> env = Context::New();
8480 env->Enter();
8481 v8::Handle<Value> value = NestedScope(env);
8482 v8::Handle<String> str = value->ToString();
8483 env->Exit();
8484 env.Dispose();
8485}
8486
8487
8488THREADED_TEST(ExternalAllocatedMemory) {
8489 v8::HandleScope outer;
8490 v8::Persistent<Context> env = Context::New();
8491 const int kSize = 1024*1024;
8492 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
8493 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
8494}
8495
8496
8497THREADED_TEST(DisposeEnteredContext) {
8498 v8::HandleScope scope;
8499 LocalContext outer;
8500 { v8::Persistent<v8::Context> inner = v8::Context::New();
8501 inner->Enter();
8502 inner.Dispose();
8503 inner.Clear();
8504 inner->Exit();
8505 }
8506}
8507
8508
8509// Regression test for issue 54, object templates with internal fields
8510// but no accessors or interceptors did not get their internal field
8511// count set on instances.
8512THREADED_TEST(Regress54) {
8513 v8::HandleScope outer;
8514 LocalContext context;
8515 static v8::Persistent<v8::ObjectTemplate> templ;
8516 if (templ.IsEmpty()) {
8517 v8::HandleScope inner;
8518 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
8519 local->SetInternalFieldCount(1);
8520 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
8521 }
8522 v8::Handle<v8::Object> result = templ->NewInstance();
8523 CHECK_EQ(1, result->InternalFieldCount());
8524}
8525
8526
8527// If part of the threaded tests, this test makes ThreadingTest fail
8528// on mac.
8529TEST(CatchStackOverflow) {
8530 v8::HandleScope scope;
8531 LocalContext context;
8532 v8::TryCatch try_catch;
8533 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
8534 "function f() {"
8535 " return f();"
8536 "}"
8537 ""
8538 "f();"));
8539 v8::Handle<v8::Value> result = script->Run();
8540 CHECK(result.IsEmpty());
8541}
8542
8543
8544static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
8545 const char* resource_name,
8546 int line_offset) {
8547 v8::HandleScope scope;
8548 v8::TryCatch try_catch;
8549 v8::Handle<v8::Value> result = script->Run();
8550 CHECK(result.IsEmpty());
8551 CHECK(try_catch.HasCaught());
8552 v8::Handle<v8::Message> message = try_catch.Message();
8553 CHECK(!message.IsEmpty());
8554 CHECK_EQ(10 + line_offset, message->GetLineNumber());
8555 CHECK_EQ(91, message->GetStartPosition());
8556 CHECK_EQ(92, message->GetEndPosition());
8557 CHECK_EQ(2, message->GetStartColumn());
8558 CHECK_EQ(3, message->GetEndColumn());
8559 v8::String::AsciiValue line(message->GetSourceLine());
8560 CHECK_EQ(" throw 'nirk';", *line);
8561 v8::String::AsciiValue name(message->GetScriptResourceName());
8562 CHECK_EQ(resource_name, *name);
8563}
8564
8565
8566THREADED_TEST(TryCatchSourceInfo) {
8567 v8::HandleScope scope;
8568 LocalContext context;
8569 v8::Handle<v8::String> source = v8::String::New(
8570 "function Foo() {\n"
8571 " return Bar();\n"
8572 "}\n"
8573 "\n"
8574 "function Bar() {\n"
8575 " return Baz();\n"
8576 "}\n"
8577 "\n"
8578 "function Baz() {\n"
8579 " throw 'nirk';\n"
8580 "}\n"
8581 "\n"
8582 "Foo();\n");
8583
8584 const char* resource_name;
8585 v8::Handle<v8::Script> script;
8586 resource_name = "test.js";
8587 script = v8::Script::Compile(source, v8::String::New(resource_name));
8588 CheckTryCatchSourceInfo(script, resource_name, 0);
8589
8590 resource_name = "test1.js";
8591 v8::ScriptOrigin origin1(v8::String::New(resource_name));
8592 script = v8::Script::Compile(source, &origin1);
8593 CheckTryCatchSourceInfo(script, resource_name, 0);
8594
8595 resource_name = "test2.js";
8596 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
8597 script = v8::Script::Compile(source, &origin2);
8598 CheckTryCatchSourceInfo(script, resource_name, 7);
8599}
8600
8601
8602THREADED_TEST(CompilationCache) {
8603 v8::HandleScope scope;
8604 LocalContext context;
8605 v8::Handle<v8::String> source0 = v8::String::New("1234");
8606 v8::Handle<v8::String> source1 = v8::String::New("1234");
8607 v8::Handle<v8::Script> script0 =
8608 v8::Script::Compile(source0, v8::String::New("test.js"));
8609 v8::Handle<v8::Script> script1 =
8610 v8::Script::Compile(source1, v8::String::New("test.js"));
8611 v8::Handle<v8::Script> script2 =
8612 v8::Script::Compile(source0); // different origin
8613 CHECK_EQ(1234, script0->Run()->Int32Value());
8614 CHECK_EQ(1234, script1->Run()->Int32Value());
8615 CHECK_EQ(1234, script2->Run()->Int32Value());
8616}
8617
8618
8619static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
8620 ApiTestFuzzer::Fuzz();
8621 return v8_num(42);
8622}
8623
8624
8625THREADED_TEST(CallbackFunctionName) {
8626 v8::HandleScope scope;
8627 LocalContext context;
8628 Local<ObjectTemplate> t = ObjectTemplate::New();
8629 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
8630 context->Global()->Set(v8_str("obj"), t->NewInstance());
8631 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
8632 CHECK(value->IsString());
8633 v8::String::AsciiValue name(value);
8634 CHECK_EQ("asdf", *name);
8635}
8636
8637
8638THREADED_TEST(DateAccess) {
8639 v8::HandleScope scope;
8640 LocalContext context;
8641 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
8642 CHECK(date->IsDate());
Steve Block6ded16b2010-05-10 14:33:55 +01008643 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
Steve Blocka7e24c12009-10-30 11:49:00 +00008644}
8645
8646
8647void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
Steve Block6ded16b2010-05-10 14:33:55 +01008648 v8::Handle<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008649 v8::Handle<v8::Array> props = obj->GetPropertyNames();
8650 CHECK_EQ(elmc, props->Length());
8651 for (int i = 0; i < elmc; i++) {
8652 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
8653 CHECK_EQ(elmv[i], *elm);
8654 }
8655}
8656
8657
8658THREADED_TEST(PropertyEnumeration) {
8659 v8::HandleScope scope;
8660 LocalContext context;
8661 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
8662 "var result = [];"
8663 "result[0] = {};"
8664 "result[1] = {a: 1, b: 2};"
8665 "result[2] = [1, 2, 3];"
8666 "var proto = {x: 1, y: 2, z: 3};"
8667 "var x = { __proto__: proto, w: 0, z: 1 };"
8668 "result[3] = x;"
8669 "result;"))->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01008670 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008671 CHECK_EQ(4, elms->Length());
8672 int elmc0 = 0;
8673 const char** elmv0 = NULL;
8674 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
8675 int elmc1 = 2;
8676 const char* elmv1[] = {"a", "b"};
8677 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
8678 int elmc2 = 3;
8679 const char* elmv2[] = {"0", "1", "2"};
8680 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
8681 int elmc3 = 4;
8682 const char* elmv3[] = {"w", "z", "x", "y"};
8683 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
8684}
8685
8686
Steve Blocka7e24c12009-10-30 11:49:00 +00008687static bool NamedSetAccessBlocker(Local<v8::Object> obj,
8688 Local<Value> name,
8689 v8::AccessType type,
8690 Local<Value> data) {
8691 return type != v8::ACCESS_SET;
8692}
8693
8694
8695static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
8696 uint32_t key,
8697 v8::AccessType type,
8698 Local<Value> data) {
8699 return type != v8::ACCESS_SET;
8700}
8701
8702
8703THREADED_TEST(DisableAccessChecksWhileConfiguring) {
8704 v8::HandleScope scope;
8705 LocalContext context;
8706 Local<ObjectTemplate> templ = ObjectTemplate::New();
8707 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8708 IndexedSetAccessBlocker);
8709 templ->Set(v8_str("x"), v8::True());
8710 Local<v8::Object> instance = templ->NewInstance();
8711 context->Global()->Set(v8_str("obj"), instance);
8712 Local<Value> value = CompileRun("obj.x");
8713 CHECK(value->BooleanValue());
8714}
8715
8716
8717static bool NamedGetAccessBlocker(Local<v8::Object> obj,
8718 Local<Value> name,
8719 v8::AccessType type,
8720 Local<Value> data) {
8721 return false;
8722}
8723
8724
8725static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
8726 uint32_t key,
8727 v8::AccessType type,
8728 Local<Value> data) {
8729 return false;
8730}
8731
8732
8733
8734THREADED_TEST(AccessChecksReenabledCorrectly) {
8735 v8::HandleScope scope;
8736 LocalContext context;
8737 Local<ObjectTemplate> templ = ObjectTemplate::New();
8738 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8739 IndexedGetAccessBlocker);
8740 templ->Set(v8_str("a"), v8_str("a"));
8741 // Add more than 8 (see kMaxFastProperties) properties
8742 // so that the constructor will force copying map.
8743 // Cannot sprintf, gcc complains unsafety.
8744 char buf[4];
8745 for (char i = '0'; i <= '9' ; i++) {
8746 buf[0] = i;
8747 for (char j = '0'; j <= '9'; j++) {
8748 buf[1] = j;
8749 for (char k = '0'; k <= '9'; k++) {
8750 buf[2] = k;
8751 buf[3] = 0;
8752 templ->Set(v8_str(buf), v8::Number::New(k));
8753 }
8754 }
8755 }
8756
8757 Local<v8::Object> instance_1 = templ->NewInstance();
8758 context->Global()->Set(v8_str("obj_1"), instance_1);
8759
8760 Local<Value> value_1 = CompileRun("obj_1.a");
8761 CHECK(value_1->IsUndefined());
8762
8763 Local<v8::Object> instance_2 = templ->NewInstance();
8764 context->Global()->Set(v8_str("obj_2"), instance_2);
8765
8766 Local<Value> value_2 = CompileRun("obj_2.a");
8767 CHECK(value_2->IsUndefined());
8768}
8769
8770
8771// This tests that access check information remains on the global
8772// object template when creating contexts.
8773THREADED_TEST(AccessControlRepeatedContextCreation) {
8774 v8::HandleScope handle_scope;
8775 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8776 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
8777 IndexedSetAccessBlocker);
8778 i::Handle<i::ObjectTemplateInfo> internal_template =
8779 v8::Utils::OpenHandle(*global_template);
8780 CHECK(!internal_template->constructor()->IsUndefined());
8781 i::Handle<i::FunctionTemplateInfo> constructor(
8782 i::FunctionTemplateInfo::cast(internal_template->constructor()));
8783 CHECK(!constructor->access_check_info()->IsUndefined());
8784 v8::Persistent<Context> context0 = Context::New(NULL, global_template);
8785 CHECK(!constructor->access_check_info()->IsUndefined());
8786}
8787
8788
8789THREADED_TEST(TurnOnAccessCheck) {
8790 v8::HandleScope handle_scope;
8791
8792 // Create an environment with access check to the global object disabled by
8793 // default.
8794 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8795 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
8796 IndexedGetAccessBlocker,
8797 v8::Handle<v8::Value>(),
8798 false);
8799 v8::Persistent<Context> context = Context::New(NULL, global_template);
8800 Context::Scope context_scope(context);
8801
8802 // Set up a property and a number of functions.
8803 context->Global()->Set(v8_str("a"), v8_num(1));
8804 CompileRun("function f1() {return a;}"
8805 "function f2() {return a;}"
8806 "function g1() {return h();}"
8807 "function g2() {return h();}"
8808 "function h() {return 1;}");
8809 Local<Function> f1 =
8810 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8811 Local<Function> f2 =
8812 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8813 Local<Function> g1 =
8814 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8815 Local<Function> g2 =
8816 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8817 Local<Function> h =
8818 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8819
8820 // Get the global object.
8821 v8::Handle<v8::Object> global = context->Global();
8822
8823 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8824 // uses the runtime system to retreive property a whereas f2 uses global load
8825 // inline cache.
8826 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8827 for (int i = 0; i < 4; i++) {
8828 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8829 }
8830
8831 // Same for g1 and g2.
8832 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8833 for (int i = 0; i < 4; i++) {
8834 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8835 }
8836
8837 // Detach the global and turn on access check.
8838 context->DetachGlobal();
8839 context->Global()->TurnOnAccessCheck();
8840
8841 // Failing access check to property get results in undefined.
8842 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8843 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8844
8845 // Failing access check to function call results in exception.
8846 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8847 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8848
8849 // No failing access check when just returning a constant.
8850 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8851}
8852
8853
Ben Murdochb0fe1622011-05-05 13:52:32 +01008854v8::Handle<v8::String> a;
8855v8::Handle<v8::String> h;
8856
8857static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
8858 Local<Value> name,
8859 v8::AccessType type,
8860 Local<Value> data) {
8861 return !(name->Equals(a) || name->Equals(h));
8862}
8863
8864
8865THREADED_TEST(TurnOnAccessCheckAndRecompile) {
8866 v8::HandleScope handle_scope;
8867
8868 // Create an environment with access check to the global object disabled by
8869 // default. When the registered access checker will block access to properties
8870 // a and h
8871 a = v8_str("a");
8872 h = v8_str("h");
8873 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8874 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
8875 IndexedGetAccessBlocker,
8876 v8::Handle<v8::Value>(),
8877 false);
8878 v8::Persistent<Context> context = Context::New(NULL, global_template);
8879 Context::Scope context_scope(context);
8880
8881 // Set up a property and a number of functions.
8882 context->Global()->Set(v8_str("a"), v8_num(1));
8883 static const char* source = "function f1() {return a;}"
8884 "function f2() {return a;}"
8885 "function g1() {return h();}"
8886 "function g2() {return h();}"
8887 "function h() {return 1;}";
8888
8889 CompileRun(source);
8890 Local<Function> f1;
8891 Local<Function> f2;
8892 Local<Function> g1;
8893 Local<Function> g2;
8894 Local<Function> h;
8895 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8896 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8897 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8898 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8899 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
8900
8901 // Get the global object.
8902 v8::Handle<v8::Object> global = context->Global();
8903
8904 // Call f1 one time and f2 a number of times. This will ensure that f1 still
8905 // uses the runtime system to retreive property a whereas f2 uses global load
8906 // inline cache.
8907 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
8908 for (int i = 0; i < 4; i++) {
8909 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
8910 }
8911
8912 // Same for g1 and g2.
8913 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
8914 for (int i = 0; i < 4; i++) {
8915 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
8916 }
8917
8918 // Detach the global and turn on access check now blocking access to property
8919 // a and function h.
8920 context->DetachGlobal();
8921 context->Global()->TurnOnAccessCheck();
8922
8923 // Failing access check to property get results in undefined.
8924 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8925 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8926
8927 // Failing access check to function call results in exception.
8928 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8929 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8930
8931 // No failing access check when just returning a constant.
8932 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
8933
8934 // Now compile the source again. And get the newly compiled functions, except
8935 // for h for which access is blocked.
8936 CompileRun(source);
8937 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
8938 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
8939 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
8940 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
8941 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
8942
8943 // Failing access check to property get results in undefined.
8944 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
8945 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
8946
8947 // Failing access check to function call results in exception.
8948 CHECK(g1->Call(global, 0, NULL).IsEmpty());
8949 CHECK(g2->Call(global, 0, NULL).IsEmpty());
8950}
8951
8952
Steve Blocka7e24c12009-10-30 11:49:00 +00008953// This test verifies that pre-compilation (aka preparsing) can be called
8954// without initializing the whole VM. Thus we cannot run this test in a
8955// multi-threaded setup.
8956TEST(PreCompile) {
8957 // TODO(155): This test would break without the initialization of V8. This is
8958 // a workaround for now to make this test not fail.
8959 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01008960 const char* script = "function foo(a) { return a+1; }";
8961 v8::ScriptData* sd =
Steve Blockd0582a62009-12-15 09:54:21 +00008962 v8::ScriptData::PreCompile(script, i::StrLength(script));
Steve Blocka7e24c12009-10-30 11:49:00 +00008963 CHECK_NE(sd->Length(), 0);
8964 CHECK_NE(sd->Data(), NULL);
Leon Clarkee46be812010-01-19 14:06:41 +00008965 CHECK(!sd->HasError());
8966 delete sd;
8967}
8968
8969
8970TEST(PreCompileWithError) {
8971 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01008972 const char* script = "function foo(a) { return 1 * * 2; }";
8973 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +00008974 v8::ScriptData::PreCompile(script, i::StrLength(script));
8975 CHECK(sd->HasError());
8976 delete sd;
8977}
8978
8979
8980TEST(Regress31661) {
8981 v8::V8::Initialize();
Leon Clarkef7060e22010-06-03 12:02:55 +01008982 const char* script = " The Definintive Guide";
8983 v8::ScriptData* sd =
Leon Clarkee46be812010-01-19 14:06:41 +00008984 v8::ScriptData::PreCompile(script, i::StrLength(script));
8985 CHECK(sd->HasError());
Steve Blocka7e24c12009-10-30 11:49:00 +00008986 delete sd;
8987}
8988
8989
Leon Clarkef7060e22010-06-03 12:02:55 +01008990// Tests that ScriptData can be serialized and deserialized.
8991TEST(PreCompileSerialization) {
8992 v8::V8::Initialize();
8993 const char* script = "function foo(a) { return a+1; }";
8994 v8::ScriptData* sd =
8995 v8::ScriptData::PreCompile(script, i::StrLength(script));
8996
8997 // Serialize.
8998 int serialized_data_length = sd->Length();
8999 char* serialized_data = i::NewArray<char>(serialized_data_length);
9000 memcpy(serialized_data, sd->Data(), serialized_data_length);
9001
9002 // Deserialize.
9003 v8::ScriptData* deserialized_sd =
9004 v8::ScriptData::New(serialized_data, serialized_data_length);
9005
9006 // Verify that the original is the same as the deserialized.
9007 CHECK_EQ(sd->Length(), deserialized_sd->Length());
9008 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
9009 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
9010
9011 delete sd;
9012 delete deserialized_sd;
9013}
9014
9015
9016// Attempts to deserialize bad data.
9017TEST(PreCompileDeserializationError) {
9018 v8::V8::Initialize();
9019 const char* data = "DONT CARE";
9020 int invalid_size = 3;
9021 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
9022
9023 CHECK_EQ(0, sd->Length());
9024
9025 delete sd;
9026}
9027
9028
Leon Clarkeac952652010-07-15 11:15:24 +01009029// Attempts to deserialize bad data.
9030TEST(PreCompileInvalidPreparseDataError) {
9031 v8::V8::Initialize();
9032 v8::HandleScope scope;
9033 LocalContext context;
9034
9035 const char* script = "function foo(){ return 5;}\n"
9036 "function bar(){ return 6 + 7;} foo();";
9037 v8::ScriptData* sd =
9038 v8::ScriptData::PreCompile(script, i::StrLength(script));
9039 CHECK(!sd->HasError());
9040 // ScriptDataImpl private implementation details
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08009041 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
Iain Merrick9ac36c92010-09-13 15:29:50 +01009042 const int kFunctionEntrySize = i::FunctionEntry::kSize;
Leon Clarkeac952652010-07-15 11:15:24 +01009043 const int kFunctionEntryStartOffset = 0;
9044 const int kFunctionEntryEndOffset = 1;
9045 unsigned* sd_data =
9046 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +01009047
9048 // Overwrite function bar's end position with 0.
9049 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
9050 v8::TryCatch try_catch;
9051
9052 Local<String> source = String::New(script);
9053 Local<Script> compiled_script = Script::New(source, NULL, sd);
9054 CHECK(try_catch.HasCaught());
9055 String::AsciiValue exception_value(try_catch.Message()->Get());
9056 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9057 *exception_value);
9058
9059 try_catch.Reset();
9060 // Overwrite function bar's start position with 200. The function entry
9061 // will not be found when searching for it by position.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009062 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
9063 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
Leon Clarkeac952652010-07-15 11:15:24 +01009064 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
9065 200;
9066 compiled_script = Script::New(source, NULL, sd);
9067 CHECK(try_catch.HasCaught());
9068 String::AsciiValue second_exception_value(try_catch.Message()->Get());
9069 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
9070 *second_exception_value);
9071
9072 delete sd;
9073}
9074
9075
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009076// Verifies that the Handle<String> and const char* versions of the API produce
9077// the same results (at least for one trivial case).
9078TEST(PreCompileAPIVariationsAreSame) {
9079 v8::V8::Initialize();
9080 v8::HandleScope scope;
9081
9082 const char* cstring = "function foo(a) { return a+1; }";
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009083
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009084 v8::ScriptData* sd_from_cstring =
9085 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
9086
9087 TestAsciiResource* resource = new TestAsciiResource(cstring);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009088 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009089 v8::String::NewExternal(resource));
9090
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009091 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
9092 v8::String::New(cstring));
9093
9094 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009095 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009096 sd_from_external_string->Data(),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009097 sd_from_cstring->Length()));
9098
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009099 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
9100 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
9101 sd_from_string->Data(),
9102 sd_from_cstring->Length()));
9103
9104
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009105 delete sd_from_cstring;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009106 delete sd_from_external_string;
9107 delete sd_from_string;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009108}
9109
9110
Steve Blocka7e24c12009-10-30 11:49:00 +00009111// This tests that we do not allow dictionary load/call inline caches
9112// to use functions that have not yet been compiled. The potential
9113// problem of loading a function that has not yet been compiled can
9114// arise because we share code between contexts via the compilation
9115// cache.
9116THREADED_TEST(DictionaryICLoadedFunction) {
9117 v8::HandleScope scope;
9118 // Test LoadIC.
9119 for (int i = 0; i < 2; i++) {
9120 LocalContext context;
9121 context->Global()->Set(v8_str("tmp"), v8::True());
9122 context->Global()->Delete(v8_str("tmp"));
9123 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
9124 }
9125 // Test CallIC.
9126 for (int i = 0; i < 2; i++) {
9127 LocalContext context;
9128 context->Global()->Set(v8_str("tmp"), v8::True());
9129 context->Global()->Delete(v8_str("tmp"));
9130 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
9131 }
9132}
9133
9134
9135// Test that cross-context new calls use the context of the callee to
9136// create the new JavaScript object.
9137THREADED_TEST(CrossContextNew) {
9138 v8::HandleScope scope;
9139 v8::Persistent<Context> context0 = Context::New();
9140 v8::Persistent<Context> context1 = Context::New();
9141
9142 // Allow cross-domain access.
9143 Local<String> token = v8_str("<security token>");
9144 context0->SetSecurityToken(token);
9145 context1->SetSecurityToken(token);
9146
9147 // Set an 'x' property on the Object prototype and define a
9148 // constructor function in context0.
9149 context0->Enter();
9150 CompileRun("Object.prototype.x = 42; function C() {};");
9151 context0->Exit();
9152
9153 // Call the constructor function from context0 and check that the
9154 // result has the 'x' property.
9155 context1->Enter();
9156 context1->Global()->Set(v8_str("other"), context0->Global());
9157 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
9158 CHECK(value->IsInt32());
9159 CHECK_EQ(42, value->Int32Value());
9160 context1->Exit();
9161
9162 // Dispose the contexts to allow them to be garbage collected.
9163 context0.Dispose();
9164 context1.Dispose();
9165}
9166
9167
9168class RegExpInterruptTest {
9169 public:
9170 RegExpInterruptTest() : block_(NULL) {}
9171 ~RegExpInterruptTest() { delete block_; }
9172 void RunTest() {
9173 block_ = i::OS::CreateSemaphore(0);
9174 gc_count_ = 0;
9175 gc_during_regexp_ = 0;
9176 regexp_success_ = false;
9177 gc_success_ = false;
9178 GCThread gc_thread(this);
9179 gc_thread.Start();
9180 v8::Locker::StartPreemption(1);
9181
9182 LongRunningRegExp();
9183 {
9184 v8::Unlocker unlock;
9185 gc_thread.Join();
9186 }
9187 v8::Locker::StopPreemption();
9188 CHECK(regexp_success_);
9189 CHECK(gc_success_);
9190 }
9191 private:
9192 // Number of garbage collections required.
9193 static const int kRequiredGCs = 5;
9194
9195 class GCThread : public i::Thread {
9196 public:
9197 explicit GCThread(RegExpInterruptTest* test)
9198 : test_(test) {}
9199 virtual void Run() {
9200 test_->CollectGarbage();
9201 }
9202 private:
9203 RegExpInterruptTest* test_;
9204 };
9205
9206 void CollectGarbage() {
9207 block_->Wait();
9208 while (gc_during_regexp_ < kRequiredGCs) {
9209 {
9210 v8::Locker lock;
9211 // TODO(lrn): Perhaps create some garbage before collecting.
9212 i::Heap::CollectAllGarbage(false);
9213 gc_count_++;
9214 }
9215 i::OS::Sleep(1);
9216 }
9217 gc_success_ = true;
9218 }
9219
9220 void LongRunningRegExp() {
9221 block_->Signal(); // Enable garbage collection thread on next preemption.
9222 int rounds = 0;
9223 while (gc_during_regexp_ < kRequiredGCs) {
9224 int gc_before = gc_count_;
9225 {
9226 // Match 15-30 "a"'s against 14 and a "b".
9227 const char* c_source =
9228 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9229 ".exec('aaaaaaaaaaaaaaab') === null";
9230 Local<String> source = String::New(c_source);
9231 Local<Script> script = Script::Compile(source);
9232 Local<Value> result = script->Run();
9233 if (!result->BooleanValue()) {
9234 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
9235 return;
9236 }
9237 }
9238 {
9239 // Match 15-30 "a"'s against 15 and a "b".
9240 const char* c_source =
9241 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9242 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
9243 Local<String> source = String::New(c_source);
9244 Local<Script> script = Script::Compile(source);
9245 Local<Value> result = script->Run();
9246 if (!result->BooleanValue()) {
9247 gc_during_regexp_ = kRequiredGCs;
9248 return;
9249 }
9250 }
9251 int gc_after = gc_count_;
9252 gc_during_regexp_ += gc_after - gc_before;
9253 rounds++;
9254 i::OS::Sleep(1);
9255 }
9256 regexp_success_ = true;
9257 }
9258
9259 i::Semaphore* block_;
9260 int gc_count_;
9261 int gc_during_regexp_;
9262 bool regexp_success_;
9263 bool gc_success_;
9264};
9265
9266
9267// Test that a regular expression execution can be interrupted and
9268// survive a garbage collection.
9269TEST(RegExpInterruption) {
9270 v8::Locker lock;
9271 v8::V8::Initialize();
9272 v8::HandleScope scope;
9273 Local<Context> local_env;
9274 {
9275 LocalContext env;
9276 local_env = env.local();
9277 }
9278
9279 // Local context should still be live.
9280 CHECK(!local_env.IsEmpty());
9281 local_env->Enter();
9282
9283 // Should complete without problems.
9284 RegExpInterruptTest().RunTest();
9285
9286 local_env->Exit();
9287}
9288
9289
9290class ApplyInterruptTest {
9291 public:
9292 ApplyInterruptTest() : block_(NULL) {}
9293 ~ApplyInterruptTest() { delete block_; }
9294 void RunTest() {
9295 block_ = i::OS::CreateSemaphore(0);
9296 gc_count_ = 0;
9297 gc_during_apply_ = 0;
9298 apply_success_ = false;
9299 gc_success_ = false;
9300 GCThread gc_thread(this);
9301 gc_thread.Start();
9302 v8::Locker::StartPreemption(1);
9303
9304 LongRunningApply();
9305 {
9306 v8::Unlocker unlock;
9307 gc_thread.Join();
9308 }
9309 v8::Locker::StopPreemption();
9310 CHECK(apply_success_);
9311 CHECK(gc_success_);
9312 }
9313 private:
9314 // Number of garbage collections required.
9315 static const int kRequiredGCs = 2;
9316
9317 class GCThread : public i::Thread {
9318 public:
9319 explicit GCThread(ApplyInterruptTest* test)
9320 : test_(test) {}
9321 virtual void Run() {
9322 test_->CollectGarbage();
9323 }
9324 private:
9325 ApplyInterruptTest* test_;
9326 };
9327
9328 void CollectGarbage() {
9329 block_->Wait();
9330 while (gc_during_apply_ < kRequiredGCs) {
9331 {
9332 v8::Locker lock;
9333 i::Heap::CollectAllGarbage(false);
9334 gc_count_++;
9335 }
9336 i::OS::Sleep(1);
9337 }
9338 gc_success_ = true;
9339 }
9340
9341 void LongRunningApply() {
9342 block_->Signal();
9343 int rounds = 0;
9344 while (gc_during_apply_ < kRequiredGCs) {
9345 int gc_before = gc_count_;
9346 {
9347 const char* c_source =
9348 "function do_very_little(bar) {"
9349 " this.foo = bar;"
9350 "}"
9351 "for (var i = 0; i < 100000; i++) {"
9352 " do_very_little.apply(this, ['bar']);"
9353 "}";
9354 Local<String> source = String::New(c_source);
9355 Local<Script> script = Script::Compile(source);
9356 Local<Value> result = script->Run();
9357 // Check that no exception was thrown.
9358 CHECK(!result.IsEmpty());
9359 }
9360 int gc_after = gc_count_;
9361 gc_during_apply_ += gc_after - gc_before;
9362 rounds++;
9363 }
9364 apply_success_ = true;
9365 }
9366
9367 i::Semaphore* block_;
9368 int gc_count_;
9369 int gc_during_apply_;
9370 bool apply_success_;
9371 bool gc_success_;
9372};
9373
9374
9375// Test that nothing bad happens if we get a preemption just when we were
9376// about to do an apply().
9377TEST(ApplyInterruption) {
9378 v8::Locker lock;
9379 v8::V8::Initialize();
9380 v8::HandleScope scope;
9381 Local<Context> local_env;
9382 {
9383 LocalContext env;
9384 local_env = env.local();
9385 }
9386
9387 // Local context should still be live.
9388 CHECK(!local_env.IsEmpty());
9389 local_env->Enter();
9390
9391 // Should complete without problems.
9392 ApplyInterruptTest().RunTest();
9393
9394 local_env->Exit();
9395}
9396
9397
9398// Verify that we can clone an object
9399TEST(ObjectClone) {
9400 v8::HandleScope scope;
9401 LocalContext env;
9402
9403 const char* sample =
9404 "var rv = {};" \
9405 "rv.alpha = 'hello';" \
9406 "rv.beta = 123;" \
9407 "rv;";
9408
9409 // Create an object, verify basics.
9410 Local<Value> val = CompileRun(sample);
9411 CHECK(val->IsObject());
Steve Block6ded16b2010-05-10 14:33:55 +01009412 Local<v8::Object> obj = val.As<v8::Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +00009413 obj->Set(v8_str("gamma"), v8_str("cloneme"));
9414
9415 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
9416 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9417 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
9418
9419 // Clone it.
9420 Local<v8::Object> clone = obj->Clone();
9421 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
9422 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
9423 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
9424
9425 // Set a property on the clone, verify each object.
9426 clone->Set(v8_str("beta"), v8::Integer::New(456));
9427 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
9428 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
9429}
9430
9431
9432class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
9433 public:
9434 explicit AsciiVectorResource(i::Vector<const char> vector)
9435 : data_(vector) {}
9436 virtual ~AsciiVectorResource() {}
9437 virtual size_t length() const { return data_.length(); }
9438 virtual const char* data() const { return data_.start(); }
9439 private:
9440 i::Vector<const char> data_;
9441};
9442
9443
9444class UC16VectorResource : public v8::String::ExternalStringResource {
9445 public:
9446 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
9447 : data_(vector) {}
9448 virtual ~UC16VectorResource() {}
9449 virtual size_t length() const { return data_.length(); }
9450 virtual const i::uc16* data() const { return data_.start(); }
9451 private:
9452 i::Vector<const i::uc16> data_;
9453};
9454
9455
9456static void MorphAString(i::String* string,
9457 AsciiVectorResource* ascii_resource,
9458 UC16VectorResource* uc16_resource) {
9459 CHECK(i::StringShape(string).IsExternal());
9460 if (string->IsAsciiRepresentation()) {
9461 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00009462 CHECK(string->map() == i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009463 // Morph external string to be TwoByte string.
Steve Blockd0582a62009-12-15 09:54:21 +00009464 string->set_map(i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009465 i::ExternalTwoByteString* morphed =
9466 i::ExternalTwoByteString::cast(string);
9467 morphed->set_resource(uc16_resource);
9468 } else {
9469 // Check old map is not symbol or long.
Steve Blockd0582a62009-12-15 09:54:21 +00009470 CHECK(string->map() == i::Heap::external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009471 // Morph external string to be ASCII string.
Steve Blockd0582a62009-12-15 09:54:21 +00009472 string->set_map(i::Heap::external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009473 i::ExternalAsciiString* morphed =
9474 i::ExternalAsciiString::cast(string);
9475 morphed->set_resource(ascii_resource);
9476 }
9477}
9478
9479
9480// Test that we can still flatten a string if the components it is built up
9481// from have been turned into 16 bit strings in the mean time.
9482THREADED_TEST(MorphCompositeStringTest) {
9483 const char* c_string = "Now is the time for all good men"
9484 " to come to the aid of the party";
9485 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
9486 {
9487 v8::HandleScope scope;
9488 LocalContext env;
9489 AsciiVectorResource ascii_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009490 i::Vector<const char>(c_string, i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00009491 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009492 i::Vector<const uint16_t>(two_byte_string,
9493 i::StrLength(c_string)));
Steve Blocka7e24c12009-10-30 11:49:00 +00009494
9495 Local<String> lhs(v8::Utils::ToLocal(
9496 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9497 Local<String> rhs(v8::Utils::ToLocal(
9498 i::Factory::NewExternalStringFromAscii(&ascii_resource)));
9499
9500 env->Global()->Set(v8_str("lhs"), lhs);
9501 env->Global()->Set(v8_str("rhs"), rhs);
9502
9503 CompileRun(
9504 "var cons = lhs + rhs;"
9505 "var slice = lhs.substring(1, lhs.length - 1);"
9506 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
9507
9508 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
9509 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
9510
9511 // Now do some stuff to make sure the strings are flattened, etc.
9512 CompileRun(
9513 "/[^a-z]/.test(cons);"
9514 "/[^a-z]/.test(slice);"
9515 "/[^a-z]/.test(slice_on_cons);");
9516 const char* expected_cons =
9517 "Now is the time for all good men to come to the aid of the party"
9518 "Now is the time for all good men to come to the aid of the party";
9519 const char* expected_slice =
9520 "ow is the time for all good men to come to the aid of the part";
9521 const char* expected_slice_on_cons =
9522 "ow is the time for all good men to come to the aid of the party"
9523 "Now is the time for all good men to come to the aid of the part";
9524 CHECK_EQ(String::New(expected_cons),
9525 env->Global()->Get(v8_str("cons")));
9526 CHECK_EQ(String::New(expected_slice),
9527 env->Global()->Get(v8_str("slice")));
9528 CHECK_EQ(String::New(expected_slice_on_cons),
9529 env->Global()->Get(v8_str("slice_on_cons")));
9530 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009531 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00009532}
9533
9534
9535TEST(CompileExternalTwoByteSource) {
9536 v8::HandleScope scope;
9537 LocalContext context;
9538
9539 // This is a very short list of sources, which currently is to check for a
9540 // regression caused by r2703.
9541 const char* ascii_sources[] = {
9542 "0.5",
9543 "-0.5", // This mainly testes PushBack in the Scanner.
9544 "--0.5", // This mainly testes PushBack in the Scanner.
9545 NULL
9546 };
9547
9548 // Compile the sources as external two byte strings.
9549 for (int i = 0; ascii_sources[i] != NULL; i++) {
9550 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
9551 UC16VectorResource uc16_resource(
Steve Blockd0582a62009-12-15 09:54:21 +00009552 i::Vector<const uint16_t>(two_byte_string,
9553 i::StrLength(ascii_sources[i])));
Steve Blocka7e24c12009-10-30 11:49:00 +00009554 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
9555 v8::Script::Compile(source);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009556 i::DeleteArray(two_byte_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00009557 }
9558}
9559
9560
9561class RegExpStringModificationTest {
9562 public:
9563 RegExpStringModificationTest()
9564 : block_(i::OS::CreateSemaphore(0)),
9565 morphs_(0),
9566 morphs_during_regexp_(0),
9567 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
9568 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
9569 ~RegExpStringModificationTest() { delete block_; }
9570 void RunTest() {
9571 regexp_success_ = false;
9572 morph_success_ = false;
9573
9574 // Initialize the contents of two_byte_content_ to be a uc16 representation
9575 // of "aaaaaaaaaaaaaab".
9576 for (int i = 0; i < 14; i++) {
9577 two_byte_content_[i] = 'a';
9578 }
9579 two_byte_content_[14] = 'b';
9580
9581 // Create the input string for the regexp - the one we are going to change
9582 // properties of.
9583 input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
9584
9585 // Inject the input as a global variable.
9586 i::Handle<i::String> input_name =
9587 i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
John Reck59135872010-11-02 12:39:01 -07009588 i::Top::global_context()->global()->SetProperty(*input_name,
9589 *input_,
9590 NONE)->ToObjectChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009591
9592
9593 MorphThread morph_thread(this);
9594 morph_thread.Start();
9595 v8::Locker::StartPreemption(1);
9596 LongRunningRegExp();
9597 {
9598 v8::Unlocker unlock;
9599 morph_thread.Join();
9600 }
9601 v8::Locker::StopPreemption();
9602 CHECK(regexp_success_);
9603 CHECK(morph_success_);
9604 }
9605 private:
9606
9607 // Number of string modifications required.
9608 static const int kRequiredModifications = 5;
9609 static const int kMaxModifications = 100;
9610
9611 class MorphThread : public i::Thread {
9612 public:
9613 explicit MorphThread(RegExpStringModificationTest* test)
9614 : test_(test) {}
9615 virtual void Run() {
9616 test_->MorphString();
9617 }
9618 private:
9619 RegExpStringModificationTest* test_;
9620 };
9621
9622 void MorphString() {
9623 block_->Wait();
9624 while (morphs_during_regexp_ < kRequiredModifications &&
9625 morphs_ < kMaxModifications) {
9626 {
9627 v8::Locker lock;
9628 // Swap string between ascii and two-byte representation.
9629 i::String* string = *input_;
9630 MorphAString(string, &ascii_resource_, &uc16_resource_);
9631 morphs_++;
9632 }
9633 i::OS::Sleep(1);
9634 }
9635 morph_success_ = true;
9636 }
9637
9638 void LongRunningRegExp() {
9639 block_->Signal(); // Enable morphing thread on next preemption.
9640 while (morphs_during_regexp_ < kRequiredModifications &&
9641 morphs_ < kMaxModifications) {
9642 int morphs_before = morphs_;
9643 {
Steve Block791712a2010-08-27 10:21:07 +01009644 v8::HandleScope scope;
Steve Blocka7e24c12009-10-30 11:49:00 +00009645 // Match 15-30 "a"'s against 14 and a "b".
9646 const char* c_source =
9647 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
9648 ".exec(input) === null";
9649 Local<String> source = String::New(c_source);
9650 Local<Script> script = Script::Compile(source);
9651 Local<Value> result = script->Run();
9652 CHECK(result->IsTrue());
9653 }
9654 int morphs_after = morphs_;
9655 morphs_during_regexp_ += morphs_after - morphs_before;
9656 }
9657 regexp_success_ = true;
9658 }
9659
9660 i::uc16 two_byte_content_[15];
9661 i::Semaphore* block_;
9662 int morphs_;
9663 int morphs_during_regexp_;
9664 bool regexp_success_;
9665 bool morph_success_;
9666 i::Handle<i::String> input_;
9667 AsciiVectorResource ascii_resource_;
9668 UC16VectorResource uc16_resource_;
9669};
9670
9671
9672// Test that a regular expression execution can be interrupted and
9673// the string changed without failing.
9674TEST(RegExpStringModification) {
9675 v8::Locker lock;
9676 v8::V8::Initialize();
9677 v8::HandleScope scope;
9678 Local<Context> local_env;
9679 {
9680 LocalContext env;
9681 local_env = env.local();
9682 }
9683
9684 // Local context should still be live.
9685 CHECK(!local_env.IsEmpty());
9686 local_env->Enter();
9687
9688 // Should complete without problems.
9689 RegExpStringModificationTest().RunTest();
9690
9691 local_env->Exit();
9692}
9693
9694
9695// Test that we can set a property on the global object even if there
9696// is a read-only property in the prototype chain.
9697TEST(ReadOnlyPropertyInGlobalProto) {
9698 v8::HandleScope scope;
9699 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9700 LocalContext context(0, templ);
9701 v8::Handle<v8::Object> global = context->Global();
9702 v8::Handle<v8::Object> global_proto =
9703 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
9704 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
9705 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
9706 // Check without 'eval' or 'with'.
9707 v8::Handle<v8::Value> res =
9708 CompileRun("function f() { x = 42; return x; }; f()");
9709 // Check with 'eval'.
9710 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
9711 CHECK_EQ(v8::Integer::New(42), res);
9712 // Check with 'with'.
9713 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
9714 CHECK_EQ(v8::Integer::New(42), res);
9715}
9716
9717static int force_set_set_count = 0;
9718static int force_set_get_count = 0;
9719bool pass_on_get = false;
9720
9721static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
9722 const v8::AccessorInfo& info) {
9723 force_set_get_count++;
9724 if (pass_on_get) {
9725 return v8::Handle<v8::Value>();
9726 } else {
9727 return v8::Int32::New(3);
9728 }
9729}
9730
9731static void ForceSetSetter(v8::Local<v8::String> name,
9732 v8::Local<v8::Value> value,
9733 const v8::AccessorInfo& info) {
9734 force_set_set_count++;
9735}
9736
9737static v8::Handle<v8::Value> ForceSetInterceptSetter(
9738 v8::Local<v8::String> name,
9739 v8::Local<v8::Value> value,
9740 const v8::AccessorInfo& info) {
9741 force_set_set_count++;
9742 return v8::Undefined();
9743}
9744
9745TEST(ForceSet) {
9746 force_set_get_count = 0;
9747 force_set_set_count = 0;
9748 pass_on_get = false;
9749
9750 v8::HandleScope scope;
9751 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9752 v8::Handle<v8::String> access_property = v8::String::New("a");
9753 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
9754 LocalContext context(NULL, templ);
9755 v8::Handle<v8::Object> global = context->Global();
9756
9757 // Ordinary properties
9758 v8::Handle<v8::String> simple_property = v8::String::New("p");
9759 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
9760 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9761 // This should fail because the property is read-only
9762 global->Set(simple_property, v8::Int32::New(5));
9763 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9764 // This should succeed even though the property is read-only
9765 global->ForceSet(simple_property, v8::Int32::New(6));
9766 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
9767
9768 // Accessors
9769 CHECK_EQ(0, force_set_set_count);
9770 CHECK_EQ(0, force_set_get_count);
9771 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9772 // CHECK_EQ the property shouldn't override it, just call the setter
9773 // which in this case does nothing.
9774 global->Set(access_property, v8::Int32::New(7));
9775 CHECK_EQ(3, global->Get(access_property)->Int32Value());
9776 CHECK_EQ(1, force_set_set_count);
9777 CHECK_EQ(2, force_set_get_count);
9778 // Forcing the property to be set should override the accessor without
9779 // calling it
9780 global->ForceSet(access_property, v8::Int32::New(8));
9781 CHECK_EQ(8, global->Get(access_property)->Int32Value());
9782 CHECK_EQ(1, force_set_set_count);
9783 CHECK_EQ(2, force_set_get_count);
9784}
9785
9786TEST(ForceSetWithInterceptor) {
9787 force_set_get_count = 0;
9788 force_set_set_count = 0;
9789 pass_on_get = false;
9790
9791 v8::HandleScope scope;
9792 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9793 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
9794 LocalContext context(NULL, templ);
9795 v8::Handle<v8::Object> global = context->Global();
9796
9797 v8::Handle<v8::String> some_property = v8::String::New("a");
9798 CHECK_EQ(0, force_set_set_count);
9799 CHECK_EQ(0, force_set_get_count);
9800 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9801 // Setting the property shouldn't override it, just call the setter
9802 // which in this case does nothing.
9803 global->Set(some_property, v8::Int32::New(7));
9804 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9805 CHECK_EQ(1, force_set_set_count);
9806 CHECK_EQ(2, force_set_get_count);
9807 // Getting the property when the interceptor returns an empty handle
9808 // should yield undefined, since the property isn't present on the
9809 // object itself yet.
9810 pass_on_get = true;
9811 CHECK(global->Get(some_property)->IsUndefined());
9812 CHECK_EQ(1, force_set_set_count);
9813 CHECK_EQ(3, force_set_get_count);
9814 // Forcing the property to be set should cause the value to be
9815 // set locally without calling the interceptor.
9816 global->ForceSet(some_property, v8::Int32::New(8));
9817 CHECK_EQ(8, global->Get(some_property)->Int32Value());
9818 CHECK_EQ(1, force_set_set_count);
9819 CHECK_EQ(4, force_set_get_count);
9820 // Reenabling the interceptor should cause it to take precedence over
9821 // the property
9822 pass_on_get = false;
9823 CHECK_EQ(3, global->Get(some_property)->Int32Value());
9824 CHECK_EQ(1, force_set_set_count);
9825 CHECK_EQ(5, force_set_get_count);
9826 // The interceptor should also work for other properties
9827 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
9828 CHECK_EQ(1, force_set_set_count);
9829 CHECK_EQ(6, force_set_get_count);
9830}
9831
9832
9833THREADED_TEST(ForceDelete) {
9834 v8::HandleScope scope;
9835 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9836 LocalContext context(NULL, templ);
9837 v8::Handle<v8::Object> global = context->Global();
9838
9839 // Ordinary properties
9840 v8::Handle<v8::String> simple_property = v8::String::New("p");
9841 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
9842 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9843 // This should fail because the property is dont-delete.
9844 CHECK(!global->Delete(simple_property));
9845 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
9846 // This should succeed even though the property is dont-delete.
9847 CHECK(global->ForceDelete(simple_property));
9848 CHECK(global->Get(simple_property)->IsUndefined());
9849}
9850
9851
9852static int force_delete_interceptor_count = 0;
9853static bool pass_on_delete = false;
9854
9855
9856static v8::Handle<v8::Boolean> ForceDeleteDeleter(
9857 v8::Local<v8::String> name,
9858 const v8::AccessorInfo& info) {
9859 force_delete_interceptor_count++;
9860 if (pass_on_delete) {
9861 return v8::Handle<v8::Boolean>();
9862 } else {
9863 return v8::True();
9864 }
9865}
9866
9867
9868THREADED_TEST(ForceDeleteWithInterceptor) {
9869 force_delete_interceptor_count = 0;
9870 pass_on_delete = false;
9871
9872 v8::HandleScope scope;
9873 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
9874 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
9875 LocalContext context(NULL, templ);
9876 v8::Handle<v8::Object> global = context->Global();
9877
9878 v8::Handle<v8::String> some_property = v8::String::New("a");
9879 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
9880
9881 // Deleting a property should get intercepted and nothing should
9882 // happen.
9883 CHECK_EQ(0, force_delete_interceptor_count);
9884 CHECK(global->Delete(some_property));
9885 CHECK_EQ(1, force_delete_interceptor_count);
9886 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9887 // Deleting the property when the interceptor returns an empty
9888 // handle should not delete the property since it is DontDelete.
9889 pass_on_delete = true;
9890 CHECK(!global->Delete(some_property));
9891 CHECK_EQ(2, force_delete_interceptor_count);
9892 CHECK_EQ(42, global->Get(some_property)->Int32Value());
9893 // Forcing the property to be deleted should delete the value
9894 // without calling the interceptor.
9895 CHECK(global->ForceDelete(some_property));
9896 CHECK(global->Get(some_property)->IsUndefined());
9897 CHECK_EQ(2, force_delete_interceptor_count);
9898}
9899
9900
9901// Make sure that forcing a delete invalidates any IC stubs, so we
9902// don't read the hole value.
9903THREADED_TEST(ForceDeleteIC) {
9904 v8::HandleScope scope;
9905 LocalContext context;
9906 // Create a DontDelete variable on the global object.
9907 CompileRun("this.__proto__ = { foo: 'horse' };"
9908 "var foo = 'fish';"
9909 "function f() { return foo.length; }");
9910 // Initialize the IC for foo in f.
9911 CompileRun("for (var i = 0; i < 4; i++) f();");
9912 // Make sure the value of foo is correct before the deletion.
9913 CHECK_EQ(4, CompileRun("f()")->Int32Value());
9914 // Force the deletion of foo.
9915 CHECK(context->Global()->ForceDelete(v8_str("foo")));
9916 // Make sure the value for foo is read from the prototype, and that
9917 // we don't get in trouble with reading the deleted cell value
9918 // sentinel.
9919 CHECK_EQ(5, CompileRun("f()")->Int32Value());
9920}
9921
9922
9923v8::Persistent<Context> calling_context0;
9924v8::Persistent<Context> calling_context1;
9925v8::Persistent<Context> calling_context2;
9926
9927
9928// Check that the call to the callback is initiated in
9929// calling_context2, the directly calling context is calling_context1
9930// and the callback itself is in calling_context0.
9931static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
9932 ApiTestFuzzer::Fuzz();
9933 CHECK(Context::GetCurrent() == calling_context0);
9934 CHECK(Context::GetCalling() == calling_context1);
9935 CHECK(Context::GetEntered() == calling_context2);
9936 return v8::Integer::New(42);
9937}
9938
9939
9940THREADED_TEST(GetCallingContext) {
9941 v8::HandleScope scope;
9942
9943 calling_context0 = Context::New();
9944 calling_context1 = Context::New();
9945 calling_context2 = Context::New();
9946
9947 // Allow cross-domain access.
9948 Local<String> token = v8_str("<security token>");
9949 calling_context0->SetSecurityToken(token);
9950 calling_context1->SetSecurityToken(token);
9951 calling_context2->SetSecurityToken(token);
9952
9953 // Create an object with a C++ callback in context0.
9954 calling_context0->Enter();
9955 Local<v8::FunctionTemplate> callback_templ =
9956 v8::FunctionTemplate::New(GetCallingContextCallback);
9957 calling_context0->Global()->Set(v8_str("callback"),
9958 callback_templ->GetFunction());
9959 calling_context0->Exit();
9960
9961 // Expose context0 in context1 and setup a function that calls the
9962 // callback function.
9963 calling_context1->Enter();
9964 calling_context1->Global()->Set(v8_str("context0"),
9965 calling_context0->Global());
9966 CompileRun("function f() { context0.callback() }");
9967 calling_context1->Exit();
9968
9969 // Expose context1 in context2 and call the callback function in
9970 // context0 indirectly through f in context1.
9971 calling_context2->Enter();
9972 calling_context2->Global()->Set(v8_str("context1"),
9973 calling_context1->Global());
9974 CompileRun("context1.f()");
9975 calling_context2->Exit();
9976
9977 // Dispose the contexts to allow them to be garbage collected.
9978 calling_context0.Dispose();
9979 calling_context1.Dispose();
9980 calling_context2.Dispose();
9981 calling_context0.Clear();
9982 calling_context1.Clear();
9983 calling_context2.Clear();
9984}
9985
9986
9987// Check that a variable declaration with no explicit initialization
9988// value does not shadow an existing property in the prototype chain.
9989//
9990// This is consistent with Firefox and Safari.
9991//
9992// See http://crbug.com/12548.
9993THREADED_TEST(InitGlobalVarInProtoChain) {
9994 v8::HandleScope scope;
9995 LocalContext context;
9996 // Introduce a variable in the prototype chain.
9997 CompileRun("__proto__.x = 42");
9998 v8::Handle<v8::Value> result = CompileRun("var x; x");
9999 CHECK(!result->IsUndefined());
10000 CHECK_EQ(42, result->Int32Value());
10001}
10002
10003
10004// Regression test for issue 398.
10005// If a function is added to an object, creating a constant function
10006// field, and the result is cloned, replacing the constant function on the
10007// original should not affect the clone.
10008// See http://code.google.com/p/v8/issues/detail?id=398
10009THREADED_TEST(ReplaceConstantFunction) {
10010 v8::HandleScope scope;
10011 LocalContext context;
10012 v8::Handle<v8::Object> obj = v8::Object::New();
10013 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
10014 v8::Handle<v8::String> foo_string = v8::String::New("foo");
10015 obj->Set(foo_string, func_templ->GetFunction());
10016 v8::Handle<v8::Object> obj_clone = obj->Clone();
10017 obj_clone->Set(foo_string, v8::String::New("Hello"));
10018 CHECK(!obj->Get(foo_string)->IsUndefined());
10019}
10020
10021
10022// Regression test for http://crbug.com/16276.
10023THREADED_TEST(Regress16276) {
10024 v8::HandleScope scope;
10025 LocalContext context;
10026 // Force the IC in f to be a dictionary load IC.
10027 CompileRun("function f(obj) { return obj.x; }\n"
10028 "var obj = { x: { foo: 42 }, y: 87 };\n"
10029 "var x = obj.x;\n"
10030 "delete obj.y;\n"
10031 "for (var i = 0; i < 5; i++) f(obj);");
10032 // Detach the global object to make 'this' refer directly to the
10033 // global object (not the proxy), and make sure that the dictionary
10034 // load IC doesn't mess up loading directly from the global object.
10035 context->DetachGlobal();
10036 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
10037}
10038
10039
10040THREADED_TEST(PixelArray) {
10041 v8::HandleScope scope;
10042 LocalContext context;
Steve Blockd0582a62009-12-15 09:54:21 +000010043 const int kElementCount = 260;
Steve Blocka7e24c12009-10-30 11:49:00 +000010044 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
10045 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
10046 pixel_data);
10047 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10048 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000010049 pixels->set(i, i % 256);
Steve Blocka7e24c12009-10-30 11:49:00 +000010050 }
10051 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10052 for (int i = 0; i < kElementCount; i++) {
Steve Blockd0582a62009-12-15 09:54:21 +000010053 CHECK_EQ(i % 256, pixels->get(i));
10054 CHECK_EQ(i % 256, pixel_data[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010055 }
10056
10057 v8::Handle<v8::Object> obj = v8::Object::New();
10058 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10059 // Set the elements to be the pixels.
10060 // jsobj->set_elements(*pixels);
10061 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
John Reck59135872010-11-02 12:39:01 -070010062 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010063 obj->Set(v8_str("field"), v8::Int32::New(1503));
10064 context->Global()->Set(v8_str("pixels"), obj);
10065 v8::Handle<v8::Value> result = CompileRun("pixels.field");
10066 CHECK_EQ(1503, result->Int32Value());
10067 result = CompileRun("pixels[1]");
10068 CHECK_EQ(1, result->Int32Value());
10069
10070 result = CompileRun("var sum = 0;"
10071 "for (var i = 0; i < 8; i++) {"
10072 " sum += pixels[i] = pixels[i] = -i;"
10073 "}"
10074 "sum;");
10075 CHECK_EQ(-28, result->Int32Value());
10076
10077 result = CompileRun("var sum = 0;"
10078 "for (var i = 0; i < 8; i++) {"
10079 " sum += pixels[i] = pixels[i] = 0;"
10080 "}"
10081 "sum;");
10082 CHECK_EQ(0, result->Int32Value());
10083
10084 result = CompileRun("var sum = 0;"
10085 "for (var i = 0; i < 8; i++) {"
10086 " sum += pixels[i] = pixels[i] = 255;"
10087 "}"
10088 "sum;");
10089 CHECK_EQ(8 * 255, result->Int32Value());
10090
10091 result = CompileRun("var sum = 0;"
10092 "for (var i = 0; i < 8; i++) {"
10093 " sum += pixels[i] = pixels[i] = 256 + i;"
10094 "}"
10095 "sum;");
10096 CHECK_EQ(2076, result->Int32Value());
10097
10098 result = CompileRun("var sum = 0;"
10099 "for (var i = 0; i < 8; i++) {"
10100 " sum += pixels[i] = pixels[i] = i;"
10101 "}"
10102 "sum;");
10103 CHECK_EQ(28, result->Int32Value());
10104
10105 result = CompileRun("var sum = 0;"
10106 "for (var i = 0; i < 8; i++) {"
10107 " sum += pixels[i];"
10108 "}"
10109 "sum;");
10110 CHECK_EQ(28, result->Int32Value());
10111
10112 i::Handle<i::Smi> value(i::Smi::FromInt(2));
10113 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010114 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010115 *value.location() = i::Smi::FromInt(256);
10116 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010117 CHECK_EQ(255,
10118 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010119 *value.location() = i::Smi::FromInt(-1);
10120 i::SetElement(jsobj, 1, value);
John Reck59135872010-11-02 12:39:01 -070010121 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010122
10123 result = CompileRun("for (var i = 0; i < 8; i++) {"
10124 " pixels[i] = (i * 65) - 109;"
10125 "}"
10126 "pixels[1] + pixels[6];");
10127 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010128 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10129 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10130 CHECK_EQ(21,
10131 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10132 CHECK_EQ(86,
10133 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10134 CHECK_EQ(151,
10135 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10136 CHECK_EQ(216,
10137 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10138 CHECK_EQ(255,
10139 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10140 CHECK_EQ(255,
10141 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010142 result = CompileRun("var sum = 0;"
10143 "for (var i = 0; i < 8; i++) {"
10144 " sum += pixels[i];"
10145 "}"
10146 "sum;");
10147 CHECK_EQ(984, result->Int32Value());
10148
10149 result = CompileRun("for (var i = 0; i < 8; i++) {"
10150 " pixels[i] = (i * 1.1);"
10151 "}"
10152 "pixels[1] + pixels[6];");
10153 CHECK_EQ(8, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010154 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
10155 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
10156 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
10157 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
10158 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
10159 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
10160 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
10161 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010162
10163 result = CompileRun("for (var i = 0; i < 8; i++) {"
10164 " pixels[7] = undefined;"
10165 "}"
10166 "pixels[7];");
10167 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010168 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010169
10170 result = CompileRun("for (var i = 0; i < 8; i++) {"
10171 " pixels[6] = '2.3';"
10172 "}"
10173 "pixels[6];");
10174 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010175 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010176
10177 result = CompileRun("for (var i = 0; i < 8; i++) {"
10178 " pixels[5] = NaN;"
10179 "}"
10180 "pixels[5];");
10181 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010182 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010183
10184 result = CompileRun("for (var i = 0; i < 8; i++) {"
10185 " pixels[8] = Infinity;"
10186 "}"
10187 "pixels[8];");
10188 CHECK_EQ(255, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010189 CHECK_EQ(255,
10190 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010191
10192 result = CompileRun("for (var i = 0; i < 8; i++) {"
10193 " pixels[9] = -Infinity;"
10194 "}"
10195 "pixels[9];");
10196 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010197 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010198
10199 result = CompileRun("pixels[3] = 33;"
10200 "delete pixels[3];"
10201 "pixels[3];");
10202 CHECK_EQ(33, result->Int32Value());
10203
10204 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
10205 "pixels[2] = 12; pixels[3] = 13;"
10206 "pixels.__defineGetter__('2',"
10207 "function() { return 120; });"
10208 "pixels[2];");
10209 CHECK_EQ(12, result->Int32Value());
10210
10211 result = CompileRun("var js_array = new Array(40);"
10212 "js_array[0] = 77;"
10213 "js_array;");
10214 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10215
10216 result = CompileRun("pixels[1] = 23;"
10217 "pixels.__proto__ = [];"
10218 "js_array.__proto__ = pixels;"
10219 "js_array.concat(pixels);");
10220 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10221 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10222
10223 result = CompileRun("pixels[1] = 23;");
10224 CHECK_EQ(23, result->Int32Value());
10225
Steve Blockd0582a62009-12-15 09:54:21 +000010226 // Test for index greater than 255. Regression test for:
10227 // http://code.google.com/p/chromium/issues/detail?id=26337.
10228 result = CompileRun("pixels[256] = 255;");
10229 CHECK_EQ(255, result->Int32Value());
10230 result = CompileRun("var i = 0;"
10231 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
10232 "i");
10233 CHECK_EQ(255, result->Int32Value());
10234
Steve Blocka7e24c12009-10-30 11:49:00 +000010235 free(pixel_data);
10236}
10237
10238
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010239THREADED_TEST(PixelArrayInfo) {
10240 v8::HandleScope scope;
10241 LocalContext context;
10242 for (int size = 0; size < 100; size += 10) {
10243 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
10244 v8::Handle<v8::Object> obj = v8::Object::New();
10245 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
10246 CHECK(obj->HasIndexedPropertiesInPixelData());
10247 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
10248 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
10249 free(pixel_data);
10250 }
10251}
10252
10253
10254static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
10255 switch (array_type) {
10256 case v8::kExternalByteArray:
10257 case v8::kExternalUnsignedByteArray:
10258 return 1;
10259 break;
10260 case v8::kExternalShortArray:
10261 case v8::kExternalUnsignedShortArray:
10262 return 2;
10263 break;
10264 case v8::kExternalIntArray:
10265 case v8::kExternalUnsignedIntArray:
10266 case v8::kExternalFloatArray:
10267 return 4;
10268 break;
10269 default:
10270 UNREACHABLE();
10271 return -1;
10272 }
10273 UNREACHABLE();
10274 return -1;
10275}
10276
10277
Steve Block3ce2e202009-11-05 08:53:23 +000010278template <class ExternalArrayClass, class ElementType>
10279static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
10280 int64_t low,
10281 int64_t high) {
10282 v8::HandleScope scope;
10283 LocalContext context;
10284 const int kElementCount = 40;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010285 int element_size = ExternalArrayElementSize(array_type);
Steve Block3ce2e202009-11-05 08:53:23 +000010286 ElementType* array_data =
10287 static_cast<ElementType*>(malloc(kElementCount * element_size));
10288 i::Handle<ExternalArrayClass> array =
10289 i::Handle<ExternalArrayClass>::cast(
10290 i::Factory::NewExternalArray(kElementCount, array_type, array_data));
10291 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10292 for (int i = 0; i < kElementCount; i++) {
10293 array->set(i, static_cast<ElementType>(i));
10294 }
10295 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10296 for (int i = 0; i < kElementCount; i++) {
10297 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
10298 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
10299 }
10300
10301 v8::Handle<v8::Object> obj = v8::Object::New();
10302 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
10303 // Set the elements to be the external array.
10304 obj->SetIndexedPropertiesToExternalArrayData(array_data,
10305 array_type,
10306 kElementCount);
John Reck59135872010-11-02 12:39:01 -070010307 CHECK_EQ(
10308 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010309 obj->Set(v8_str("field"), v8::Int32::New(1503));
10310 context->Global()->Set(v8_str("ext_array"), obj);
10311 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
10312 CHECK_EQ(1503, result->Int32Value());
10313 result = CompileRun("ext_array[1]");
10314 CHECK_EQ(1, result->Int32Value());
10315
10316 // Check pass through of assigned smis
10317 result = CompileRun("var sum = 0;"
10318 "for (var i = 0; i < 8; i++) {"
10319 " sum += ext_array[i] = ext_array[i] = -i;"
10320 "}"
10321 "sum;");
10322 CHECK_EQ(-28, result->Int32Value());
10323
10324 // Check assigned smis
10325 result = CompileRun("for (var i = 0; i < 8; i++) {"
10326 " ext_array[i] = i;"
10327 "}"
10328 "var sum = 0;"
10329 "for (var i = 0; i < 8; i++) {"
10330 " sum += ext_array[i];"
10331 "}"
10332 "sum;");
10333 CHECK_EQ(28, result->Int32Value());
10334
10335 // Check assigned smis in reverse order
10336 result = CompileRun("for (var i = 8; --i >= 0; ) {"
10337 " ext_array[i] = i;"
10338 "}"
10339 "var sum = 0;"
10340 "for (var i = 0; i < 8; i++) {"
10341 " sum += ext_array[i];"
10342 "}"
10343 "sum;");
10344 CHECK_EQ(28, result->Int32Value());
10345
10346 // Check pass through of assigned HeapNumbers
10347 result = CompileRun("var sum = 0;"
10348 "for (var i = 0; i < 16; i+=2) {"
10349 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
10350 "}"
10351 "sum;");
10352 CHECK_EQ(-28, result->Int32Value());
10353
10354 // Check assigned HeapNumbers
10355 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
10356 " ext_array[i] = (i * 0.5);"
10357 "}"
10358 "var sum = 0;"
10359 "for (var i = 0; i < 16; i+=2) {"
10360 " sum += ext_array[i];"
10361 "}"
10362 "sum;");
10363 CHECK_EQ(28, result->Int32Value());
10364
10365 // Check assigned HeapNumbers in reverse order
10366 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
10367 " ext_array[i] = (i * 0.5);"
10368 "}"
10369 "var sum = 0;"
10370 "for (var i = 0; i < 16; i+=2) {"
10371 " sum += ext_array[i];"
10372 "}"
10373 "sum;");
10374 CHECK_EQ(28, result->Int32Value());
10375
10376 i::ScopedVector<char> test_buf(1024);
10377
10378 // Check legal boundary conditions.
10379 // The repeated loads and stores ensure the ICs are exercised.
10380 const char* boundary_program =
10381 "var res = 0;"
10382 "for (var i = 0; i < 16; i++) {"
10383 " ext_array[i] = %lld;"
10384 " if (i > 8) {"
10385 " res = ext_array[i];"
10386 " }"
10387 "}"
10388 "res;";
10389 i::OS::SNPrintF(test_buf,
10390 boundary_program,
10391 low);
10392 result = CompileRun(test_buf.start());
10393 CHECK_EQ(low, result->IntegerValue());
10394
10395 i::OS::SNPrintF(test_buf,
10396 boundary_program,
10397 high);
10398 result = CompileRun(test_buf.start());
10399 CHECK_EQ(high, result->IntegerValue());
10400
10401 // Check misprediction of type in IC.
10402 result = CompileRun("var tmp_array = ext_array;"
10403 "var sum = 0;"
10404 "for (var i = 0; i < 8; i++) {"
10405 " tmp_array[i] = i;"
10406 " sum += tmp_array[i];"
10407 " if (i == 4) {"
10408 " tmp_array = {};"
10409 " }"
10410 "}"
10411 "sum;");
10412 i::Heap::CollectAllGarbage(false); // Force GC to trigger verification.
10413 CHECK_EQ(28, result->Int32Value());
10414
10415 // Make sure out-of-range loads do not throw.
10416 i::OS::SNPrintF(test_buf,
10417 "var caught_exception = false;"
10418 "try {"
10419 " ext_array[%d];"
10420 "} catch (e) {"
10421 " caught_exception = true;"
10422 "}"
10423 "caught_exception;",
10424 kElementCount);
10425 result = CompileRun(test_buf.start());
10426 CHECK_EQ(false, result->BooleanValue());
10427
10428 // Make sure out-of-range stores do not throw.
10429 i::OS::SNPrintF(test_buf,
10430 "var caught_exception = false;"
10431 "try {"
10432 " ext_array[%d] = 1;"
10433 "} catch (e) {"
10434 " caught_exception = true;"
10435 "}"
10436 "caught_exception;",
10437 kElementCount);
10438 result = CompileRun(test_buf.start());
10439 CHECK_EQ(false, result->BooleanValue());
10440
10441 // Check other boundary conditions, values and operations.
10442 result = CompileRun("for (var i = 0; i < 8; i++) {"
10443 " ext_array[7] = undefined;"
10444 "}"
10445 "ext_array[7];");
10446 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010447 CHECK_EQ(
10448 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010449
10450 result = CompileRun("for (var i = 0; i < 8; i++) {"
10451 " ext_array[6] = '2.3';"
10452 "}"
10453 "ext_array[6];");
10454 CHECK_EQ(2, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010455 CHECK_EQ(
10456 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
Steve Block3ce2e202009-11-05 08:53:23 +000010457
10458 if (array_type != v8::kExternalFloatArray) {
10459 // Though the specification doesn't state it, be explicit about
10460 // converting NaNs and +/-Infinity to zero.
10461 result = CompileRun("for (var i = 0; i < 8; i++) {"
10462 " ext_array[i] = 5;"
10463 "}"
10464 "for (var i = 0; i < 8; i++) {"
10465 " ext_array[i] = NaN;"
10466 "}"
10467 "ext_array[5];");
10468 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010469 CHECK_EQ(0,
10470 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010471
10472 result = CompileRun("for (var i = 0; i < 8; i++) {"
10473 " ext_array[i] = 5;"
10474 "}"
10475 "for (var i = 0; i < 8; i++) {"
10476 " ext_array[i] = Infinity;"
10477 "}"
10478 "ext_array[5];");
10479 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010480 CHECK_EQ(0,
10481 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010482
10483 result = CompileRun("for (var i = 0; i < 8; i++) {"
10484 " ext_array[i] = 5;"
10485 "}"
10486 "for (var i = 0; i < 8; i++) {"
10487 " ext_array[i] = -Infinity;"
10488 "}"
10489 "ext_array[5];");
10490 CHECK_EQ(0, result->Int32Value());
John Reck59135872010-11-02 12:39:01 -070010491 CHECK_EQ(0,
10492 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
Steve Block3ce2e202009-11-05 08:53:23 +000010493 }
10494
10495 result = CompileRun("ext_array[3] = 33;"
10496 "delete ext_array[3];"
10497 "ext_array[3];");
10498 CHECK_EQ(33, result->Int32Value());
10499
10500 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
10501 "ext_array[2] = 12; ext_array[3] = 13;"
10502 "ext_array.__defineGetter__('2',"
10503 "function() { return 120; });"
10504 "ext_array[2];");
10505 CHECK_EQ(12, result->Int32Value());
10506
10507 result = CompileRun("var js_array = new Array(40);"
10508 "js_array[0] = 77;"
10509 "js_array;");
10510 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10511
10512 result = CompileRun("ext_array[1] = 23;"
10513 "ext_array.__proto__ = [];"
10514 "js_array.__proto__ = ext_array;"
10515 "js_array.concat(ext_array);");
10516 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
10517 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
10518
10519 result = CompileRun("ext_array[1] = 23;");
10520 CHECK_EQ(23, result->Int32Value());
10521
Steve Blockd0582a62009-12-15 09:54:21 +000010522 // Test more complex manipulations which cause eax to contain values
10523 // that won't be completely overwritten by loads from the arrays.
10524 // This catches bugs in the instructions used for the KeyedLoadIC
10525 // for byte and word types.
10526 {
10527 const int kXSize = 300;
10528 const int kYSize = 300;
10529 const int kLargeElementCount = kXSize * kYSize * 4;
10530 ElementType* large_array_data =
10531 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
10532 i::Handle<ExternalArrayClass> large_array =
10533 i::Handle<ExternalArrayClass>::cast(
10534 i::Factory::NewExternalArray(kLargeElementCount,
10535 array_type,
10536 array_data));
10537 v8::Handle<v8::Object> large_obj = v8::Object::New();
10538 // Set the elements to be the external array.
10539 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
10540 array_type,
10541 kLargeElementCount);
10542 context->Global()->Set(v8_str("large_array"), large_obj);
10543 // Initialize contents of a few rows.
10544 for (int x = 0; x < 300; x++) {
10545 int row = 0;
10546 int offset = row * 300 * 4;
10547 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10548 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10549 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10550 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10551 row = 150;
10552 offset = row * 300 * 4;
10553 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10554 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10555 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10556 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10557 row = 298;
10558 offset = row * 300 * 4;
10559 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
10560 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
10561 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
10562 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
10563 }
10564 // The goal of the code below is to make "offset" large enough
10565 // that the computation of the index (which goes into eax) has
10566 // high bits set which will not be overwritten by a byte or short
10567 // load.
10568 result = CompileRun("var failed = false;"
10569 "var offset = 0;"
10570 "for (var i = 0; i < 300; i++) {"
10571 " if (large_array[4 * i] != 127 ||"
10572 " large_array[4 * i + 1] != 0 ||"
10573 " large_array[4 * i + 2] != 0 ||"
10574 " large_array[4 * i + 3] != 127) {"
10575 " failed = true;"
10576 " }"
10577 "}"
10578 "offset = 150 * 300 * 4;"
10579 "for (var i = 0; i < 300; i++) {"
10580 " if (large_array[offset + 4 * i] != 127 ||"
10581 " large_array[offset + 4 * i + 1] != 0 ||"
10582 " large_array[offset + 4 * i + 2] != 0 ||"
10583 " large_array[offset + 4 * i + 3] != 127) {"
10584 " failed = true;"
10585 " }"
10586 "}"
10587 "offset = 298 * 300 * 4;"
10588 "for (var i = 0; i < 300; i++) {"
10589 " if (large_array[offset + 4 * i] != 127 ||"
10590 " large_array[offset + 4 * i + 1] != 0 ||"
10591 " large_array[offset + 4 * i + 2] != 0 ||"
10592 " large_array[offset + 4 * i + 3] != 127) {"
10593 " failed = true;"
10594 " }"
10595 "}"
10596 "!failed;");
10597 CHECK_EQ(true, result->BooleanValue());
10598 free(large_array_data);
10599 }
10600
Steve Block3ce2e202009-11-05 08:53:23 +000010601 free(array_data);
10602}
10603
10604
10605THREADED_TEST(ExternalByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010606 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010607 v8::kExternalByteArray,
10608 -128,
10609 127);
10610}
10611
10612
10613THREADED_TEST(ExternalUnsignedByteArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010614 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010615 v8::kExternalUnsignedByteArray,
10616 0,
10617 255);
10618}
10619
10620
10621THREADED_TEST(ExternalShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010622 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010623 v8::kExternalShortArray,
10624 -32768,
10625 32767);
10626}
10627
10628
10629THREADED_TEST(ExternalUnsignedShortArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010630 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010631 v8::kExternalUnsignedShortArray,
10632 0,
10633 65535);
10634}
10635
10636
10637THREADED_TEST(ExternalIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010638 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010639 v8::kExternalIntArray,
10640 INT_MIN, // -2147483648
10641 INT_MAX); // 2147483647
10642}
10643
10644
10645THREADED_TEST(ExternalUnsignedIntArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010646 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
Steve Block3ce2e202009-11-05 08:53:23 +000010647 v8::kExternalUnsignedIntArray,
10648 0,
10649 UINT_MAX); // 4294967295
10650}
10651
10652
10653THREADED_TEST(ExternalFloatArray) {
Steve Block8defd9f2010-07-08 12:39:36 +010010654 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
Steve Block3ce2e202009-11-05 08:53:23 +000010655 v8::kExternalFloatArray,
10656 -500,
10657 500);
10658}
10659
10660
10661THREADED_TEST(ExternalArrays) {
10662 TestExternalByteArray();
10663 TestExternalUnsignedByteArray();
10664 TestExternalShortArray();
10665 TestExternalUnsignedShortArray();
10666 TestExternalIntArray();
10667 TestExternalUnsignedIntArray();
10668 TestExternalFloatArray();
10669}
10670
10671
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010672void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
10673 v8::HandleScope scope;
10674 LocalContext context;
10675 for (int size = 0; size < 100; size += 10) {
10676 int element_size = ExternalArrayElementSize(array_type);
10677 void* external_data = malloc(size * element_size);
10678 v8::Handle<v8::Object> obj = v8::Object::New();
10679 obj->SetIndexedPropertiesToExternalArrayData(
10680 external_data, array_type, size);
10681 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
10682 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
10683 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
10684 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
10685 free(external_data);
10686 }
10687}
10688
10689
10690THREADED_TEST(ExternalArrayInfo) {
10691 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
10692 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
10693 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
10694 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
10695 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
10696 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
10697 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
10698}
10699
10700
Steve Blocka7e24c12009-10-30 11:49:00 +000010701THREADED_TEST(ScriptContextDependence) {
10702 v8::HandleScope scope;
10703 LocalContext c1;
10704 const char *source = "foo";
10705 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
10706 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
10707 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
10708 CHECK_EQ(dep->Run()->Int32Value(), 100);
10709 CHECK_EQ(indep->Run()->Int32Value(), 100);
10710 LocalContext c2;
10711 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
10712 CHECK_EQ(dep->Run()->Int32Value(), 100);
10713 CHECK_EQ(indep->Run()->Int32Value(), 101);
10714}
10715
10716
10717THREADED_TEST(StackTrace) {
10718 v8::HandleScope scope;
10719 LocalContext context;
10720 v8::TryCatch try_catch;
10721 const char *source = "function foo() { FAIL.FAIL; }; foo();";
10722 v8::Handle<v8::String> src = v8::String::New(source);
10723 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
10724 v8::Script::New(src, origin)->Run();
10725 CHECK(try_catch.HasCaught());
10726 v8::String::Utf8Value stack(try_catch.StackTrace());
10727 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
10728}
10729
10730
Kristian Monsen25f61362010-05-21 11:50:48 +010010731// Checks that a StackFrame has certain expected values.
10732void checkStackFrame(const char* expected_script_name,
10733 const char* expected_func_name, int expected_line_number,
10734 int expected_column, bool is_eval, bool is_constructor,
10735 v8::Handle<v8::StackFrame> frame) {
10736 v8::HandleScope scope;
10737 v8::String::Utf8Value func_name(frame->GetFunctionName());
10738 v8::String::Utf8Value script_name(frame->GetScriptName());
10739 if (*script_name == NULL) {
10740 // The situation where there is no associated script, like for evals.
10741 CHECK(expected_script_name == NULL);
10742 } else {
10743 CHECK(strstr(*script_name, expected_script_name) != NULL);
10744 }
10745 CHECK(strstr(*func_name, expected_func_name) != NULL);
10746 CHECK_EQ(expected_line_number, frame->GetLineNumber());
10747 CHECK_EQ(expected_column, frame->GetColumn());
10748 CHECK_EQ(is_eval, frame->IsEval());
10749 CHECK_EQ(is_constructor, frame->IsConstructor());
10750}
10751
10752
10753v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
10754 v8::HandleScope scope;
10755 const char* origin = "capture-stack-trace-test";
10756 const int kOverviewTest = 1;
10757 const int kDetailedTest = 2;
10758
10759 ASSERT(args.Length() == 1);
10760
10761 int testGroup = args[0]->Int32Value();
10762 if (testGroup == kOverviewTest) {
10763 v8::Handle<v8::StackTrace> stackTrace =
10764 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
10765 CHECK_EQ(4, stackTrace->GetFrameCount());
10766 checkStackFrame(origin, "bar", 2, 10, false, false,
10767 stackTrace->GetFrame(0));
10768 checkStackFrame(origin, "foo", 6, 3, false, false,
10769 stackTrace->GetFrame(1));
10770 checkStackFrame(NULL, "", 1, 1, false, false,
10771 stackTrace->GetFrame(2));
10772 // The last frame is an anonymous function that has the initial call.
10773 checkStackFrame(origin, "", 8, 7, false, false,
10774 stackTrace->GetFrame(3));
10775
10776 CHECK(stackTrace->AsArray()->IsArray());
10777 } else if (testGroup == kDetailedTest) {
10778 v8::Handle<v8::StackTrace> stackTrace =
10779 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10780 CHECK_EQ(4, stackTrace->GetFrameCount());
10781 checkStackFrame(origin, "bat", 4, 22, false, false,
10782 stackTrace->GetFrame(0));
10783 checkStackFrame(origin, "baz", 8, 3, false, true,
10784 stackTrace->GetFrame(1));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010785#ifdef ENABLE_DEBUGGER_SUPPORT
10786 bool is_eval = true;
10787#else // ENABLE_DEBUGGER_SUPPORT
10788 bool is_eval = false;
10789#endif // ENABLE_DEBUGGER_SUPPORT
10790
10791 checkStackFrame(NULL, "", 1, 1, is_eval, false,
Kristian Monsen25f61362010-05-21 11:50:48 +010010792 stackTrace->GetFrame(2));
10793 // The last frame is an anonymous function that has the initial call to foo.
10794 checkStackFrame(origin, "", 10, 1, false, false,
10795 stackTrace->GetFrame(3));
10796
10797 CHECK(stackTrace->AsArray()->IsArray());
10798 }
10799 return v8::Undefined();
10800}
10801
10802
10803// Tests the C++ StackTrace API.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010804// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
10805// THREADED_TEST(CaptureStackTrace) {
10806TEST(CaptureStackTrace) {
Kristian Monsen25f61362010-05-21 11:50:48 +010010807 v8::HandleScope scope;
10808 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
10809 Local<ObjectTemplate> templ = ObjectTemplate::New();
10810 templ->Set(v8_str("AnalyzeStackInNativeCode"),
10811 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
10812 LocalContext context(0, templ);
10813
10814 // Test getting OVERVIEW information. Should ignore information that is not
10815 // script name, function name, line number, and column offset.
10816 const char *overview_source =
10817 "function bar() {\n"
10818 " var y; AnalyzeStackInNativeCode(1);\n"
10819 "}\n"
10820 "function foo() {\n"
10821 "\n"
10822 " bar();\n"
10823 "}\n"
10824 "var x;eval('new foo();');";
10825 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
10826 v8::Handle<Value> overview_result =
10827 v8::Script::New(overview_src, origin)->Run();
10828 ASSERT(!overview_result.IsEmpty());
10829 ASSERT(overview_result->IsObject());
10830
10831 // Test getting DETAILED information.
10832 const char *detailed_source =
10833 "function bat() {AnalyzeStackInNativeCode(2);\n"
10834 "}\n"
10835 "\n"
10836 "function baz() {\n"
10837 " bat();\n"
10838 "}\n"
10839 "eval('new baz();');";
10840 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
10841 // Make the script using a non-zero line and column offset.
10842 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
10843 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
10844 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
10845 v8::Handle<v8::Script> detailed_script(
10846 v8::Script::New(detailed_src, &detailed_origin));
10847 v8::Handle<Value> detailed_result = detailed_script->Run();
10848 ASSERT(!detailed_result.IsEmpty());
10849 ASSERT(detailed_result->IsObject());
10850}
10851
10852
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010853static void StackTraceForUncaughtExceptionListener(
10854 v8::Handle<v8::Message> message,
10855 v8::Handle<Value>) {
10856 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
10857 CHECK_EQ(2, stack_trace->GetFrameCount());
10858 checkStackFrame("origin", "foo", 2, 3, false, false,
10859 stack_trace->GetFrame(0));
10860 checkStackFrame("origin", "bar", 5, 3, false, false,
10861 stack_trace->GetFrame(1));
10862}
10863
10864TEST(CaptureStackTraceForUncaughtException) {
10865 report_count = 0;
10866 v8::HandleScope scope;
10867 LocalContext env;
10868 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
10869 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
10870
10871 Script::Compile(v8_str("function foo() {\n"
10872 " throw 1;\n"
10873 "};\n"
10874 "function bar() {\n"
10875 " foo();\n"
10876 "};"),
10877 v8_str("origin"))->Run();
10878 v8::Local<v8::Object> global = env->Global();
10879 Local<Value> trouble = global->Get(v8_str("bar"));
10880 CHECK(trouble->IsFunction());
10881 Function::Cast(*trouble)->Call(global, 0, NULL);
10882 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
10883 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
10884}
10885
10886
Ben Murdochf87a2032010-10-22 12:50:53 +010010887v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
10888 v8::HandleScope scope;
10889 v8::Handle<v8::StackTrace> stackTrace =
10890 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
10891 CHECK_EQ(5, stackTrace->GetFrameCount());
10892 v8::Handle<v8::String> url = v8_str("eval_url");
10893 for (int i = 0; i < 3; i++) {
10894 v8::Handle<v8::String> name =
10895 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
10896 CHECK(!name.IsEmpty());
10897 CHECK_EQ(url, name);
10898 }
10899 return v8::Undefined();
10900}
10901
10902
10903TEST(SourceURLInStackTrace) {
10904 v8::HandleScope scope;
10905 Local<ObjectTemplate> templ = ObjectTemplate::New();
10906 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
10907 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
10908 LocalContext context(0, templ);
10909
10910 const char *source =
10911 "function outer() {\n"
10912 "function bar() {\n"
10913 " AnalyzeStackOfEvalWithSourceURL();\n"
10914 "}\n"
10915 "function foo() {\n"
10916 "\n"
10917 " bar();\n"
10918 "}\n"
10919 "foo();\n"
10920 "}\n"
10921 "eval('(' + outer +')()//@ sourceURL=eval_url');";
10922 CHECK(CompileRun(source)->IsUndefined());
10923}
10924
10925
Steve Block3ce2e202009-11-05 08:53:23 +000010926// Test that idle notification can be handled and eventually returns true.
Steve Blocka7e24c12009-10-30 11:49:00 +000010927THREADED_TEST(IdleNotification) {
Steve Block3ce2e202009-11-05 08:53:23 +000010928 bool rv = false;
10929 for (int i = 0; i < 100; i++) {
10930 rv = v8::V8::IdleNotification();
10931 if (rv)
10932 break;
10933 }
10934 CHECK(rv == true);
Steve Blocka7e24c12009-10-30 11:49:00 +000010935}
10936
10937
10938static uint32_t* stack_limit;
10939
10940static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080010941 stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::real_climit());
Steve Blocka7e24c12009-10-30 11:49:00 +000010942 return v8::Undefined();
10943}
10944
10945
10946// Uses the address of a local variable to determine the stack top now.
10947// Given a size, returns an address that is that far from the current
10948// top of stack.
10949static uint32_t* ComputeStackLimit(uint32_t size) {
10950 uint32_t* answer = &size - (size / sizeof(size));
10951 // If the size is very large and the stack is very near the bottom of
10952 // memory then the calculation above may wrap around and give an address
10953 // that is above the (downwards-growing) stack. In that case we return
10954 // a very low address.
10955 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
10956 return answer;
10957}
10958
10959
10960TEST(SetResourceConstraints) {
10961 static const int K = 1024;
10962 uint32_t* set_limit = ComputeStackLimit(128 * K);
10963
10964 // Set stack limit.
10965 v8::ResourceConstraints constraints;
10966 constraints.set_stack_limit(set_limit);
10967 CHECK(v8::SetResourceConstraints(&constraints));
10968
10969 // Execute a script.
10970 v8::HandleScope scope;
10971 LocalContext env;
10972 Local<v8::FunctionTemplate> fun_templ =
10973 v8::FunctionTemplate::New(GetStackLimitCallback);
10974 Local<Function> fun = fun_templ->GetFunction();
10975 env->Global()->Set(v8_str("get_stack_limit"), fun);
10976 CompileRun("get_stack_limit();");
10977
10978 CHECK(stack_limit == set_limit);
10979}
10980
10981
10982TEST(SetResourceConstraintsInThread) {
10983 uint32_t* set_limit;
10984 {
10985 v8::Locker locker;
10986 static const int K = 1024;
10987 set_limit = ComputeStackLimit(128 * K);
10988
10989 // Set stack limit.
10990 v8::ResourceConstraints constraints;
10991 constraints.set_stack_limit(set_limit);
10992 CHECK(v8::SetResourceConstraints(&constraints));
10993
10994 // Execute a script.
10995 v8::HandleScope scope;
10996 LocalContext env;
10997 Local<v8::FunctionTemplate> fun_templ =
10998 v8::FunctionTemplate::New(GetStackLimitCallback);
10999 Local<Function> fun = fun_templ->GetFunction();
11000 env->Global()->Set(v8_str("get_stack_limit"), fun);
11001 CompileRun("get_stack_limit();");
11002
11003 CHECK(stack_limit == set_limit);
11004 }
11005 {
11006 v8::Locker locker;
11007 CHECK(stack_limit == set_limit);
11008 }
11009}
Steve Block3ce2e202009-11-05 08:53:23 +000011010
11011
11012THREADED_TEST(GetHeapStatistics) {
11013 v8::HandleScope scope;
11014 LocalContext c1;
11015 v8::HeapStatistics heap_statistics;
Steve Blockd0582a62009-12-15 09:54:21 +000011016 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
11017 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
Steve Block3ce2e202009-11-05 08:53:23 +000011018 v8::V8::GetHeapStatistics(&heap_statistics);
Steve Blockd0582a62009-12-15 09:54:21 +000011019 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
11020 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
11021}
11022
11023
11024static double DoubleFromBits(uint64_t value) {
11025 double target;
11026#ifdef BIG_ENDIAN_FLOATING_POINT
11027 const int kIntSize = 4;
11028 // Somebody swapped the lower and higher half of doubles.
11029 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11030 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11031#else
11032 memcpy(&target, &value, sizeof(target));
11033#endif
11034 return target;
11035}
11036
11037
11038static uint64_t DoubleToBits(double value) {
11039 uint64_t target;
11040#ifdef BIG_ENDIAN_FLOATING_POINT
11041 const int kIntSize = 4;
11042 // Somebody swapped the lower and higher half of doubles.
11043 memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
11044 memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
11045#else
11046 memcpy(&target, &value, sizeof(target));
11047#endif
11048 return target;
11049}
11050
11051
11052static double DoubleToDateTime(double input) {
11053 double date_limit = 864e13;
11054 if (IsNaN(input) || input < -date_limit || input > date_limit) {
11055 return i::OS::nan_value();
11056 }
11057 return (input < 0) ? -(floor(-input)) : floor(input);
11058}
11059
11060// We don't have a consistent way to write 64-bit constants syntactically, so we
11061// split them into two 32-bit constants and combine them programmatically.
11062static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
11063 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
11064}
11065
11066
11067THREADED_TEST(QuietSignalingNaNs) {
11068 v8::HandleScope scope;
11069 LocalContext context;
11070 v8::TryCatch try_catch;
11071
11072 // Special double values.
11073 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
11074 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
11075 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
11076 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
11077 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
11078 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
11079 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
11080
11081 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
11082 // on either side of the epoch.
11083 double date_limit = 864e13;
11084
11085 double test_values[] = {
11086 snan,
11087 qnan,
11088 infinity,
11089 max_normal,
11090 date_limit + 1,
11091 date_limit,
11092 min_normal,
11093 max_denormal,
11094 min_denormal,
11095 0,
11096 -0,
11097 -min_denormal,
11098 -max_denormal,
11099 -min_normal,
11100 -date_limit,
11101 -date_limit - 1,
11102 -max_normal,
11103 -infinity,
11104 -qnan,
11105 -snan
11106 };
11107 int num_test_values = 20;
11108
11109 for (int i = 0; i < num_test_values; i++) {
11110 double test_value = test_values[i];
11111
11112 // Check that Number::New preserves non-NaNs and quiets SNaNs.
11113 v8::Handle<v8::Value> number = v8::Number::New(test_value);
11114 double stored_number = number->NumberValue();
11115 if (!IsNaN(test_value)) {
11116 CHECK_EQ(test_value, stored_number);
11117 } else {
11118 uint64_t stored_bits = DoubleToBits(stored_number);
11119 // Check if quiet nan (bits 51..62 all set).
11120 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11121 }
11122
11123 // Check that Date::New preserves non-NaNs in the date range and
11124 // quiets SNaNs.
11125 v8::Handle<v8::Value> date = v8::Date::New(test_value);
11126 double expected_stored_date = DoubleToDateTime(test_value);
11127 double stored_date = date->NumberValue();
11128 if (!IsNaN(expected_stored_date)) {
11129 CHECK_EQ(expected_stored_date, stored_date);
11130 } else {
11131 uint64_t stored_bits = DoubleToBits(stored_date);
11132 // Check if quiet nan (bits 51..62 all set).
11133 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
11134 }
11135 }
11136}
11137
11138
11139static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
11140 v8::HandleScope scope;
11141 v8::TryCatch tc;
11142 v8::Handle<v8::String> str = args[0]->ToString();
11143 if (tc.HasCaught())
11144 return tc.ReThrow();
11145 return v8::Undefined();
11146}
11147
11148
11149// Test that an exception can be propagated down through a spaghetti
11150// stack using ReThrow.
11151THREADED_TEST(SpaghettiStackReThrow) {
11152 v8::HandleScope scope;
11153 LocalContext context;
11154 context->Global()->Set(
11155 v8::String::New("s"),
11156 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
11157 v8::TryCatch try_catch;
11158 CompileRun(
11159 "var i = 0;"
11160 "var o = {"
11161 " toString: function () {"
11162 " if (i == 10) {"
11163 " throw 'Hey!';"
11164 " } else {"
11165 " i++;"
11166 " return s(o);"
11167 " }"
11168 " }"
11169 "};"
11170 "s(o);");
11171 CHECK(try_catch.HasCaught());
11172 v8::String::Utf8Value value(try_catch.Exception());
11173 CHECK_EQ(0, strcmp(*value, "Hey!"));
11174}
11175
11176
Steve Blockd0582a62009-12-15 09:54:21 +000011177TEST(Regress528) {
11178 v8::V8::Initialize();
11179
11180 v8::HandleScope scope;
11181 v8::Persistent<Context> context;
11182 v8::Persistent<Context> other_context;
11183 int gc_count;
11184
11185 // Create a context used to keep the code from aging in the compilation
11186 // cache.
11187 other_context = Context::New();
11188
11189 // Context-dependent context data creates reference from the compilation
11190 // cache to the global object.
11191 const char* source_simple = "1";
11192 context = Context::New();
11193 {
11194 v8::HandleScope scope;
11195
11196 context->Enter();
11197 Local<v8::String> obj = v8::String::New("");
11198 context->SetData(obj);
11199 CompileRun(source_simple);
11200 context->Exit();
11201 }
11202 context.Dispose();
11203 for (gc_count = 1; gc_count < 10; gc_count++) {
11204 other_context->Enter();
11205 CompileRun(source_simple);
11206 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011207 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011208 if (GetGlobalObjectsCount() == 1) break;
11209 }
11210 CHECK_GE(2, gc_count);
11211 CHECK_EQ(1, GetGlobalObjectsCount());
11212
11213 // Eval in a function creates reference from the compilation cache to the
11214 // global object.
11215 const char* source_eval = "function f(){eval('1')}; f()";
11216 context = Context::New();
11217 {
11218 v8::HandleScope scope;
11219
11220 context->Enter();
11221 CompileRun(source_eval);
11222 context->Exit();
11223 }
11224 context.Dispose();
11225 for (gc_count = 1; gc_count < 10; gc_count++) {
11226 other_context->Enter();
11227 CompileRun(source_eval);
11228 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011229 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011230 if (GetGlobalObjectsCount() == 1) break;
11231 }
11232 CHECK_GE(2, gc_count);
11233 CHECK_EQ(1, GetGlobalObjectsCount());
11234
11235 // Looking up the line number for an exception creates reference from the
11236 // compilation cache to the global object.
11237 const char* source_exception = "function f(){throw 1;} f()";
11238 context = Context::New();
11239 {
11240 v8::HandleScope scope;
11241
11242 context->Enter();
11243 v8::TryCatch try_catch;
11244 CompileRun(source_exception);
11245 CHECK(try_catch.HasCaught());
11246 v8::Handle<v8::Message> message = try_catch.Message();
11247 CHECK(!message.IsEmpty());
11248 CHECK_EQ(1, message->GetLineNumber());
11249 context->Exit();
11250 }
11251 context.Dispose();
11252 for (gc_count = 1; gc_count < 10; gc_count++) {
11253 other_context->Enter();
11254 CompileRun(source_exception);
11255 other_context->Exit();
Steve Block8defd9f2010-07-08 12:39:36 +010011256 i::Heap::CollectAllGarbage(false);
Steve Blockd0582a62009-12-15 09:54:21 +000011257 if (GetGlobalObjectsCount() == 1) break;
11258 }
11259 CHECK_GE(2, gc_count);
11260 CHECK_EQ(1, GetGlobalObjectsCount());
11261
11262 other_context.Dispose();
Steve Block3ce2e202009-11-05 08:53:23 +000011263}
Andrei Popescu402d9372010-02-26 13:31:12 +000011264
11265
11266THREADED_TEST(ScriptOrigin) {
11267 v8::HandleScope scope;
11268 LocalContext env;
11269 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11270 v8::Handle<v8::String> script = v8::String::New(
11271 "function f() {}\n\nfunction g() {}");
11272 v8::Script::Compile(script, &origin)->Run();
11273 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11274 env->Global()->Get(v8::String::New("f")));
11275 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11276 env->Global()->Get(v8::String::New("g")));
11277
11278 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
11279 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
11280 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
11281
11282 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
11283 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
11284 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
11285}
11286
11287
11288THREADED_TEST(ScriptLineNumber) {
11289 v8::HandleScope scope;
11290 LocalContext env;
11291 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
11292 v8::Handle<v8::String> script = v8::String::New(
11293 "function f() {}\n\nfunction g() {}");
11294 v8::Script::Compile(script, &origin)->Run();
11295 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
11296 env->Global()->Get(v8::String::New("f")));
11297 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
11298 env->Global()->Get(v8::String::New("g")));
11299 CHECK_EQ(0, f->GetScriptLineNumber());
11300 CHECK_EQ(2, g->GetScriptLineNumber());
11301}
11302
11303
11304static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
11305 const AccessorInfo& info) {
11306 return v8_num(42);
11307}
11308
11309
11310static void SetterWhichSetsYOnThisTo23(Local<String> name,
11311 Local<Value> value,
11312 const AccessorInfo& info) {
11313 info.This()->Set(v8_str("y"), v8_num(23));
11314}
11315
11316
Steve Block6ded16b2010-05-10 14:33:55 +010011317TEST(SetterOnConstructorPrototype) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011318 v8::HandleScope scope;
11319 Local<ObjectTemplate> templ = ObjectTemplate::New();
11320 templ->SetAccessor(v8_str("x"),
11321 GetterWhichReturns42,
11322 SetterWhichSetsYOnThisTo23);
11323 LocalContext context;
11324 context->Global()->Set(v8_str("P"), templ->NewInstance());
11325 CompileRun("function C1() {"
11326 " this.x = 23;"
11327 "};"
11328 "C1.prototype = P;"
11329 "function C2() {"
11330 " this.x = 23"
11331 "};"
11332 "C2.prototype = { };"
11333 "C2.prototype.__proto__ = P;");
11334
11335 v8::Local<v8::Script> script;
11336 script = v8::Script::Compile(v8_str("new C1();"));
11337 for (int i = 0; i < 10; i++) {
11338 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11339 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11340 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11341 }
11342
11343 script = v8::Script::Compile(v8_str("new C2();"));
11344 for (int i = 0; i < 10; i++) {
11345 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11346 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
11347 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
11348 }
11349}
11350
11351
11352static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
11353 Local<String> name, const AccessorInfo& info) {
11354 return v8_num(42);
11355}
11356
11357
11358static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
11359 Local<String> name, Local<Value> value, const AccessorInfo& info) {
11360 if (name->Equals(v8_str("x"))) {
11361 info.This()->Set(v8_str("y"), v8_num(23));
11362 }
11363 return v8::Handle<Value>();
11364}
11365
11366
11367THREADED_TEST(InterceptorOnConstructorPrototype) {
11368 v8::HandleScope scope;
11369 Local<ObjectTemplate> templ = ObjectTemplate::New();
11370 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
11371 NamedPropertySetterWhichSetsYOnThisTo23);
11372 LocalContext context;
11373 context->Global()->Set(v8_str("P"), templ->NewInstance());
11374 CompileRun("function C1() {"
11375 " this.x = 23;"
11376 "};"
11377 "C1.prototype = P;"
11378 "function C2() {"
11379 " this.x = 23"
11380 "};"
11381 "C2.prototype = { };"
11382 "C2.prototype.__proto__ = P;");
11383
11384 v8::Local<v8::Script> script;
11385 script = v8::Script::Compile(v8_str("new C1();"));
11386 for (int i = 0; i < 10; i++) {
11387 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11388 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11389 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11390 }
11391
11392 script = v8::Script::Compile(v8_str("new C2();"));
11393 for (int i = 0; i < 10; i++) {
11394 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
11395 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
11396 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
11397 }
11398}
Steve Block6ded16b2010-05-10 14:33:55 +010011399
11400
11401TEST(Bug618) {
11402 const char* source = "function C1() {"
11403 " this.x = 23;"
11404 "};"
11405 "C1.prototype = P;";
11406
11407 v8::HandleScope scope;
11408 LocalContext context;
11409 v8::Local<v8::Script> script;
11410
11411 // Use a simple object as prototype.
11412 v8::Local<v8::Object> prototype = v8::Object::New();
11413 prototype->Set(v8_str("y"), v8_num(42));
11414 context->Global()->Set(v8_str("P"), prototype);
11415
11416 // This compile will add the code to the compilation cache.
11417 CompileRun(source);
11418
11419 script = v8::Script::Compile(v8_str("new C1();"));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011420 // Allow enough iterations for the inobject slack tracking logic
11421 // to finalize instance size and install the fast construct stub.
11422 for (int i = 0; i < 256; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +010011423 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11424 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
11425 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
11426 }
11427
11428 // Use an API object with accessors as prototype.
11429 Local<ObjectTemplate> templ = ObjectTemplate::New();
11430 templ->SetAccessor(v8_str("x"),
11431 GetterWhichReturns42,
11432 SetterWhichSetsYOnThisTo23);
11433 context->Global()->Set(v8_str("P"), templ->NewInstance());
11434
11435 // This compile will get the code from the compilation cache.
11436 CompileRun(source);
11437
11438 script = v8::Script::Compile(v8_str("new C1();"));
11439 for (int i = 0; i < 10; i++) {
11440 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
11441 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
11442 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
11443 }
11444}
11445
11446int prologue_call_count = 0;
11447int epilogue_call_count = 0;
11448int prologue_call_count_second = 0;
11449int epilogue_call_count_second = 0;
11450
11451void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
11452 ++prologue_call_count;
11453}
11454
11455void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
11456 ++epilogue_call_count;
11457}
11458
11459void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11460 ++prologue_call_count_second;
11461}
11462
11463void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
11464 ++epilogue_call_count_second;
11465}
11466
11467TEST(GCCallbacks) {
11468 LocalContext context;
11469
11470 v8::V8::AddGCPrologueCallback(PrologueCallback);
11471 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
11472 CHECK_EQ(0, prologue_call_count);
11473 CHECK_EQ(0, epilogue_call_count);
11474 i::Heap::CollectAllGarbage(false);
11475 CHECK_EQ(1, prologue_call_count);
11476 CHECK_EQ(1, epilogue_call_count);
11477 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
11478 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
11479 i::Heap::CollectAllGarbage(false);
11480 CHECK_EQ(2, prologue_call_count);
11481 CHECK_EQ(2, epilogue_call_count);
11482 CHECK_EQ(1, prologue_call_count_second);
11483 CHECK_EQ(1, epilogue_call_count_second);
11484 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
11485 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
11486 i::Heap::CollectAllGarbage(false);
11487 CHECK_EQ(2, prologue_call_count);
11488 CHECK_EQ(2, epilogue_call_count);
11489 CHECK_EQ(2, prologue_call_count_second);
11490 CHECK_EQ(2, epilogue_call_count_second);
11491 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
11492 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
11493 i::Heap::CollectAllGarbage(false);
11494 CHECK_EQ(2, prologue_call_count);
11495 CHECK_EQ(2, epilogue_call_count);
11496 CHECK_EQ(2, prologue_call_count_second);
11497 CHECK_EQ(2, epilogue_call_count_second);
11498}
Kristian Monsen25f61362010-05-21 11:50:48 +010011499
11500
11501THREADED_TEST(AddToJSFunctionResultCache) {
11502 i::FLAG_allow_natives_syntax = true;
11503 v8::HandleScope scope;
11504
11505 LocalContext context;
11506
11507 const char* code =
11508 "(function() {"
11509 " var key0 = 'a';"
11510 " var key1 = 'b';"
11511 " var r0 = %_GetFromCache(0, key0);"
11512 " var r1 = %_GetFromCache(0, key1);"
11513 " var r0_ = %_GetFromCache(0, key0);"
11514 " if (r0 !== r0_)"
11515 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
11516 " var r1_ = %_GetFromCache(0, key1);"
11517 " if (r1 !== r1_)"
11518 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
11519 " return 'PASSED';"
11520 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011521 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011522 ExpectString(code, "PASSED");
11523}
11524
11525
11526static const int k0CacheSize = 16;
11527
11528THREADED_TEST(FillJSFunctionResultCache) {
11529 i::FLAG_allow_natives_syntax = true;
11530 v8::HandleScope scope;
11531
11532 LocalContext context;
11533
11534 const char* code =
11535 "(function() {"
11536 " var k = 'a';"
11537 " var r = %_GetFromCache(0, k);"
11538 " for (var i = 0; i < 16; i++) {"
11539 " %_GetFromCache(0, 'a' + i);"
11540 " };"
11541 " if (r === %_GetFromCache(0, k))"
11542 " return 'FAILED: k0CacheSize is too small';"
11543 " return 'PASSED';"
11544 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011545 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011546 ExpectString(code, "PASSED");
11547}
11548
11549
11550THREADED_TEST(RoundRobinGetFromCache) {
11551 i::FLAG_allow_natives_syntax = true;
11552 v8::HandleScope scope;
11553
11554 LocalContext context;
11555
11556 const char* code =
11557 "(function() {"
11558 " var keys = [];"
11559 " for (var i = 0; i < 16; i++) keys.push(i);"
11560 " var values = [];"
11561 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11562 " for (var i = 0; i < 16; i++) {"
11563 " var v = %_GetFromCache(0, keys[i]);"
11564 " if (v !== values[i])"
11565 " return 'Wrong value for ' + "
11566 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11567 " };"
11568 " return 'PASSED';"
11569 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011570 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011571 ExpectString(code, "PASSED");
11572}
11573
11574
11575THREADED_TEST(ReverseGetFromCache) {
11576 i::FLAG_allow_natives_syntax = true;
11577 v8::HandleScope scope;
11578
11579 LocalContext context;
11580
11581 const char* code =
11582 "(function() {"
11583 " var keys = [];"
11584 " for (var i = 0; i < 16; i++) keys.push(i);"
11585 " var values = [];"
11586 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
11587 " for (var i = 15; i >= 16; i--) {"
11588 " var v = %_GetFromCache(0, keys[i]);"
11589 " if (v !== values[i])"
11590 " return 'Wrong value for ' + "
11591 " keys[i] + ': ' + v + ' vs. ' + values[i];"
11592 " };"
11593 " return 'PASSED';"
11594 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011595 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011596 ExpectString(code, "PASSED");
11597}
11598
11599
11600THREADED_TEST(TestEviction) {
11601 i::FLAG_allow_natives_syntax = true;
11602 v8::HandleScope scope;
11603
11604 LocalContext context;
11605
11606 const char* code =
11607 "(function() {"
11608 " for (var i = 0; i < 2*16; i++) {"
11609 " %_GetFromCache(0, 'a' + i);"
11610 " };"
11611 " return 'PASSED';"
11612 "})()";
Steve Block8defd9f2010-07-08 12:39:36 +010011613 i::Heap::ClearJSFunctionResultCaches();
Kristian Monsen25f61362010-05-21 11:50:48 +010011614 ExpectString(code, "PASSED");
11615}
Steve Block8defd9f2010-07-08 12:39:36 +010011616
11617
11618THREADED_TEST(TwoByteStringInAsciiCons) {
11619 // See Chromium issue 47824.
11620 v8::HandleScope scope;
11621
11622 LocalContext context;
11623 const char* init_code =
11624 "var str1 = 'abelspendabel';"
11625 "var str2 = str1 + str1 + str1;"
11626 "str2;";
11627 Local<Value> result = CompileRun(init_code);
11628
11629 CHECK(result->IsString());
11630 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
11631 int length = string->length();
11632 CHECK(string->IsAsciiRepresentation());
11633
11634 FlattenString(string);
11635 i::Handle<i::String> flat_string = FlattenGetString(string);
11636
11637 CHECK(string->IsAsciiRepresentation());
11638 CHECK(flat_string->IsAsciiRepresentation());
11639
11640 // Create external resource.
11641 uint16_t* uc16_buffer = new uint16_t[length + 1];
11642
11643 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
11644 uc16_buffer[length] = 0;
11645
11646 TestResource resource(uc16_buffer);
11647
11648 flat_string->MakeExternal(&resource);
11649
11650 CHECK(flat_string->IsTwoByteRepresentation());
11651
11652 // At this point, we should have a Cons string which is flat and ASCII,
11653 // with a first half that is a two-byte string (although it only contains
11654 // ASCII characters). This is a valid sequence of steps, and it can happen
11655 // in real pages.
11656
11657 CHECK(string->IsAsciiRepresentation());
11658 i::ConsString* cons = i::ConsString::cast(*string);
11659 CHECK_EQ(0, cons->second()->length());
11660 CHECK(cons->first()->IsTwoByteRepresentation());
11661
11662 // Check that some string operations work.
11663
11664 // Atom RegExp.
11665 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
11666 CHECK_EQ(6, reresult->Int32Value());
11667
11668 // Nonatom RegExp.
11669 reresult = CompileRun("str2.match(/abe./g).length;");
11670 CHECK_EQ(6, reresult->Int32Value());
11671
11672 reresult = CompileRun("str2.search(/bel/g);");
11673 CHECK_EQ(1, reresult->Int32Value());
11674
11675 reresult = CompileRun("str2.search(/be./g);");
11676 CHECK_EQ(1, reresult->Int32Value());
11677
11678 ExpectTrue("/bel/g.test(str2);");
11679
11680 ExpectTrue("/be./g.test(str2);");
11681
11682 reresult = CompileRun("/bel/g.exec(str2);");
11683 CHECK(!reresult->IsNull());
11684
11685 reresult = CompileRun("/be./g.exec(str2);");
11686 CHECK(!reresult->IsNull());
11687
11688 ExpectString("str2.substring(2, 10);", "elspenda");
11689
11690 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
11691
11692 ExpectString("str2.charAt(2);", "e");
11693
11694 reresult = CompileRun("str2.charCodeAt(2);");
11695 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
11696}
Iain Merrick75681382010-08-19 15:07:18 +010011697
11698
11699// Failed access check callback that performs a GC on each invocation.
11700void FailedAccessCheckCallbackGC(Local<v8::Object> target,
11701 v8::AccessType type,
11702 Local<v8::Value> data) {
11703 i::Heap::CollectAllGarbage(true);
11704}
11705
11706
11707TEST(GCInFailedAccessCheckCallback) {
11708 // Install a failed access check callback that performs a GC on each
11709 // invocation. Then force the callback to be called from va
11710
11711 v8::V8::Initialize();
11712 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
11713
11714 v8::HandleScope scope;
11715
11716 // Create an ObjectTemplate for global objects and install access
11717 // check callbacks that will block access.
11718 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
11719 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
11720 IndexedGetAccessBlocker,
11721 v8::Handle<v8::Value>(),
11722 false);
11723
11724 // Create a context and set an x property on it's global object.
11725 LocalContext context0(NULL, global_template);
11726 context0->Global()->Set(v8_str("x"), v8_num(42));
11727 v8::Handle<v8::Object> global0 = context0->Global();
11728
11729 // Create a context with a different security token so that the
11730 // failed access check callback will be called on each access.
11731 LocalContext context1(NULL, global_template);
11732 context1->Global()->Set(v8_str("other"), global0);
11733
11734 // Get property with failed access check.
11735 ExpectUndefined("other.x");
11736
11737 // Get element with failed access check.
11738 ExpectUndefined("other[0]");
11739
11740 // Set property with failed access check.
11741 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
11742 CHECK(result->IsObject());
11743
11744 // Set element with failed access check.
11745 result = CompileRun("other[0] = new Object()");
11746 CHECK(result->IsObject());
11747
11748 // Get property attribute with failed access check.
11749 ExpectFalse("\'x\' in other");
11750
11751 // Get property attribute for element with failed access check.
11752 ExpectFalse("0 in other");
11753
11754 // Delete property.
11755 ExpectFalse("delete other.x");
11756
11757 // Delete element.
11758 CHECK_EQ(false, global0->Delete(0));
11759
11760 // DefineAccessor.
11761 CHECK_EQ(false,
11762 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
11763
11764 // Define JavaScript accessor.
11765 ExpectUndefined("Object.prototype.__defineGetter__.call("
11766 " other, \'x\', function() { return 42; })");
11767
11768 // LookupAccessor.
11769 ExpectUndefined("Object.prototype.__lookupGetter__.call("
11770 " other, \'x\')");
11771
11772 // HasLocalElement.
11773 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
11774
11775 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
11776 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
11777 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
11778
11779 // Reset the failed access check callback so it does not influence
11780 // the other tests.
11781 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
11782}
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011783
11784
11785TEST(StringCheckMultipleContexts) {
11786 const char* code =
11787 "(function() { return \"a\".charAt(0); })()";
11788
11789 {
11790 // Run the code twice in the first context to initialize the call IC.
11791 v8::HandleScope scope;
11792 LocalContext context1;
11793 ExpectString(code, "a");
11794 ExpectString(code, "a");
11795 }
11796
11797 {
11798 // Change the String.prototype in the second context and check
11799 // that the right function gets called.
11800 v8::HandleScope scope;
11801 LocalContext context2;
11802 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
11803 ExpectString(code, "not a");
11804 }
11805}
11806
11807
11808TEST(NumberCheckMultipleContexts) {
11809 const char* code =
11810 "(function() { return (42).toString(); })()";
11811
11812 {
11813 // Run the code twice in the first context to initialize the call IC.
11814 v8::HandleScope scope;
11815 LocalContext context1;
11816 ExpectString(code, "42");
11817 ExpectString(code, "42");
11818 }
11819
11820 {
11821 // Change the Number.prototype in the second context and check
11822 // that the right function gets called.
11823 v8::HandleScope scope;
11824 LocalContext context2;
11825 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
11826 ExpectString(code, "not 42");
11827 }
11828}
11829
11830
11831TEST(BooleanCheckMultipleContexts) {
11832 const char* code =
11833 "(function() { return true.toString(); })()";
11834
11835 {
11836 // Run the code twice in the first context to initialize the call IC.
11837 v8::HandleScope scope;
11838 LocalContext context1;
11839 ExpectString(code, "true");
11840 ExpectString(code, "true");
11841 }
11842
11843 {
11844 // Change the Boolean.prototype in the second context and check
11845 // that the right function gets called.
11846 v8::HandleScope scope;
11847 LocalContext context2;
11848 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
11849 ExpectString(code, "");
11850 }
11851}
Ben Murdochf87a2032010-10-22 12:50:53 +010011852
11853
11854TEST(DontDeleteCellLoadIC) {
11855 const char* function_code =
11856 "function readCell() { while (true) { return cell; } }";
11857
11858 {
11859 // Run the code twice in the first context to initialize the load
11860 // IC for a don't delete cell.
11861 v8::HandleScope scope;
11862 LocalContext context1;
11863 CompileRun("var cell = \"first\";");
11864 ExpectBoolean("delete cell", false);
11865 CompileRun(function_code);
11866 ExpectString("readCell()", "first");
11867 ExpectString("readCell()", "first");
11868 }
11869
11870 {
11871 // Use a deletable cell in the second context.
11872 v8::HandleScope scope;
11873 LocalContext context2;
11874 CompileRun("cell = \"second\";");
11875 CompileRun(function_code);
11876 ExpectString("readCell()", "second");
11877 ExpectBoolean("delete cell", true);
11878 ExpectString("(function() {"
11879 " try {"
11880 " return readCell();"
11881 " } catch(e) {"
11882 " return e.toString();"
11883 " }"
11884 "})()",
11885 "ReferenceError: cell is not defined");
11886 CompileRun("cell = \"new_second\";");
11887 i::Heap::CollectAllGarbage(true);
11888 ExpectString("readCell()", "new_second");
11889 ExpectString("readCell()", "new_second");
11890 }
11891}
11892
11893
11894TEST(DontDeleteCellLoadICForceDelete) {
11895 const char* function_code =
11896 "function readCell() { while (true) { return cell; } }";
11897
11898 // Run the code twice to initialize the load IC for a don't delete
11899 // cell.
11900 v8::HandleScope scope;
11901 LocalContext context;
11902 CompileRun("var cell = \"value\";");
11903 ExpectBoolean("delete cell", false);
11904 CompileRun(function_code);
11905 ExpectString("readCell()", "value");
11906 ExpectString("readCell()", "value");
11907
11908 // Delete the cell using the API and check the inlined code works
11909 // correctly.
11910 CHECK(context->Global()->ForceDelete(v8_str("cell")));
11911 ExpectString("(function() {"
11912 " try {"
11913 " return readCell();"
11914 " } catch(e) {"
11915 " return e.toString();"
11916 " }"
11917 "})()",
11918 "ReferenceError: cell is not defined");
11919}
11920
11921
11922TEST(DontDeleteCellLoadICAPI) {
11923 const char* function_code =
11924 "function readCell() { while (true) { return cell; } }";
11925
11926 // Run the code twice to initialize the load IC for a don't delete
11927 // cell created using the API.
11928 v8::HandleScope scope;
11929 LocalContext context;
11930 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
11931 ExpectBoolean("delete cell", false);
11932 CompileRun(function_code);
11933 ExpectString("readCell()", "value");
11934 ExpectString("readCell()", "value");
11935
11936 // Delete the cell using the API and check the inlined code works
11937 // correctly.
11938 CHECK(context->Global()->ForceDelete(v8_str("cell")));
11939 ExpectString("(function() {"
11940 " try {"
11941 " return readCell();"
11942 " } catch(e) {"
11943 " return e.toString();"
11944 " }"
11945 "})()",
11946 "ReferenceError: cell is not defined");
11947}
11948
11949
11950TEST(GlobalLoadICGC) {
11951 const char* function_code =
11952 "function readCell() { while (true) { return cell; } }";
11953
11954 // Check inline load code for a don't delete cell is cleared during
11955 // GC.
11956 {
11957 v8::HandleScope scope;
11958 LocalContext context;
11959 CompileRun("var cell = \"value\";");
11960 ExpectBoolean("delete cell", false);
11961 CompileRun(function_code);
11962 ExpectString("readCell()", "value");
11963 ExpectString("readCell()", "value");
11964 }
11965 {
11966 v8::HandleScope scope;
11967 LocalContext context2;
11968 // Hold the code object in the second context.
11969 CompileRun(function_code);
11970 CheckSurvivingGlobalObjectsCount(1);
11971 }
11972
11973 // Check inline load code for a deletable cell is cleared during GC.
11974 {
11975 v8::HandleScope scope;
11976 LocalContext context;
11977 CompileRun("cell = \"value\";");
11978 CompileRun(function_code);
11979 ExpectString("readCell()", "value");
11980 ExpectString("readCell()", "value");
11981 }
11982 {
11983 v8::HandleScope scope;
11984 LocalContext context2;
11985 // Hold the code object in the second context.
11986 CompileRun(function_code);
11987 CheckSurvivingGlobalObjectsCount(1);
11988 }
11989}
11990
11991
11992TEST(RegExp) {
11993 v8::HandleScope scope;
11994 LocalContext context;
11995
11996 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
11997 CHECK(re->IsRegExp());
11998 CHECK(re->GetSource()->Equals(v8_str("foo")));
11999 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12000
12001 re = v8::RegExp::New(v8_str("bar"),
12002 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12003 v8::RegExp::kGlobal));
12004 CHECK(re->IsRegExp());
12005 CHECK(re->GetSource()->Equals(v8_str("bar")));
12006 CHECK_EQ(static_cast<int>(re->GetFlags()),
12007 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
12008
12009 re = v8::RegExp::New(v8_str("baz"),
12010 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12011 v8::RegExp::kMultiline));
12012 CHECK(re->IsRegExp());
12013 CHECK(re->GetSource()->Equals(v8_str("baz")));
12014 CHECK_EQ(static_cast<int>(re->GetFlags()),
12015 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12016
12017 re = CompileRun("/quux/").As<v8::RegExp>();
12018 CHECK(re->IsRegExp());
12019 CHECK(re->GetSource()->Equals(v8_str("quux")));
12020 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12021
12022 re = CompileRun("/quux/gm").As<v8::RegExp>();
12023 CHECK(re->IsRegExp());
12024 CHECK(re->GetSource()->Equals(v8_str("quux")));
12025 CHECK_EQ(static_cast<int>(re->GetFlags()),
12026 v8::RegExp::kGlobal | v8::RegExp::kMultiline);
12027
12028 // Override the RegExp constructor and check the API constructor
12029 // still works.
12030 CompileRun("RegExp = function() {}");
12031
12032 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
12033 CHECK(re->IsRegExp());
12034 CHECK(re->GetSource()->Equals(v8_str("foobar")));
12035 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
12036
12037 re = v8::RegExp::New(v8_str("foobarbaz"),
12038 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
12039 v8::RegExp::kMultiline));
12040 CHECK(re->IsRegExp());
12041 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
12042 CHECK_EQ(static_cast<int>(re->GetFlags()),
12043 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
12044
12045 context->Global()->Set(v8_str("re"), re);
12046 ExpectTrue("re.test('FoobarbaZ')");
12047
12048 v8::TryCatch try_catch;
12049 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
12050 CHECK(re.IsEmpty());
12051 CHECK(try_catch.HasCaught());
12052 context->Global()->Set(v8_str("ex"), try_catch.Exception());
12053 ExpectTrue("ex instanceof SyntaxError");
12054}
12055
12056
12057static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
12058 const v8::AccessorInfo& info ) {
12059 return v8_str("42!");
12060}
12061
12062
12063static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
12064 v8::Handle<v8::Array> result = v8::Array::New();
12065 result->Set(0, v8_str("universalAnswer"));
12066 return result;
12067}
12068
12069
12070TEST(NamedEnumeratorAndForIn) {
12071 v8::HandleScope handle_scope;
12072 LocalContext context;
12073 v8::Context::Scope context_scope(context.local());
12074
12075 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
12076 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
12077 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
12078 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
12079 "var result = []; for (var k in o) result.push(k); result"));
12080 CHECK_EQ(1, result->Length());
12081 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
12082}